From ecfd38f68602a0dfcb6f2e0f73183f00a65fe1c3 Mon Sep 17 00:00:00 2001 From: David Date: Wed, 3 Apr 2024 19:16:44 -0400 Subject: [PATCH] Asset Revision 4 --- Makefile | 50 +- asm/assets/assets.s | 3927 +-- asm/assets/ucode_data.s | 12 +- asm/assets/ucode_text.s | 14 +- asm/boot/boot.bin | Bin 0 -> 4032 bytes asm/boot/rom_boot.s | 2 +- extract-ver/us_1.0.config.json | 921 +- extract.sh | 5 +- include/enums.h | 22 + include/level_object_entries.h | 160 +- include/object_behaviors.h | 135 + include/structs.h | 8 - src/object_functions.c | 2 +- src/object_functions.h | 2 +- tools/Makefile | 16 +- tools/dkr_assets_tool.cpp | 204 - .../builder/build_files/build_fonts.cpp | 137 - .../builder/build_files/build_fonts.h | 13 - .../builder/build_files/build_gametext.cpp | 133 - .../builder/build_files/build_gametext.h | 14 - .../builder/build_files/build_levelheader.cpp | 116 - .../builder/build_files/build_levelheader.h | 11 - .../builder/build_files/build_levelname.cpp | 32 - .../builder/build_files/build_levelname.h | 9 - .../builder/build_files/build_menutext.cpp | 46 - .../builder/build_files/build_menutext.h | 9 - .../builder/build_files/build_sprite.cpp | 29 - .../builder/build_files/build_sprite.h | 9 - .../builder/build_files/build_texture.cpp | 221 - .../builder/build_files/build_texture.h | 13 - .../builder/build_files/build_ttghost.cpp | 33 - .../builder/build_files/build_ttghost.h | 12 - .../builder/builder.cpp | 36 - .../dkr_assets_tool_classes/builder/builder.h | 28 - .../common/revision_number.h | 5 - .../common/textures.cpp | 138 - .../dkr_assets_tool_classes/common/textures.h | 26 - .../dkr_assets_tool_classes/common/types.cpp | 17 - tools/dkr_assets_tool_classes/common/types.h | 7 - tools/dkr_assets_tool_classes/common/util.cpp | 162 - tools/dkr_assets_tool_classes/common/util.h | 39 - .../common/util/enumHelper.cpp | 182 - .../common/util/enumHelper.h | 24 - .../common/util/errorHelper.cpp | 3 - .../common/util/errorHelper.h | 31 - .../common/util/fileHelper.cpp | 238 - .../common/util/fileHelper.h | 53 - .../common/util/jsonHelper.cpp | 201 - .../common/util/jsonHelper.h | 152 - .../compiler/compiler.cpp | 253 - .../compiler/compiler.h | 21 - .../extractor/config.cpp | 467 - .../extractor/config.h | 79 - .../extractor/extract/extract.cpp | 17 - .../extractor/extract/extract.h | 16 - .../extractor/extract/extract_binary.cpp | 10 - .../extractor/extract/extract_binary.h | 9 - .../extractor/extract/extract_compressed.cpp | 19 - .../extractor/extract/extract_compressed.h | 9 - .../extractor/extract/extract_fonts.cpp | 89 - .../extractor/extract/extract_fonts.h | 9 - .../extractor/extract/extract_gametext.cpp | 164 - .../extractor/extract/extract_gametext.h | 13 - .../extractor/extract/extract_levelheader.cpp | 132 - .../extractor/extract/extract_levelheader.h | 9 - .../extractor/extract/extract_levelname.cpp | 25 - .../extractor/extract/extract_levelname.h | 9 - .../extractor/extract/extract_menutext.cpp | 40 - .../extractor/extract/extract_menutext.h | 10 - .../extractor/extract/extract_sprite.cpp | 28 - .../extractor/extract/extract_sprite.h | 9 - .../extractor/extract/extract_textures.cpp | 204 - .../extractor/extract/extract_textures.h | 13 - .../extractor/extract/extract_ttghost.cpp | 42 - .../extractor/extract/extract_ttghost.h | 9 - .../extractor/extractor.cpp | 36 - .../extractor/extractor.h | 21 - .../dkr_assets_tool_classes/extractor/rom.cpp | 119 - tools/dkr_assets_tool_classes/extractor/rom.h | 32 - tools/dkr_assets_tool_classes/libs/json.hpp | 773 - .../make_asset_files/asset_asm_data.cpp | 177 - .../make_asset_files/asset_asm_data.h | 28 - .../make_asset_files/asset_enums_header.cpp | 75 - .../make_asset_files/asset_enums_header.h | 21 - tools/dkr_assets_tool_settings.json | 17 + .../dkr_assets_tool_src/builder/buildInfo.o | Bin 0 -> 2400 bytes .../builder/buildTypes/buildAudio.o | Bin 0 -> 23040 bytes .../builder/buildTypes/buildBinary.o | Bin 0 -> 22560 bytes .../builder/buildTypes/buildFonts.o | Bin 0 -> 53128 bytes .../builder/buildTypes/buildGameText.o | Bin 0 -> 73112 bytes .../builder/buildTypes/buildLevelHeader.o | Bin 0 -> 78680 bytes .../builder/buildTypes/buildLevelModel.o | Bin 0 -> 22584 bytes .../buildLevelObjectTranslationTable.o | Bin 0 -> 24024 bytes .../builder/buildTypes/buildMenuText.o | Bin 0 -> 23032 bytes .../builder/buildTypes/buildMisc.o | Bin 0 -> 63064 bytes .../builder/buildTypes/buildObjectAnimation.o | Bin 0 -> 22632 bytes .../builder/buildTypes/buildObjectHeader.o | Bin 0 -> 63824 bytes .../builder/buildTypes/buildObjectMap.o | Bin 0 -> 72760 bytes .../builder/buildTypes/buildObjectModel.o | Bin 0 -> 22608 bytes .../builder/buildTypes/buildParticle.o | Bin 0 -> 22568 bytes .../buildTypes/buildParticleBehavior.o | Bin 0 -> 22632 bytes .../builder/buildTypes/buildSprite.o | Bin 0 -> 26800 bytes .../builder/buildTypes/buildTTGhost.o | Bin 0 -> 28872 bytes .../builder/buildTypes/buildTexture.o | Bin 0 -> 48336 bytes .../dkr_assets_tool_src/builder/builder.o | Bin 0 -> 102960 bytes .../dkr_assets_tool_src/extract/assetTable.o | Bin 0 -> 34240 bytes .../dkr_assets_tool_src/extract/config.o | Bin 0 -> 145144 bytes .../dkr_assets_tool_src/extract/extractInfo.o | Bin 0 -> 66720 bytes .../extract/extractTypes/extractAudio.o | Bin 0 -> 30744 bytes .../extract/extractTypes/extractBinary.o | Bin 0 -> 31528 bytes .../extract/extractTypes/extractFonts.o | Bin 0 -> 46640 bytes .../extract/extractTypes/extractGameText.o | Bin 0 -> 71600 bytes .../extract/extractTypes/extractLevelHeader.o | Bin 0 -> 78600 bytes .../extract/extractTypes/extractLevelModel.o | Bin 0 -> 30992 bytes .../extract/extractTypes/extractLevelName.o | Bin 0 -> 33424 bytes .../extractLevelObjectTranslationTable.o | Bin 0 -> 35184 bytes .../extract/extractTypes/extractMenuText.o | Bin 0 -> 44912 bytes .../extract/extractTypes/extractMisc.o | Bin 0 -> 82312 bytes .../extractTypes/extractObjectAnimation.o | Bin 0 -> 30432 bytes .../extractTypes/extractObjectHeader.o | Bin 0 -> 64520 bytes .../extract/extractTypes/extractObjectMap.o | Bin 0 -> 81520 bytes .../extract/extractTypes/extractObjectModel.o | Bin 0 -> 30376 bytes .../extract/extractTypes/extractParticle.o | Bin 0 -> 30352 bytes .../extractTypes/extractParticleBehavior.o | Bin 0 -> 30632 bytes .../extract/extractTypes/extractSprite.o | Bin 0 -> 32960 bytes .../extract/extractTypes/extractTTGhost.o | Bin 0 -> 35944 bytes .../extract/extractTypes/extractTexture.o | Bin 0 -> 66384 bytes .../dkr_assets_tool_src/extract/extractor.o | Bin 0 -> 276920 bytes .../_build/dkr_assets_tool_src/extract/rom.o | Bin 0 -> 47264 bytes .../dkr_assets_tool_src/helpers/asmHeader.o | Bin 0 -> 14160 bytes .../helpers/assetsHelper.o | Bin 0 -> 67736 bytes .../dkr_assets_tool_src/helpers/c/cContext.o | Bin 0 -> 38048 bytes .../helpers/c/cEnumsHelper.o | Bin 0 -> 66560 bytes .../dkr_assets_tool_src/helpers/c/cHeader.o | Bin 0 -> 10512 bytes .../helpers/c/cStructGltfHelper.o | Bin 0 -> 50944 bytes .../helpers/c/cStructHelper.o | Bin 0 -> 70184 bytes .../dkr_assets_tool_src/helpers/c/cTypes.o | Bin 0 -> 23768 bytes .../dkr_assets_tool_src/helpers/dataHelper.o | Bin 0 -> 1576 bytes .../dkr_assets_tool_src/helpers/debugHelper.o | Bin 0 -> 8464 bytes .../dkr_assets_tool_src/helpers/fileHelper.o | Bin 0 -> 79912 bytes .../helpers/gltf/gltfDkrTriangle.o | Bin 0 -> 2224 bytes .../helpers/gltf/gltfDkrVertex.o | Bin 0 -> 3976 bytes .../helpers/gltf/gltfHelper.o | Bin 0 -> 956632 bytes .../helpers/gltf/gltfPrimitive.o | Bin 0 -> 15912 bytes .../dkr_assets_tool_src/helpers/gzipHelper.o | Bin 0 -> 6240 bytes .../dkr_assets_tool_src/helpers/imageHelper.o | Bin 0 -> 53664 bytes .../dkr_assets_tool_src/helpers/jsonHelper.o | Bin 0 -> 488624 bytes .../dkr_assets_tool_src/helpers/miscHelper.o | Bin 0 -> 1712 bytes .../dkr_assets_tool_src/helpers/regex/match.o | Bin 0 -> 10664 bytes .../helpers/regex/regexPcre2.o | Bin 0 -> 22648 bytes .../helpers/regex/regexStd.o | Bin 0 -> 269608 bytes .../dkr_assets_tool_src/helpers/regexHelper.o | Bin 0 -> 5672 bytes .../helpers/stringHelper.o | Bin 0 -> 29952 bytes .../libs/gzip/DKRCompression.o | Bin 0 -> 18568 bytes .../dkr_assets_tool_src/libs/gzip/DKRGzip.o | Bin 0 -> 29384 bytes .../libs/gzip/GECompression.o | Bin 0 -> 16816 bytes .../libs/n64graphics/n64graphics-utils.o | Bin 0 -> 7872 bytes .../libs/n64graphics/n64graphics.o | Bin 0 -> 138992 bytes .../_build/dkr_assets_tool_src/main.o | Bin 0 -> 226032 bytes .../prebuild/compileAssets/compile.o | Bin 0 -> 222008 bytes .../dkr_assets_tool_src/prebuild/linker/ld.o | Bin 0 -> 29864 bytes .../prebuild/makeIncludes/assetEnums.o | Bin 0 -> 33640 bytes .../prebuild/makeIncludes/assetsAsm.o | Bin 0 -> 88576 bytes .../dkr_assets_tool_src/prebuild/prebuild.o | Bin 0 -> 157808 bytes .../_build/dkr_assets_tool_src/test/test.o | Bin 0 -> 111456 bytes .../dkr_assets_tool_src/builder/buildInfo.cpp | 8 + tools/dkr_assets_tool_src/builder/buildInfo.h | 16 + .../builder/buildTypes/buildAudio.cpp | 20 + .../builder/buildTypes/buildAudio.h | 19 + .../builder/buildTypes/buildBinary.cpp | 15 + .../builder/buildTypes/buildBinary.h | 19 + .../builder/buildTypes/buildFonts.cpp | 120 + .../builder/buildTypes/buildFonts.h | 22 + .../builder/buildTypes/buildGameText.cpp | 175 + .../builder/buildTypes/buildGameText.h | 34 + .../builder/buildTypes/buildLevelHeader.cpp | 277 + .../builder/buildTypes/buildLevelHeader.h | 34 + .../builder/buildTypes/buildLevelModel.cpp | 15 + .../builder/buildTypes/buildLevelModel.h | 19 + .../buildLevelObjectTranslationTable.cpp | 45 + .../buildLevelObjectTranslationTable.h | 19 + .../builder/buildTypes/buildMenuText.cpp | 64 + .../builder/buildTypes/buildMenuText.h | 23 + .../builder/buildTypes/buildMisc.cpp | 227 + .../builder/buildTypes/buildMisc.h | 32 + .../buildTypes/buildObjectAnimation.cpp | 15 + .../builder/buildTypes/buildObjectAnimation.h | 19 + .../builder/buildTypes/buildObjectHeader.cpp | 229 + .../builder/buildTypes/buildObjectHeader.h | 24 + .../builder/buildTypes/buildObjectMap.cpp | 183 + .../builder/buildTypes/buildObjectMap.h | 37 + .../builder/buildTypes/buildObjectModel.cpp | 15 + .../builder/buildTypes/buildObjectModel.h | 19 + .../builder/buildTypes/buildParticle.cpp | 15 + .../builder/buildTypes/buildParticle.h | 19 + .../buildTypes/buildParticleBehavior.cpp | 15 + .../buildTypes/buildParticleBehavior.h | 19 + .../builder/buildTypes/buildSprite.cpp | 41 + .../builder/buildTypes/buildSprite.h | 19 + .../builder/buildTypes/buildTTGhost.cpp | 65 + .../builder/buildTypes/buildTTGhost.h | 24 + .../builder/buildTypes/buildTexture.cpp | 146 + .../builder/buildTypes/buildTexture.h | 21 + tools/dkr_assets_tool_src/builder/builder.cpp | 93 + tools/dkr_assets_tool_src/builder/builder.h | 14 + .../extract/assetTable.cpp | 214 + .../dkr_assets_tool_src/extract/assetTable.h | 49 + tools/dkr_assets_tool_src/extract/config.cpp | 281 + tools/dkr_assets_tool_src/extract/config.h | 153 + .../extract/extractInfo.cpp | 137 + .../dkr_assets_tool_src/extract/extractInfo.h | 94 + .../extract/extractTypes/extractAudio.cpp | 28 + .../extract/extractTypes/extractAudio.h | 13 + .../extract/extractTypes/extractBinary.cpp | 31 + .../extract/extractTypes/extractBinary.h | 21 + .../extract/extractTypes/extractFonts.cpp | 86 + .../extract/extractTypes/extractFonts.h | 18 + .../extract/extractTypes/extractGameText.cpp | 164 + .../extract/extractTypes/extractGameText.h | 17 + .../extractTypes/extractLevelHeader.cpp | 264 + .../extract/extractTypes/extractLevelHeader.h | 23 + .../extractTypes/extractLevelModel.cpp | 29 + .../extract/extractTypes/extractLevelModel.h | 13 + .../extract/extractTypes/extractLevelName.cpp | 42 + .../extract/extractTypes/extractLevelName.h | 13 + .../extractLevelObjectTranslationTable.cpp | 54 + .../extractLevelObjectTranslationTable.h | 13 + .../extract/extractTypes/extractMenuText.cpp | 50 + .../extract/extractTypes/extractMenuText.h | 13 + .../extract/extractTypes/extractMisc.cpp | 165 + .../extract/extractTypes/extractMisc.h | 22 + .../extractTypes/extractObjectAnimation.cpp | 20 + .../extractTypes/extractObjectAnimation.h | 13 + .../extractTypes/extractObjectHeader.cpp | 190 + .../extractTypes/extractObjectHeader.h | 18 + .../extract/extractTypes/extractObjectMap.cpp | 155 + .../extract/extractTypes/extractObjectMap.h | 22 + .../extractTypes/extractObjectModel.cpp | 20 + .../extract/extractTypes/extractObjectModel.h | 13 + .../extract/extractTypes/extractParticle.cpp | 20 + .../extract/extractTypes/extractParticle.h | 13 + .../extractTypes/extractParticleBehavior.cpp | 20 + .../extractTypes/extractParticleBehavior.h | 13 + .../extract/extractTypes/extractSprite.cpp | 39 + .../extract/extractTypes/extractSprite.h | 13 + .../extract/extractTypes/extractTTGhost.cpp | 53 + .../extract/extractTypes/extractTTGhost.h | 13 + .../extract/extractTypes/extractTexture.cpp | 131 + .../extract/extractTypes/extractTexture.h | 19 + .../dkr_assets_tool_src/extract/extractor.cpp | 509 + tools/dkr_assets_tool_src/extract/extractor.h | 61 + tools/dkr_assets_tool_src/extract/rom.cpp | 163 + tools/dkr_assets_tool_src/extract/rom.h | 42 + tools/dkr_assets_tool_src/fileTypes/fonts.hpp | 47 + .../fileTypes/gameText.hpp | 62 + .../fileTypes/levelHeader.hpp | 119 + .../fileTypes/levelObjectMap.hpp | 14 + .../fileTypes/levelObjectTranslationTable.hpp | 8 + tools/dkr_assets_tool_src/fileTypes/misc.hpp | 14 + .../fileTypes/objectHeader.hpp | 106 + .../dkr_assets_tool_src/fileTypes/sprite.hpp | 13 + .../fileTypes/texCoords.hpp | 9 + .../dkr_assets_tool_src/fileTypes/texture.hpp | 53 + .../fileTypes/triangle.hpp | 15 + .../dkr_assets_tool_src/fileTypes/ttGhost.hpp | 25 + tools/dkr_assets_tool_src/fileTypes/types.hpp | 90 + .../dkr_assets_tool_src/fileTypes/vertex.hpp | 14 + .../dkr_assets_tool_src/helpers/asmHeader.cpp | 54 + tools/dkr_assets_tool_src/helpers/asmHeader.h | 31 + .../helpers/assetsHelper.cpp | 157 + .../helpers/assetsHelper.h | 40 + .../helpers/c/cContext.cpp | 123 + .../dkr_assets_tool_src/helpers/c/cContext.h | 40 + .../helpers/c/cEnumsHelper.cpp | 214 + .../helpers/c/cEnumsHelper.h | 70 + .../dkr_assets_tool_src/helpers/c/cHeader.cpp | 34 + tools/dkr_assets_tool_src/helpers/c/cHeader.h | 27 + .../helpers/c/cStructGltfHelper.cpp | 67 + .../helpers/c/cStructGltfHelper.h | 15 + .../helpers/c/cStructHelper.cpp | 577 + .../helpers/c/cStructHelper.h | 132 + .../dkr_assets_tool_src/helpers/c/cTypes.cpp | 90 + tools/dkr_assets_tool_src/helpers/c/cTypes.h | 19 + .../helpers/dataHelper.cpp | 25 + .../dkr_assets_tool_src/helpers/dataHelper.h | 57 + .../helpers/debugHelper.cpp | 41 + .../dkr_assets_tool_src/helpers/debugHelper.h | 152 + .../helpers/fileHelper.cpp | 357 + .../dkr_assets_tool_src/helpers/fileHelper.h | 62 + .../helpers/gltf/gltfDkrTriangle.cpp | 40 + .../helpers/gltf/gltfDkrTriangle.h | 22 + .../helpers/gltf/gltfDkrVertex.cpp | 96 + .../helpers/gltf/gltfDkrVertex.h | 39 + .../helpers/gltf/gltfHelper.cpp | 120 + .../helpers/gltf/gltfHelper.h | 82 + .../helpers/gltf/gltfPrimitive.cpp | 46 + .../helpers/gltf/gltfPrimitive.h | 20 + .../helpers/gzipHelper.cpp | 32 + .../dkr_assets_tool_src/helpers/gzipHelper.h | 15 + .../helpers/imageHelper.cpp | 365 + .../dkr_assets_tool_src/helpers/imageHelper.h | 56 + .../helpers/jsonHelper.cpp | 480 + .../dkr_assets_tool_src/helpers/jsonHelper.h | 129 + .../helpers/miscHelper.cpp | 54 + .../dkr_assets_tool_src/helpers/miscHelper.h | 11 + .../helpers/regex/match.cpp | 43 + .../dkr_assets_tool_src/helpers/regex/match.h | 33 + .../helpers/regex/regexPcre2.cpp | 245 + .../helpers/regex/regexPcre2.h | 18 + .../helpers/regex/regexStd.cpp | 50 + .../helpers/regex/regexStd.h | 15 + .../helpers/regexHelper.cpp | 71 + .../dkr_assets_tool_src/helpers/regexHelper.h | 32 + .../helpers/stringHelper.cpp | 142 + .../helpers/stringHelper.h | 40 + .../libs/ThreadPool.h | 2 + tools/dkr_assets_tool_src/libs/argparse.hpp | 2183 ++ tools/dkr_assets_tool_src/libs/bimap.hpp | 165 + .../libs/calculator.hpp | 0 .../libs/gzip}/DKRCompression.cpp | 2 +- .../libs/gzip}/DKRCompression.h | 0 .../libs/gzip}/DKRGzip.c | 7 +- .../libs/gzip}/DKRGzip.h | 0 .../libs/gzip}/GECompression.cpp | 12 +- .../libs/gzip}/GECompression.h | 0 tools/dkr_assets_tool_src/libs/json.hpp | 26755 ++++++++++++++++ .../libs/md5.hpp} | 6 +- .../libs/n64graphics}/n64graphics-utils.c | 0 .../libs/n64graphics}/n64graphics-utils.h | 0 .../libs/n64graphics}/n64graphics.c | 8 +- .../libs/n64graphics}/n64graphics.h | 0 .../libs/stb_image.h | 0 .../libs/stb_image_write.h | 0 tools/dkr_assets_tool_src/libs/tiny_gltf.h | 8508 +++++ .../libs/zip_file.hpp | 0 tools/dkr_assets_tool_src/main.cpp | 96 + tools/dkr_assets_tool_src/misc/constants.hpp | 31 + tools/dkr_assets_tool_src/misc/settings.hpp | 190 + .../prebuild/compileAssets/compile.cpp | 214 + .../prebuild/compileAssets/compile.h | 39 + .../prebuild/linker/ld.cpp | 79 + .../dkr_assets_tool_src/prebuild/linker/ld.h | 46 + .../prebuild/makeIncludes/assetEnums.cpp | 104 + .../prebuild/makeIncludes/assetEnums.h | 26 + .../prebuild/makeIncludes/assetsAsm.cpp | 318 + .../prebuild/makeIncludes/assetsAsm.h | 36 + .../dkr_assets_tool_src/prebuild/prebuild.cpp | 382 + tools/dkr_assets_tool_src/prebuild/prebuild.h | 54 + tools/dkr_assets_tool_src/test/test.cpp | 503 + tools/dkr_assets_tool_src/test/test.h | 11 + 350 files changed, 53719 insertions(+), 7792 deletions(-) create mode 100644 asm/boot/boot.bin mode change 100755 => 100644 extract-ver/us_1.0.config.json create mode 100644 include/object_behaviors.h delete mode 100644 tools/dkr_assets_tool.cpp delete mode 100644 tools/dkr_assets_tool_classes/builder/build_files/build_fonts.cpp delete mode 100644 tools/dkr_assets_tool_classes/builder/build_files/build_fonts.h delete mode 100644 tools/dkr_assets_tool_classes/builder/build_files/build_gametext.cpp delete mode 100644 tools/dkr_assets_tool_classes/builder/build_files/build_gametext.h delete mode 100644 tools/dkr_assets_tool_classes/builder/build_files/build_levelheader.cpp delete mode 100644 tools/dkr_assets_tool_classes/builder/build_files/build_levelheader.h delete mode 100644 tools/dkr_assets_tool_classes/builder/build_files/build_levelname.cpp delete mode 100644 tools/dkr_assets_tool_classes/builder/build_files/build_levelname.h delete mode 100644 tools/dkr_assets_tool_classes/builder/build_files/build_menutext.cpp delete mode 100644 tools/dkr_assets_tool_classes/builder/build_files/build_menutext.h delete mode 100644 tools/dkr_assets_tool_classes/builder/build_files/build_sprite.cpp delete mode 100644 tools/dkr_assets_tool_classes/builder/build_files/build_sprite.h delete mode 100644 tools/dkr_assets_tool_classes/builder/build_files/build_texture.cpp delete mode 100644 tools/dkr_assets_tool_classes/builder/build_files/build_texture.h delete mode 100644 tools/dkr_assets_tool_classes/builder/build_files/build_ttghost.cpp delete mode 100644 tools/dkr_assets_tool_classes/builder/build_files/build_ttghost.h delete mode 100644 tools/dkr_assets_tool_classes/builder/builder.cpp delete mode 100644 tools/dkr_assets_tool_classes/builder/builder.h delete mode 100644 tools/dkr_assets_tool_classes/common/revision_number.h delete mode 100644 tools/dkr_assets_tool_classes/common/textures.cpp delete mode 100644 tools/dkr_assets_tool_classes/common/textures.h delete mode 100644 tools/dkr_assets_tool_classes/common/types.cpp delete mode 100644 tools/dkr_assets_tool_classes/common/types.h delete mode 100644 tools/dkr_assets_tool_classes/common/util.cpp delete mode 100644 tools/dkr_assets_tool_classes/common/util.h delete mode 100644 tools/dkr_assets_tool_classes/common/util/enumHelper.cpp delete mode 100644 tools/dkr_assets_tool_classes/common/util/enumHelper.h delete mode 100644 tools/dkr_assets_tool_classes/common/util/errorHelper.cpp delete mode 100644 tools/dkr_assets_tool_classes/common/util/errorHelper.h delete mode 100644 tools/dkr_assets_tool_classes/common/util/fileHelper.cpp delete mode 100644 tools/dkr_assets_tool_classes/common/util/fileHelper.h delete mode 100644 tools/dkr_assets_tool_classes/common/util/jsonHelper.cpp delete mode 100644 tools/dkr_assets_tool_classes/common/util/jsonHelper.h delete mode 100644 tools/dkr_assets_tool_classes/compiler/compiler.cpp delete mode 100644 tools/dkr_assets_tool_classes/compiler/compiler.h delete mode 100644 tools/dkr_assets_tool_classes/extractor/config.cpp delete mode 100644 tools/dkr_assets_tool_classes/extractor/config.h delete mode 100644 tools/dkr_assets_tool_classes/extractor/extract/extract.cpp delete mode 100644 tools/dkr_assets_tool_classes/extractor/extract/extract.h delete mode 100644 tools/dkr_assets_tool_classes/extractor/extract/extract_binary.cpp delete mode 100644 tools/dkr_assets_tool_classes/extractor/extract/extract_binary.h delete mode 100644 tools/dkr_assets_tool_classes/extractor/extract/extract_compressed.cpp delete mode 100644 tools/dkr_assets_tool_classes/extractor/extract/extract_compressed.h delete mode 100644 tools/dkr_assets_tool_classes/extractor/extract/extract_fonts.cpp delete mode 100644 tools/dkr_assets_tool_classes/extractor/extract/extract_fonts.h delete mode 100644 tools/dkr_assets_tool_classes/extractor/extract/extract_gametext.cpp delete mode 100644 tools/dkr_assets_tool_classes/extractor/extract/extract_gametext.h delete mode 100644 tools/dkr_assets_tool_classes/extractor/extract/extract_levelheader.cpp delete mode 100644 tools/dkr_assets_tool_classes/extractor/extract/extract_levelheader.h delete mode 100644 tools/dkr_assets_tool_classes/extractor/extract/extract_levelname.cpp delete mode 100644 tools/dkr_assets_tool_classes/extractor/extract/extract_levelname.h delete mode 100644 tools/dkr_assets_tool_classes/extractor/extract/extract_menutext.cpp delete mode 100644 tools/dkr_assets_tool_classes/extractor/extract/extract_menutext.h delete mode 100644 tools/dkr_assets_tool_classes/extractor/extract/extract_sprite.cpp delete mode 100644 tools/dkr_assets_tool_classes/extractor/extract/extract_sprite.h delete mode 100644 tools/dkr_assets_tool_classes/extractor/extract/extract_textures.cpp delete mode 100644 tools/dkr_assets_tool_classes/extractor/extract/extract_textures.h delete mode 100644 tools/dkr_assets_tool_classes/extractor/extract/extract_ttghost.cpp delete mode 100644 tools/dkr_assets_tool_classes/extractor/extract/extract_ttghost.h delete mode 100644 tools/dkr_assets_tool_classes/extractor/extractor.cpp delete mode 100644 tools/dkr_assets_tool_classes/extractor/extractor.h delete mode 100644 tools/dkr_assets_tool_classes/extractor/rom.cpp delete mode 100644 tools/dkr_assets_tool_classes/extractor/rom.h delete mode 100644 tools/dkr_assets_tool_classes/libs/json.hpp delete mode 100644 tools/dkr_assets_tool_classes/make_asset_files/asset_asm_data.cpp delete mode 100644 tools/dkr_assets_tool_classes/make_asset_files/asset_asm_data.h delete mode 100644 tools/dkr_assets_tool_classes/make_asset_files/asset_enums_header.cpp delete mode 100644 tools/dkr_assets_tool_classes/make_asset_files/asset_enums_header.h create mode 100644 tools/dkr_assets_tool_settings.json create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/builder/buildInfo.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/builder/buildTypes/buildAudio.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/builder/buildTypes/buildBinary.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/builder/buildTypes/buildFonts.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/builder/buildTypes/buildGameText.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/builder/buildTypes/buildLevelHeader.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/builder/buildTypes/buildLevelModel.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/builder/buildTypes/buildLevelObjectTranslationTable.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/builder/buildTypes/buildMenuText.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/builder/buildTypes/buildMisc.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/builder/buildTypes/buildObjectAnimation.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/builder/buildTypes/buildObjectHeader.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/builder/buildTypes/buildObjectMap.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/builder/buildTypes/buildObjectModel.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/builder/buildTypes/buildParticle.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/builder/buildTypes/buildParticleBehavior.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/builder/buildTypes/buildSprite.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/builder/buildTypes/buildTTGhost.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/builder/buildTypes/buildTexture.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/builder/builder.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/assetTable.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/config.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/extractInfo.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/extractTypes/extractAudio.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/extractTypes/extractBinary.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/extractTypes/extractFonts.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/extractTypes/extractGameText.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/extractTypes/extractLevelHeader.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/extractTypes/extractLevelModel.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/extractTypes/extractLevelName.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/extractTypes/extractLevelObjectTranslationTable.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/extractTypes/extractMenuText.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/extractTypes/extractMisc.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/extractTypes/extractObjectAnimation.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/extractTypes/extractObjectHeader.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/extractTypes/extractObjectMap.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/extractTypes/extractObjectModel.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/extractTypes/extractParticle.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/extractTypes/extractParticleBehavior.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/extractTypes/extractSprite.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/extractTypes/extractTTGhost.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/extractTypes/extractTexture.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/extractor.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/rom.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/asmHeader.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/assetsHelper.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/c/cContext.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/c/cEnumsHelper.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/c/cHeader.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/c/cStructGltfHelper.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/c/cStructHelper.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/c/cTypes.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/dataHelper.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/debugHelper.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/fileHelper.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/gltf/gltfDkrTriangle.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/gltf/gltfDkrVertex.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/gltf/gltfHelper.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/gltf/gltfPrimitive.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/gzipHelper.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/imageHelper.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/jsonHelper.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/miscHelper.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/regex/match.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/regex/regexPcre2.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/regex/regexStd.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/regexHelper.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/stringHelper.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/libs/gzip/DKRCompression.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/libs/gzip/DKRGzip.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/libs/gzip/GECompression.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/libs/n64graphics/n64graphics-utils.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/libs/n64graphics/n64graphics.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/main.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/prebuild/compileAssets/compile.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/prebuild/linker/ld.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/prebuild/makeIncludes/assetEnums.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/prebuild/makeIncludes/assetsAsm.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/prebuild/prebuild.o create mode 100644 tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/test/test.o create mode 100644 tools/dkr_assets_tool_src/builder/buildInfo.cpp create mode 100644 tools/dkr_assets_tool_src/builder/buildInfo.h create mode 100644 tools/dkr_assets_tool_src/builder/buildTypes/buildAudio.cpp create mode 100644 tools/dkr_assets_tool_src/builder/buildTypes/buildAudio.h create mode 100644 tools/dkr_assets_tool_src/builder/buildTypes/buildBinary.cpp create mode 100644 tools/dkr_assets_tool_src/builder/buildTypes/buildBinary.h create mode 100644 tools/dkr_assets_tool_src/builder/buildTypes/buildFonts.cpp create mode 100644 tools/dkr_assets_tool_src/builder/buildTypes/buildFonts.h create mode 100644 tools/dkr_assets_tool_src/builder/buildTypes/buildGameText.cpp create mode 100644 tools/dkr_assets_tool_src/builder/buildTypes/buildGameText.h create mode 100644 tools/dkr_assets_tool_src/builder/buildTypes/buildLevelHeader.cpp create mode 100644 tools/dkr_assets_tool_src/builder/buildTypes/buildLevelHeader.h create mode 100644 tools/dkr_assets_tool_src/builder/buildTypes/buildLevelModel.cpp create mode 100644 tools/dkr_assets_tool_src/builder/buildTypes/buildLevelModel.h create mode 100644 tools/dkr_assets_tool_src/builder/buildTypes/buildLevelObjectTranslationTable.cpp create mode 100644 tools/dkr_assets_tool_src/builder/buildTypes/buildLevelObjectTranslationTable.h create mode 100644 tools/dkr_assets_tool_src/builder/buildTypes/buildMenuText.cpp create mode 100644 tools/dkr_assets_tool_src/builder/buildTypes/buildMenuText.h create mode 100644 tools/dkr_assets_tool_src/builder/buildTypes/buildMisc.cpp create mode 100644 tools/dkr_assets_tool_src/builder/buildTypes/buildMisc.h create mode 100644 tools/dkr_assets_tool_src/builder/buildTypes/buildObjectAnimation.cpp create mode 100644 tools/dkr_assets_tool_src/builder/buildTypes/buildObjectAnimation.h create mode 100644 tools/dkr_assets_tool_src/builder/buildTypes/buildObjectHeader.cpp create mode 100644 tools/dkr_assets_tool_src/builder/buildTypes/buildObjectHeader.h create mode 100644 tools/dkr_assets_tool_src/builder/buildTypes/buildObjectMap.cpp create mode 100644 tools/dkr_assets_tool_src/builder/buildTypes/buildObjectMap.h create mode 100644 tools/dkr_assets_tool_src/builder/buildTypes/buildObjectModel.cpp create mode 100644 tools/dkr_assets_tool_src/builder/buildTypes/buildObjectModel.h create mode 100644 tools/dkr_assets_tool_src/builder/buildTypes/buildParticle.cpp create mode 100644 tools/dkr_assets_tool_src/builder/buildTypes/buildParticle.h create mode 100644 tools/dkr_assets_tool_src/builder/buildTypes/buildParticleBehavior.cpp create mode 100644 tools/dkr_assets_tool_src/builder/buildTypes/buildParticleBehavior.h create mode 100644 tools/dkr_assets_tool_src/builder/buildTypes/buildSprite.cpp create mode 100644 tools/dkr_assets_tool_src/builder/buildTypes/buildSprite.h create mode 100644 tools/dkr_assets_tool_src/builder/buildTypes/buildTTGhost.cpp create mode 100644 tools/dkr_assets_tool_src/builder/buildTypes/buildTTGhost.h create mode 100644 tools/dkr_assets_tool_src/builder/buildTypes/buildTexture.cpp create mode 100644 tools/dkr_assets_tool_src/builder/buildTypes/buildTexture.h create mode 100644 tools/dkr_assets_tool_src/builder/builder.cpp create mode 100644 tools/dkr_assets_tool_src/builder/builder.h create mode 100644 tools/dkr_assets_tool_src/extract/assetTable.cpp create mode 100644 tools/dkr_assets_tool_src/extract/assetTable.h create mode 100644 tools/dkr_assets_tool_src/extract/config.cpp create mode 100644 tools/dkr_assets_tool_src/extract/config.h create mode 100644 tools/dkr_assets_tool_src/extract/extractInfo.cpp create mode 100644 tools/dkr_assets_tool_src/extract/extractInfo.h create mode 100644 tools/dkr_assets_tool_src/extract/extractTypes/extractAudio.cpp create mode 100644 tools/dkr_assets_tool_src/extract/extractTypes/extractAudio.h create mode 100644 tools/dkr_assets_tool_src/extract/extractTypes/extractBinary.cpp create mode 100644 tools/dkr_assets_tool_src/extract/extractTypes/extractBinary.h create mode 100644 tools/dkr_assets_tool_src/extract/extractTypes/extractFonts.cpp create mode 100644 tools/dkr_assets_tool_src/extract/extractTypes/extractFonts.h create mode 100644 tools/dkr_assets_tool_src/extract/extractTypes/extractGameText.cpp create mode 100644 tools/dkr_assets_tool_src/extract/extractTypes/extractGameText.h create mode 100644 tools/dkr_assets_tool_src/extract/extractTypes/extractLevelHeader.cpp create mode 100644 tools/dkr_assets_tool_src/extract/extractTypes/extractLevelHeader.h create mode 100644 tools/dkr_assets_tool_src/extract/extractTypes/extractLevelModel.cpp create mode 100644 tools/dkr_assets_tool_src/extract/extractTypes/extractLevelModel.h create mode 100644 tools/dkr_assets_tool_src/extract/extractTypes/extractLevelName.cpp create mode 100644 tools/dkr_assets_tool_src/extract/extractTypes/extractLevelName.h create mode 100644 tools/dkr_assets_tool_src/extract/extractTypes/extractLevelObjectTranslationTable.cpp create mode 100644 tools/dkr_assets_tool_src/extract/extractTypes/extractLevelObjectTranslationTable.h create mode 100644 tools/dkr_assets_tool_src/extract/extractTypes/extractMenuText.cpp create mode 100644 tools/dkr_assets_tool_src/extract/extractTypes/extractMenuText.h create mode 100644 tools/dkr_assets_tool_src/extract/extractTypes/extractMisc.cpp create mode 100644 tools/dkr_assets_tool_src/extract/extractTypes/extractMisc.h create mode 100644 tools/dkr_assets_tool_src/extract/extractTypes/extractObjectAnimation.cpp create mode 100644 tools/dkr_assets_tool_src/extract/extractTypes/extractObjectAnimation.h create mode 100644 tools/dkr_assets_tool_src/extract/extractTypes/extractObjectHeader.cpp create mode 100644 tools/dkr_assets_tool_src/extract/extractTypes/extractObjectHeader.h create mode 100644 tools/dkr_assets_tool_src/extract/extractTypes/extractObjectMap.cpp create mode 100644 tools/dkr_assets_tool_src/extract/extractTypes/extractObjectMap.h create mode 100644 tools/dkr_assets_tool_src/extract/extractTypes/extractObjectModel.cpp create mode 100644 tools/dkr_assets_tool_src/extract/extractTypes/extractObjectModel.h create mode 100644 tools/dkr_assets_tool_src/extract/extractTypes/extractParticle.cpp create mode 100644 tools/dkr_assets_tool_src/extract/extractTypes/extractParticle.h create mode 100644 tools/dkr_assets_tool_src/extract/extractTypes/extractParticleBehavior.cpp create mode 100644 tools/dkr_assets_tool_src/extract/extractTypes/extractParticleBehavior.h create mode 100644 tools/dkr_assets_tool_src/extract/extractTypes/extractSprite.cpp create mode 100644 tools/dkr_assets_tool_src/extract/extractTypes/extractSprite.h create mode 100644 tools/dkr_assets_tool_src/extract/extractTypes/extractTTGhost.cpp create mode 100644 tools/dkr_assets_tool_src/extract/extractTypes/extractTTGhost.h create mode 100644 tools/dkr_assets_tool_src/extract/extractTypes/extractTexture.cpp create mode 100644 tools/dkr_assets_tool_src/extract/extractTypes/extractTexture.h create mode 100644 tools/dkr_assets_tool_src/extract/extractor.cpp create mode 100644 tools/dkr_assets_tool_src/extract/extractor.h create mode 100644 tools/dkr_assets_tool_src/extract/rom.cpp create mode 100644 tools/dkr_assets_tool_src/extract/rom.h create mode 100644 tools/dkr_assets_tool_src/fileTypes/fonts.hpp create mode 100644 tools/dkr_assets_tool_src/fileTypes/gameText.hpp create mode 100644 tools/dkr_assets_tool_src/fileTypes/levelHeader.hpp create mode 100644 tools/dkr_assets_tool_src/fileTypes/levelObjectMap.hpp create mode 100644 tools/dkr_assets_tool_src/fileTypes/levelObjectTranslationTable.hpp create mode 100644 tools/dkr_assets_tool_src/fileTypes/misc.hpp create mode 100644 tools/dkr_assets_tool_src/fileTypes/objectHeader.hpp create mode 100644 tools/dkr_assets_tool_src/fileTypes/sprite.hpp create mode 100644 tools/dkr_assets_tool_src/fileTypes/texCoords.hpp create mode 100644 tools/dkr_assets_tool_src/fileTypes/texture.hpp create mode 100644 tools/dkr_assets_tool_src/fileTypes/triangle.hpp create mode 100644 tools/dkr_assets_tool_src/fileTypes/ttGhost.hpp create mode 100644 tools/dkr_assets_tool_src/fileTypes/types.hpp create mode 100644 tools/dkr_assets_tool_src/fileTypes/vertex.hpp create mode 100644 tools/dkr_assets_tool_src/helpers/asmHeader.cpp create mode 100644 tools/dkr_assets_tool_src/helpers/asmHeader.h create mode 100644 tools/dkr_assets_tool_src/helpers/assetsHelper.cpp create mode 100644 tools/dkr_assets_tool_src/helpers/assetsHelper.h create mode 100644 tools/dkr_assets_tool_src/helpers/c/cContext.cpp create mode 100644 tools/dkr_assets_tool_src/helpers/c/cContext.h create mode 100644 tools/dkr_assets_tool_src/helpers/c/cEnumsHelper.cpp create mode 100644 tools/dkr_assets_tool_src/helpers/c/cEnumsHelper.h create mode 100644 tools/dkr_assets_tool_src/helpers/c/cHeader.cpp create mode 100644 tools/dkr_assets_tool_src/helpers/c/cHeader.h create mode 100644 tools/dkr_assets_tool_src/helpers/c/cStructGltfHelper.cpp create mode 100644 tools/dkr_assets_tool_src/helpers/c/cStructGltfHelper.h create mode 100644 tools/dkr_assets_tool_src/helpers/c/cStructHelper.cpp create mode 100644 tools/dkr_assets_tool_src/helpers/c/cStructHelper.h create mode 100644 tools/dkr_assets_tool_src/helpers/c/cTypes.cpp create mode 100644 tools/dkr_assets_tool_src/helpers/c/cTypes.h create mode 100644 tools/dkr_assets_tool_src/helpers/dataHelper.cpp create mode 100644 tools/dkr_assets_tool_src/helpers/dataHelper.h create mode 100644 tools/dkr_assets_tool_src/helpers/debugHelper.cpp create mode 100644 tools/dkr_assets_tool_src/helpers/debugHelper.h create mode 100644 tools/dkr_assets_tool_src/helpers/fileHelper.cpp create mode 100644 tools/dkr_assets_tool_src/helpers/fileHelper.h create mode 100644 tools/dkr_assets_tool_src/helpers/gltf/gltfDkrTriangle.cpp create mode 100644 tools/dkr_assets_tool_src/helpers/gltf/gltfDkrTriangle.h create mode 100644 tools/dkr_assets_tool_src/helpers/gltf/gltfDkrVertex.cpp create mode 100644 tools/dkr_assets_tool_src/helpers/gltf/gltfDkrVertex.h create mode 100644 tools/dkr_assets_tool_src/helpers/gltf/gltfHelper.cpp create mode 100644 tools/dkr_assets_tool_src/helpers/gltf/gltfHelper.h create mode 100644 tools/dkr_assets_tool_src/helpers/gltf/gltfPrimitive.cpp create mode 100644 tools/dkr_assets_tool_src/helpers/gltf/gltfPrimitive.h create mode 100644 tools/dkr_assets_tool_src/helpers/gzipHelper.cpp create mode 100644 tools/dkr_assets_tool_src/helpers/gzipHelper.h create mode 100644 tools/dkr_assets_tool_src/helpers/imageHelper.cpp create mode 100644 tools/dkr_assets_tool_src/helpers/imageHelper.h create mode 100644 tools/dkr_assets_tool_src/helpers/jsonHelper.cpp create mode 100644 tools/dkr_assets_tool_src/helpers/jsonHelper.h create mode 100644 tools/dkr_assets_tool_src/helpers/miscHelper.cpp create mode 100644 tools/dkr_assets_tool_src/helpers/miscHelper.h create mode 100644 tools/dkr_assets_tool_src/helpers/regex/match.cpp create mode 100644 tools/dkr_assets_tool_src/helpers/regex/match.h create mode 100644 tools/dkr_assets_tool_src/helpers/regex/regexPcre2.cpp create mode 100644 tools/dkr_assets_tool_src/helpers/regex/regexPcre2.h create mode 100644 tools/dkr_assets_tool_src/helpers/regex/regexStd.cpp create mode 100644 tools/dkr_assets_tool_src/helpers/regex/regexStd.h create mode 100644 tools/dkr_assets_tool_src/helpers/regexHelper.cpp create mode 100644 tools/dkr_assets_tool_src/helpers/regexHelper.h create mode 100644 tools/dkr_assets_tool_src/helpers/stringHelper.cpp create mode 100644 tools/dkr_assets_tool_src/helpers/stringHelper.h rename tools/{dkr_assets_tool_classes => dkr_assets_tool_src}/libs/ThreadPool.h (98%) create mode 100644 tools/dkr_assets_tool_src/libs/argparse.hpp create mode 100644 tools/dkr_assets_tool_src/libs/bimap.hpp rename tools/{dkr_assets_tool_classes => dkr_assets_tool_src}/libs/calculator.hpp (100%) rename tools/{dkr_assets_tool_classes/libs => dkr_assets_tool_src/libs/gzip}/DKRCompression.cpp (97%) rename tools/{dkr_assets_tool_classes/libs => dkr_assets_tool_src/libs/gzip}/DKRCompression.h (100%) rename tools/{dkr_assets_tool_classes/libs => dkr_assets_tool_src/libs/gzip}/DKRGzip.c (99%) rename tools/{dkr_assets_tool_classes/libs => dkr_assets_tool_src/libs/gzip}/DKRGzip.h (100%) rename tools/{dkr_assets_tool_classes/libs => dkr_assets_tool_src/libs/gzip}/GECompression.cpp (99%) rename tools/{dkr_assets_tool_classes/libs => dkr_assets_tool_src/libs/gzip}/GECompression.h (100%) create mode 100644 tools/dkr_assets_tool_src/libs/json.hpp rename tools/{dkr_assets_tool_classes/common/util/md5.h => dkr_assets_tool_src/libs/md5.hpp} (98%) rename tools/{dkr_assets_tool_classes/libs => dkr_assets_tool_src/libs/n64graphics}/n64graphics-utils.c (100%) rename tools/{dkr_assets_tool_classes/libs => dkr_assets_tool_src/libs/n64graphics}/n64graphics-utils.h (100%) rename tools/{dkr_assets_tool_classes/libs => dkr_assets_tool_src/libs/n64graphics}/n64graphics.c (99%) rename tools/{dkr_assets_tool_classes/libs => dkr_assets_tool_src/libs/n64graphics}/n64graphics.h (100%) rename tools/{dkr_assets_tool_classes => dkr_assets_tool_src}/libs/stb_image.h (100%) rename tools/{dkr_assets_tool_classes => dkr_assets_tool_src}/libs/stb_image_write.h (100%) create mode 100644 tools/dkr_assets_tool_src/libs/tiny_gltf.h rename tools/{dkr_assets_tool_classes => dkr_assets_tool_src}/libs/zip_file.hpp (100%) create mode 100644 tools/dkr_assets_tool_src/main.cpp create mode 100644 tools/dkr_assets_tool_src/misc/constants.hpp create mode 100644 tools/dkr_assets_tool_src/misc/settings.hpp create mode 100644 tools/dkr_assets_tool_src/prebuild/compileAssets/compile.cpp create mode 100644 tools/dkr_assets_tool_src/prebuild/compileAssets/compile.h create mode 100644 tools/dkr_assets_tool_src/prebuild/linker/ld.cpp create mode 100644 tools/dkr_assets_tool_src/prebuild/linker/ld.h create mode 100644 tools/dkr_assets_tool_src/prebuild/makeIncludes/assetEnums.cpp create mode 100644 tools/dkr_assets_tool_src/prebuild/makeIncludes/assetEnums.h create mode 100644 tools/dkr_assets_tool_src/prebuild/makeIncludes/assetsAsm.cpp create mode 100644 tools/dkr_assets_tool_src/prebuild/makeIncludes/assetsAsm.h create mode 100644 tools/dkr_assets_tool_src/prebuild/prebuild.cpp create mode 100644 tools/dkr_assets_tool_src/prebuild/prebuild.h create mode 100644 tools/dkr_assets_tool_src/test/test.cpp create mode 100644 tools/dkr_assets_tool_src/test/test.h diff --git a/Makefile b/Makefile index 73ff2a0a..41951a96 100755 --- a/Makefile +++ b/Makefile @@ -12,16 +12,6 @@ VERSION := us_1.0 NON_MATCHING ?= 0 $(eval $(call validate-option,NON_MATCHING,0 1)) -COMPILE_ASSETS ?= 0 -$(eval $(call validate-option,COMPILE_ASSETS,0 1)) - -ifeq ($(COMPILE_ASSETS),1) - DUMMY != ./tools/dkr_assets_tool -c $(VERSION) ./assets >&2 || echo FAIL - ifeq ($(DUMMY),FAIL) - $(error Failed to compile assets) - endif -endif - ifeq ($(VERSION),us_1.0) DEFINES += VERSION_US_1_0=1 DEFINES += F3DDKR_GBI=1 @@ -100,6 +90,10 @@ endif DUMMY != python3 ./tools/python/check_if_need_to_extract.py $(VERSION) >&2 || echo FAIL +######## Prebuild step (Compile assets, generate linker file, etc.) ######## + +DUMMY != ./tools/dkr_assets_tool -dkrv $(VERSION) prebuild >&2 || echo FAIL + ################################ endif @@ -181,8 +175,7 @@ LOADER_FLAGS = -vwf N64CRC = $(TOOLS_DIR)/n64crc FIXCHECKSUMS = python3 $(TOOLS_DIR)/python/calc_func_checksums.py $(VERSION) -COMPRESS = $(TOOLS_DIR)/dkr_assets_tool -fc -BUILDER = $(TOOLS_DIR)/dkr_assets_tool -b $(VERSION) ./assets +BUILDER = $(TOOLS_DIR)/dkr_assets_tool -dkrv $(VERSION) build LIB_DIRS := lib ASM_DIRS := asm asm/boot asm/assets lib/asm lib/asm/non_decompilable @@ -229,13 +222,12 @@ JSON_FILES := $(shell find $(ASSETS) -type f -name '*.json') IGNORE_JSON_FILES := $(shell find $(ASSETS) -type f -name '*.meta.json') JSON_FILES := $(filter-out $(IGNORE_JSON_FILES),$(JSON_FILES)) # Add .cbin files -CBIN_FILES := $(shell find $(ASSETS) -type f -name '*.cbin') +#CBIN_FILES := $(shell find $(ASSETS) -type f -name '*.cbin') # Add .bin files -BIN_FILES := $(shell find $(ASSETS) -type f -name '*.bin') -ALL_FILES := $(CBIN_FILES) $(BIN_FILES) $(JSON_FILES) +#BIN_FILES := $(shell find $(ASSETS) -type f -name '*.bin') +ALL_FILES := $(JSON_FILES) ALL_FILES_OUT := $(foreach FILE,ALL_FILES,$($(FILE):$(ASSETS)%=$(ASSETS_BUILD_DIR)%)) -ALL_FILES_OUT := $(foreach FILE,ALL_FILES_OUT,$($(FILE):$.cbin%=$.bin%)) ALL_FILES_OUT := $(foreach FILE,ALL_FILES_OUT,$($(FILE):$.json%=$.bin%)) DIRECTORY = $(sort $(dir $(ALL_FILES_OUT))) $(addprefix $(BUILD_DIR)/,$(LIB_DIRS) $(ASM_DIRS) $(SRC_DIRS) ucode) @@ -250,22 +242,10 @@ $$(BASE_PATH).bin: $1 $(eval ALL_ASSETS_BUILT+=$(BASE_PATH).bin) endef -# $1 = Print message -define BIN_FILE_ACTION - $$(call print,$1:,$$<,$$@) - $$(V)$$(ASSETS_COPY) $$^ $$@ -endef - -# $1 = Print message -define CBIN_FILE_ACTION - $$(call print,$1:,$$<,$$@) - $$(V)$$(COMPRESS) $$^ $$@ -endef - # $1 = Print message define JSON_FILE_ACTION $$(call print,$1:,$$<,$$@) - $$(V)$$(BUILDER) $$< $$@ + $$(V)$$(BUILDER) -i $$< -o $$@ endef # Microcode @@ -361,18 +341,6 @@ dont_remove_asset_files: $(ALL_ASSETS_BUILT) ######## Asset Targets ######## -$(BUILD_DIR)/enumsCache.bin: include/enums.h - $(call print,Building enums.h cache:,$<,$@) - $(V)$(TOOLS_DIR)/dkr_assets_tool -bc $(VERSION) $< - -dkr.ld: $(BUILD_DIR)/enumsCache.bin - @$(PRINT) "$(YELLOW)Generating Linker File...$(NO_COL)\n" - $(V)./generate_ld.sh $(VERSION) - -ALL_ASSETS_BUILT += dkr.ld # This is a hack, but it works I guess. - -$(foreach FILE,$(BIN_FILES),$(eval $(call DEFINE_ASSET_TARGET,$(FILE),$(call BIN_FILE_ACTION,Copying)))) -$(foreach FILE,$(CBIN_FILES),$(eval $(call DEFINE_ASSET_TARGET,$(FILE),$(call CBIN_FILE_ACTION,Compressing)))) $(foreach FILE,$(JSON_FILES),$(eval $(call DEFINE_ASSET_TARGET,$(FILE),$(call JSON_FILE_ACTION,Building)))) # Microcode target diff --git a/asm/assets/assets.s b/asm/assets/assets.s index df2120ad..0cdd7ec7 100755 --- a/asm/assets/assets.s +++ b/asm/assets/assets.s @@ -39,7 +39,7 @@ .word ASSET_OBJECT_ANIMATIONS_TABLE - ASSETS_START .word ASSET_OBJECT_ANIMATIONS - ASSETS_START .word ASSET_OBJECT_HEADERS_TABLE - ASSETS_START -.word ASSET_OBJECT_HEADERS - ASSETS_START +.word ASSET_OBJECTS - ASSETS_START .word ASSET_LEVEL_OBJECT_TRANSLATION_TABLE - ASSETS_START .word ASSET_EMPTY_37_TABLE - ASSETS_START .word ASSET_EMPTY_37 - ASSETS_START @@ -57,7 +57,7 @@ .word ASSET_TTGHOSTS - ASSETS_START .word ASSETS_END - ASSETS_START -/********** Asset Sections **********/ +/********** Asset Sections Table **********/ .balign 16 glabel ASSETS_START @@ -67,25 +67,25 @@ glabel ASSETS_START .balign 16 glabel ASSET_AI_BEHAVIOUR glabel ASSET_AI_BEHAVIOUR_0 -.incbin "./build/us_1.0/assets/ai-racers/unknown_0_0.bin" +.incbin "./build/us_1.0/assets/ai-racers/asset_ai_behaviour_0.bin" glabel ASSET_AI_BEHAVIOUR_1 -.incbin "./build/us_1.0/assets/ai-racers/unknown_0_1.bin" +.incbin "./build/us_1.0/assets/ai-racers/asset_ai_behaviour_1.bin" glabel ASSET_AI_BEHAVIOUR_2 -.incbin "./build/us_1.0/assets/ai-racers/unknown_0_2.bin" +.incbin "./build/us_1.0/assets/ai-racers/asset_ai_behaviour_2.bin" glabel ASSET_AI_BEHAVIOUR_3 -.incbin "./build/us_1.0/assets/ai-racers/unknown_0_3.bin" +.incbin "./build/us_1.0/assets/ai-racers/asset_ai_behaviour_3.bin" glabel ASSET_AI_BEHAVIOUR_4 -.incbin "./build/us_1.0/assets/ai-racers/unknown_0_4.bin" +.incbin "./build/us_1.0/assets/ai-racers/asset_ai_behaviour_4.bin" glabel ASSET_AI_BEHAVIOUR_5 -.incbin "./build/us_1.0/assets/ai-racers/unknown_0_5.bin" +.incbin "./build/us_1.0/assets/ai-racers/asset_ai_behaviour_5.bin" glabel ASSET_AI_BEHAVIOUR_6 -.incbin "./build/us_1.0/assets/ai-racers/unknown_0_6.bin" +.incbin "./build/us_1.0/assets/ai-racers/asset_ai_behaviour_6.bin" glabel ASSET_AI_BEHAVIOUR_7 -.incbin "./build/us_1.0/assets/ai-racers/unknown_0_7.bin" +.incbin "./build/us_1.0/assets/ai-racers/asset_ai_behaviour_7.bin" glabel ASSET_AI_BEHAVIOUR_8 -.incbin "./build/us_1.0/assets/ai-racers/unknown_0_8.bin" +.incbin "./build/us_1.0/assets/ai-racers/asset_ai_behaviour_8.bin" glabel ASSET_AI_BEHAVIOUR_9 -.incbin "./build/us_1.0/assets/ai-racers/unknown_0_9.bin" +.incbin "./build/us_1.0/assets/ai-racers/asset_ai_behaviour_9.bin" glabel ASSET_AI_BEHAVIOUR_END /********** ASSET_AI_BEHAVIOUR_TABLE **********/ @@ -104,6 +104,7 @@ glabel ASSET_AI_BEHAVIOUR_TABLE .word ASSET_AI_BEHAVIOUR_9 - ASSET_AI_BEHAVIOUR .word ASSET_AI_BEHAVIOUR_END - ASSET_AI_BEHAVIOUR .word 0xFFFFFFFF +glabel ASSET_AI_BEHAVIOUR_TABLE_END /********** ASSET_TEXTURES_3D **********/ @@ -4320,6 +4321,7 @@ glabel ASSET_TEXTURES_3D_TABLE .word ASSET_TEX3D_SPACE_RAREWARESIGNNONBLINKING - ASSET_TEXTURES_3D .word ASSET_TEXTURES_3D_END - ASSET_TEXTURES_3D .word 0xFFFFFFFF +glabel ASSET_TEXTURES_3D_TABLE_END /********** ASSET_TEXTURES_2D **********/ @@ -7051,521 +7053,522 @@ glabel ASSET_TEXTURES_2D_TABLE .word ASSET_TEX2D_MENU_ICONTTAMULET4_1 - ASSET_TEXTURES_2D .word ASSET_TEXTURES_2D_END - ASSET_TEXTURES_2D .word 0xFFFFFFFF +glabel ASSET_TEXTURES_2D_TABLE_END /********** ASSET_GAME_TEXT **********/ .balign 16 glabel ASSET_GAME_TEXT glabel ASSET_GAME_TEXT_0 -.incbin "./build/us_1.0/assets/text/game/unknown_6_0.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_0.bin" glabel ASSET_GAME_TEXT_1 -.incbin "./build/us_1.0/assets/text/game/unknown_6_1.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_1.bin" glabel ASSET_GAME_TEXT_2 -.incbin "./build/us_1.0/assets/text/game/unknown_6_2.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_2.bin" glabel ASSET_GAME_TEXT_3 -.incbin "./build/us_1.0/assets/text/game/unknown_6_3.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_3.bin" glabel ASSET_GAME_TEXT_4 -.incbin "./build/us_1.0/assets/text/game/unknown_6_4.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_4.bin" glabel ASSET_GAME_TEXT_5 -.incbin "./build/us_1.0/assets/text/game/unknown_6_5.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_5.bin" glabel ASSET_GAME_TEXT_6 -.incbin "./build/us_1.0/assets/text/game/unknown_6_6.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_6.bin" glabel ASSET_GAME_TEXT_7 -.incbin "./build/us_1.0/assets/text/game/unknown_6_7.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_7.bin" glabel ASSET_GAME_TEXT_8 -.incbin "./build/us_1.0/assets/text/game/unknown_6_8.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_8.bin" glabel ASSET_GAME_TEXT_9 -.incbin "./build/us_1.0/assets/text/game/unknown_6_9.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_9.bin" glabel ASSET_GAME_TEXT_10 -.incbin "./build/us_1.0/assets/text/game/unknown_6_10.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_10.bin" glabel ASSET_GAME_TEXT_11 -.incbin "./build/us_1.0/assets/text/game/unknown_6_11.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_11.bin" glabel ASSET_GAME_TEXT_12 -.incbin "./build/us_1.0/assets/text/game/unknown_6_12.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_12.bin" glabel ASSET_GAME_TEXT_13 -.incbin "./build/us_1.0/assets/text/game/unknown_6_13.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_13.bin" glabel ASSET_GAME_TEXT_14 -.incbin "./build/us_1.0/assets/text/game/unknown_6_14.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_14.bin" glabel ASSET_GAME_TEXT_15 -.incbin "./build/us_1.0/assets/text/game/unknown_6_15.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_15.bin" glabel ASSET_GAME_TEXT_16 -.incbin "./build/us_1.0/assets/text/game/unknown_6_16.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_16.bin" glabel ASSET_GAME_TEXT_17 -.incbin "./build/us_1.0/assets/text/game/unknown_6_17.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_17.bin" glabel ASSET_GAME_TEXT_18 -.incbin "./build/us_1.0/assets/text/game/unknown_6_18.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_18.bin" glabel ASSET_GAME_TEXT_19 -.incbin "./build/us_1.0/assets/text/game/unknown_6_19.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_19.bin" glabel ASSET_GAME_TEXT_20 -.incbin "./build/us_1.0/assets/text/game/unknown_6_20.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_20.bin" glabel ASSET_GAME_TEXT_21 -.incbin "./build/us_1.0/assets/text/game/unknown_6_21.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_21.bin" glabel ASSET_GAME_TEXT_22 -.incbin "./build/us_1.0/assets/text/game/unknown_6_22.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_22.bin" glabel ASSET_GAME_TEXT_23 -.incbin "./build/us_1.0/assets/text/game/unknown_6_23.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_23.bin" glabel ASSET_GAME_TEXT_24 -.incbin "./build/us_1.0/assets/text/game/unknown_6_24.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_24.bin" glabel ASSET_GAME_TEXT_25 -.incbin "./build/us_1.0/assets/text/game/unknown_6_25.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_25.bin" glabel ASSET_GAME_TEXT_26 -.incbin "./build/us_1.0/assets/text/game/unknown_6_26.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_26.bin" glabel ASSET_GAME_TEXT_27 -.incbin "./build/us_1.0/assets/text/game/unknown_6_27.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_27.bin" glabel ASSET_GAME_TEXT_28 -.incbin "./build/us_1.0/assets/text/game/unknown_6_28.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_28.bin" glabel ASSET_GAME_TEXT_29 -.incbin "./build/us_1.0/assets/text/game/unknown_6_29.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_29.bin" glabel ASSET_GAME_TEXT_30 -.incbin "./build/us_1.0/assets/text/game/unknown_6_30.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_30.bin" glabel ASSET_GAME_TEXT_31 -.incbin "./build/us_1.0/assets/text/game/unknown_6_31.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_31.bin" glabel ASSET_GAME_TEXT_32 -.incbin "./build/us_1.0/assets/text/game/unknown_6_32.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_32.bin" glabel ASSET_GAME_TEXT_33 -.incbin "./build/us_1.0/assets/text/game/unknown_6_33.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_33.bin" glabel ASSET_GAME_TEXT_34 -.incbin "./build/us_1.0/assets/text/game/unknown_6_34.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_34.bin" glabel ASSET_GAME_TEXT_35 -.incbin "./build/us_1.0/assets/text/game/unknown_6_35.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_35.bin" glabel ASSET_GAME_TEXT_36 -.incbin "./build/us_1.0/assets/text/game/unknown_6_36.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_36.bin" glabel ASSET_GAME_TEXT_37 -.incbin "./build/us_1.0/assets/text/game/unknown_6_37.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_37.bin" glabel ASSET_GAME_TEXT_38 -.incbin "./build/us_1.0/assets/text/game/unknown_6_38.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_38.bin" glabel ASSET_GAME_TEXT_39 -.incbin "./build/us_1.0/assets/text/game/unknown_6_39.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_39.bin" glabel ASSET_GAME_TEXT_40 -.incbin "./build/us_1.0/assets/text/game/unknown_6_40.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_40.bin" glabel ASSET_GAME_TEXT_41 -.incbin "./build/us_1.0/assets/text/game/unknown_6_41.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_41.bin" glabel ASSET_GAME_TEXT_42 -.incbin "./build/us_1.0/assets/text/game/unknown_6_42.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_42.bin" glabel ASSET_GAME_TEXT_43 -.incbin "./build/us_1.0/assets/text/game/unknown_6_43.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_43.bin" glabel ASSET_GAME_TEXT_44 -.incbin "./build/us_1.0/assets/text/game/unknown_6_44.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_44.bin" glabel ASSET_GAME_TEXT_45 -.incbin "./build/us_1.0/assets/text/game/unknown_6_45.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_45.bin" glabel ASSET_GAME_TEXT_46 -.incbin "./build/us_1.0/assets/text/game/unknown_6_46.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_46.bin" glabel ASSET_GAME_TEXT_47 -.incbin "./build/us_1.0/assets/text/game/unknown_6_47.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_47.bin" glabel ASSET_GAME_TEXT_48 -.incbin "./build/us_1.0/assets/text/game/unknown_6_48.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_48.bin" glabel ASSET_GAME_TEXT_49 -.incbin "./build/us_1.0/assets/text/game/unknown_6_49.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_49.bin" glabel ASSET_GAME_TEXT_50 -.incbin "./build/us_1.0/assets/text/game/unknown_6_50.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_50.bin" glabel ASSET_GAME_TEXT_51 -.incbin "./build/us_1.0/assets/text/game/unknown_6_51.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_51.bin" glabel ASSET_GAME_TEXT_52 -.incbin "./build/us_1.0/assets/text/game/unknown_6_52.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_52.bin" glabel ASSET_GAME_TEXT_53 -.incbin "./build/us_1.0/assets/text/game/unknown_6_53.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_53.bin" glabel ASSET_GAME_TEXT_54 -.incbin "./build/us_1.0/assets/text/game/unknown_6_54.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_54.bin" glabel ASSET_GAME_TEXT_55 -.incbin "./build/us_1.0/assets/text/game/unknown_6_55.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_55.bin" glabel ASSET_GAME_TEXT_56 -.incbin "./build/us_1.0/assets/text/game/unknown_6_56.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_56.bin" glabel ASSET_GAME_TEXT_57 -.incbin "./build/us_1.0/assets/text/game/unknown_6_57.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_57.bin" glabel ASSET_GAME_TEXT_58 -.incbin "./build/us_1.0/assets/text/game/unknown_6_58.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_58.bin" glabel ASSET_GAME_TEXT_59 -.incbin "./build/us_1.0/assets/text/game/unknown_6_59.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_59.bin" glabel ASSET_GAME_TEXT_60 -.incbin "./build/us_1.0/assets/text/game/unknown_6_60.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_60.bin" glabel ASSET_GAME_TEXT_61 -.incbin "./build/us_1.0/assets/text/game/unknown_6_61.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_61.bin" glabel ASSET_GAME_TEXT_62 -.incbin "./build/us_1.0/assets/text/game/unknown_6_62.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_62.bin" glabel ASSET_GAME_TEXT_63 -.incbin "./build/us_1.0/assets/text/game/unknown_6_63.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_63.bin" glabel ASSET_GAME_TEXT_64 -.incbin "./build/us_1.0/assets/text/game/unknown_6_64.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_64.bin" glabel ASSET_GAME_TEXT_65 -.incbin "./build/us_1.0/assets/text/game/unknown_6_65.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_65.bin" glabel ASSET_GAME_TEXT_66 -.incbin "./build/us_1.0/assets/text/game/unknown_6_66.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_66.bin" glabel ASSET_GAME_TEXT_67 -.incbin "./build/us_1.0/assets/text/game/unknown_6_67.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_67.bin" glabel ASSET_GAME_TEXT_68 -.incbin "./build/us_1.0/assets/text/game/unknown_6_68.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_68.bin" glabel ASSET_GAME_TEXT_69 -.incbin "./build/us_1.0/assets/text/game/unknown_6_69.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_69.bin" glabel ASSET_GAME_TEXT_70 -.incbin "./build/us_1.0/assets/text/game/unknown_6_70.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_70.bin" glabel ASSET_GAME_TEXT_71 -.incbin "./build/us_1.0/assets/text/game/unknown_6_71.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_71.bin" glabel ASSET_GAME_TEXT_72 -.incbin "./build/us_1.0/assets/text/game/unknown_6_72.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_72.bin" glabel ASSET_GAME_TEXT_73 -.incbin "./build/us_1.0/assets/text/game/unknown_6_73.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_73.bin" glabel ASSET_GAME_TEXT_74 -.incbin "./build/us_1.0/assets/text/game/unknown_6_74.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_74.bin" glabel ASSET_GAME_TEXT_75 -.incbin "./build/us_1.0/assets/text/game/unknown_6_75.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_75.bin" glabel ASSET_GAME_TEXT_76 -.incbin "./build/us_1.0/assets/text/game/unknown_6_76.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_76.bin" glabel ASSET_GAME_TEXT_77 -.incbin "./build/us_1.0/assets/text/game/unknown_6_77.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_77.bin" glabel ASSET_GAME_TEXT_78 -.incbin "./build/us_1.0/assets/text/game/unknown_6_78.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_78.bin" glabel ASSET_GAME_TEXT_79 -.incbin "./build/us_1.0/assets/text/game/unknown_6_79.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_79.bin" glabel ASSET_GAME_TEXT_80 -.incbin "./build/us_1.0/assets/text/game/unknown_6_80.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_80.bin" glabel ASSET_GAME_TEXT_81 -.incbin "./build/us_1.0/assets/text/game/unknown_6_81.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_81.bin" glabel ASSET_GAME_TEXT_82 -.incbin "./build/us_1.0/assets/text/game/unknown_6_82.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_82.bin" glabel ASSET_GAME_TEXT_83 -.incbin "./build/us_1.0/assets/text/game/unknown_6_83.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_83.bin" glabel ASSET_GAME_TEXT_84 -.incbin "./build/us_1.0/assets/text/game/unknown_6_84.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_84.bin" glabel ASSET_GAME_TEXT_85 -.incbin "./build/us_1.0/assets/text/game/unknown_6_85.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_85.bin" glabel ASSET_GAME_TEXT_86 -.incbin "./build/us_1.0/assets/text/game/unknown_6_86.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_86.bin" glabel ASSET_GAME_TEXT_87 -.incbin "./build/us_1.0/assets/text/game/unknown_6_87.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_87.bin" glabel ASSET_GAME_TEXT_88 -.incbin "./build/us_1.0/assets/text/game/unknown_6_88.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_88.bin" glabel ASSET_GAME_TEXT_89 -.incbin "./build/us_1.0/assets/text/game/unknown_6_89.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_89.bin" glabel ASSET_GAME_TEXT_90 -.incbin "./build/us_1.0/assets/text/game/unknown_6_90.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_90.bin" glabel ASSET_GAME_TEXT_91 -.incbin "./build/us_1.0/assets/text/game/unknown_6_91.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_91.bin" glabel ASSET_GAME_TEXT_92 -.incbin "./build/us_1.0/assets/text/game/unknown_6_92.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_92.bin" glabel ASSET_GAME_TEXT_93 -.incbin "./build/us_1.0/assets/text/game/unknown_6_93.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_93.bin" glabel ASSET_GAME_TEXT_94 -.incbin "./build/us_1.0/assets/text/game/unknown_6_94.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_94.bin" glabel ASSET_GAME_TEXT_95 -.incbin "./build/us_1.0/assets/text/game/unknown_6_95.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_95.bin" glabel ASSET_GAME_TEXT_96 -.incbin "./build/us_1.0/assets/text/game/unknown_6_96.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_96.bin" glabel ASSET_GAME_TEXT_97 -.incbin "./build/us_1.0/assets/text/game/unknown_6_97.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_97.bin" glabel ASSET_GAME_TEXT_98 -.incbin "./build/us_1.0/assets/text/game/unknown_6_98.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_98.bin" glabel ASSET_GAME_TEXT_99 -.incbin "./build/us_1.0/assets/text/game/unknown_6_99.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_99.bin" glabel ASSET_GAME_TEXT_100 -.incbin "./build/us_1.0/assets/text/game/unknown_6_100.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_100.bin" glabel ASSET_GAME_TEXT_101 -.incbin "./build/us_1.0/assets/text/game/unknown_6_101.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_101.bin" glabel ASSET_GAME_TEXT_102 -.incbin "./build/us_1.0/assets/text/game/unknown_6_102.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_102.bin" glabel ASSET_GAME_TEXT_103 -.incbin "./build/us_1.0/assets/text/game/unknown_6_103.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_103.bin" glabel ASSET_GAME_TEXT_104 -.incbin "./build/us_1.0/assets/text/game/unknown_6_104.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_104.bin" glabel ASSET_GAME_TEXT_105 -.incbin "./build/us_1.0/assets/text/game/unknown_6_105.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_105.bin" glabel ASSET_GAME_TEXT_106 -.incbin "./build/us_1.0/assets/text/game/unknown_6_106.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_106.bin" glabel ASSET_GAME_TEXT_107 -.incbin "./build/us_1.0/assets/text/game/unknown_6_107.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_107.bin" glabel ASSET_GAME_TEXT_108 -.incbin "./build/us_1.0/assets/text/game/unknown_6_108.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_108.bin" glabel ASSET_GAME_TEXT_109 -.incbin "./build/us_1.0/assets/text/game/unknown_6_109.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_109.bin" glabel ASSET_GAME_TEXT_110 -.incbin "./build/us_1.0/assets/text/game/unknown_6_110.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_110.bin" glabel ASSET_GAME_TEXT_111 -.incbin "./build/us_1.0/assets/text/game/unknown_6_111.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_111.bin" glabel ASSET_GAME_TEXT_112 -.incbin "./build/us_1.0/assets/text/game/unknown_6_112.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_112.bin" glabel ASSET_GAME_TEXT_113 -.incbin "./build/us_1.0/assets/text/game/unknown_6_113.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_113.bin" glabel ASSET_GAME_TEXT_114 -.incbin "./build/us_1.0/assets/text/game/unknown_6_114.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_114.bin" glabel ASSET_GAME_TEXT_115 -.incbin "./build/us_1.0/assets/text/game/unknown_6_115.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_115.bin" glabel ASSET_GAME_TEXT_116 -.incbin "./build/us_1.0/assets/text/game/unknown_6_116.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_116.bin" glabel ASSET_GAME_TEXT_117 -.incbin "./build/us_1.0/assets/text/game/unknown_6_117.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_117.bin" glabel ASSET_GAME_TEXT_118 -.incbin "./build/us_1.0/assets/text/game/unknown_6_118.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_118.bin" glabel ASSET_GAME_TEXT_119 -.incbin "./build/us_1.0/assets/text/game/unknown_6_119.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_119.bin" glabel ASSET_GAME_TEXT_120 -.incbin "./build/us_1.0/assets/text/game/unknown_6_120.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_120.bin" glabel ASSET_GAME_TEXT_121 -.incbin "./build/us_1.0/assets/text/game/unknown_6_121.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_121.bin" glabel ASSET_GAME_TEXT_122 -.incbin "./build/us_1.0/assets/text/game/unknown_6_122.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_122.bin" glabel ASSET_GAME_TEXT_123 -.incbin "./build/us_1.0/assets/text/game/unknown_6_123.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_123.bin" glabel ASSET_GAME_TEXT_124 -.incbin "./build/us_1.0/assets/text/game/unknown_6_124.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_124.bin" glabel ASSET_GAME_TEXT_125 -.incbin "./build/us_1.0/assets/text/game/unknown_6_125.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_125.bin" glabel ASSET_GAME_TEXT_126 -.incbin "./build/us_1.0/assets/text/game/unknown_6_126.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_126.bin" glabel ASSET_GAME_TEXT_127 -.incbin "./build/us_1.0/assets/text/game/unknown_6_127.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_127.bin" glabel ASSET_GAME_TEXT_128 -.incbin "./build/us_1.0/assets/text/game/unknown_6_128.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_128.bin" glabel ASSET_GAME_TEXT_129 -.incbin "./build/us_1.0/assets/text/game/unknown_6_129.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_129.bin" glabel ASSET_GAME_TEXT_130 -.incbin "./build/us_1.0/assets/text/game/unknown_6_130.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_130.bin" glabel ASSET_GAME_TEXT_131 -.incbin "./build/us_1.0/assets/text/game/unknown_6_131.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_131.bin" glabel ASSET_GAME_TEXT_132 -.incbin "./build/us_1.0/assets/text/game/unknown_6_132.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_132.bin" glabel ASSET_GAME_TEXT_133 -.incbin "./build/us_1.0/assets/text/game/unknown_6_133.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_133.bin" glabel ASSET_GAME_TEXT_134 -.incbin "./build/us_1.0/assets/text/game/unknown_6_134.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_134.bin" glabel ASSET_GAME_TEXT_135 -.incbin "./build/us_1.0/assets/text/game/unknown_6_135.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_135.bin" glabel ASSET_GAME_TEXT_136 -.incbin "./build/us_1.0/assets/text/game/unknown_6_136.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_136.bin" glabel ASSET_GAME_TEXT_137 -.incbin "./build/us_1.0/assets/text/game/unknown_6_137.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_137.bin" glabel ASSET_GAME_TEXT_138 -.incbin "./build/us_1.0/assets/text/game/unknown_6_138.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_138.bin" glabel ASSET_GAME_TEXT_139 -.incbin "./build/us_1.0/assets/text/game/unknown_6_139.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_139.bin" glabel ASSET_GAME_TEXT_140 -.incbin "./build/us_1.0/assets/text/game/unknown_6_140.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_140.bin" glabel ASSET_GAME_TEXT_141 -.incbin "./build/us_1.0/assets/text/game/unknown_6_141.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_141.bin" glabel ASSET_GAME_TEXT_142 -.incbin "./build/us_1.0/assets/text/game/unknown_6_142.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_142.bin" glabel ASSET_GAME_TEXT_143 -.incbin "./build/us_1.0/assets/text/game/unknown_6_143.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_143.bin" glabel ASSET_GAME_TEXT_144 -.incbin "./build/us_1.0/assets/text/game/unknown_6_144.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_144.bin" glabel ASSET_GAME_TEXT_145 -.incbin "./build/us_1.0/assets/text/game/unknown_6_145.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_145.bin" glabel ASSET_GAME_TEXT_146 -.incbin "./build/us_1.0/assets/text/game/unknown_6_146.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_146.bin" glabel ASSET_GAME_TEXT_147 -.incbin "./build/us_1.0/assets/text/game/unknown_6_147.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_147.bin" glabel ASSET_GAME_TEXT_148 -.incbin "./build/us_1.0/assets/text/game/unknown_6_148.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_148.bin" glabel ASSET_GAME_TEXT_149 -.incbin "./build/us_1.0/assets/text/game/unknown_6_149.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_149.bin" glabel ASSET_GAME_TEXT_150 -.incbin "./build/us_1.0/assets/text/game/unknown_6_150.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_150.bin" glabel ASSET_GAME_TEXT_151 -.incbin "./build/us_1.0/assets/text/game/unknown_6_151.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_151.bin" glabel ASSET_GAME_TEXT_152 -.incbin "./build/us_1.0/assets/text/game/unknown_6_152.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_152.bin" glabel ASSET_GAME_TEXT_153 -.incbin "./build/us_1.0/assets/text/game/unknown_6_153.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_153.bin" glabel ASSET_GAME_TEXT_154 -.incbin "./build/us_1.0/assets/text/game/unknown_6_154.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_154.bin" glabel ASSET_GAME_TEXT_155 -.incbin "./build/us_1.0/assets/text/game/unknown_6_155.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_155.bin" glabel ASSET_GAME_TEXT_156 -.incbin "./build/us_1.0/assets/text/game/unknown_6_156.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_156.bin" glabel ASSET_GAME_TEXT_157 -.incbin "./build/us_1.0/assets/text/game/unknown_6_157.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_157.bin" glabel ASSET_GAME_TEXT_158 -.incbin "./build/us_1.0/assets/text/game/unknown_6_158.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_158.bin" glabel ASSET_GAME_TEXT_159 -.incbin "./build/us_1.0/assets/text/game/unknown_6_159.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_159.bin" glabel ASSET_GAME_TEXT_160 -.incbin "./build/us_1.0/assets/text/game/unknown_6_160.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_160.bin" glabel ASSET_GAME_TEXT_161 -.incbin "./build/us_1.0/assets/text/game/unknown_6_161.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_161.bin" glabel ASSET_GAME_TEXT_162 -.incbin "./build/us_1.0/assets/text/game/unknown_6_162.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_162.bin" glabel ASSET_GAME_TEXT_163 -.incbin "./build/us_1.0/assets/text/game/unknown_6_163.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_163.bin" glabel ASSET_GAME_TEXT_164 -.incbin "./build/us_1.0/assets/text/game/unknown_6_164.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_164.bin" glabel ASSET_GAME_TEXT_165 -.incbin "./build/us_1.0/assets/text/game/unknown_6_165.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_165.bin" glabel ASSET_GAME_TEXT_166 -.incbin "./build/us_1.0/assets/text/game/unknown_6_166.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_166.bin" glabel ASSET_GAME_TEXT_167 -.incbin "./build/us_1.0/assets/text/game/unknown_6_167.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_167.bin" glabel ASSET_GAME_TEXT_168 -.incbin "./build/us_1.0/assets/text/game/unknown_6_168.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_168.bin" glabel ASSET_GAME_TEXT_169 -.incbin "./build/us_1.0/assets/text/game/unknown_6_169.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_169.bin" glabel ASSET_GAME_TEXT_170 -.incbin "./build/us_1.0/assets/text/game/unknown_6_170.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_170.bin" glabel ASSET_GAME_TEXT_171 -.incbin "./build/us_1.0/assets/text/game/unknown_6_171.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_171.bin" glabel ASSET_GAME_TEXT_172 -.incbin "./build/us_1.0/assets/text/game/unknown_6_172.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_172.bin" glabel ASSET_GAME_TEXT_173 -.incbin "./build/us_1.0/assets/text/game/unknown_6_173.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_173.bin" glabel ASSET_GAME_TEXT_174 -.incbin "./build/us_1.0/assets/text/game/unknown_6_174.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_174.bin" glabel ASSET_GAME_TEXT_175 -.incbin "./build/us_1.0/assets/text/game/unknown_6_175.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_175.bin" glabel ASSET_GAME_TEXT_176 -.incbin "./build/us_1.0/assets/text/game/unknown_6_176.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_176.bin" glabel ASSET_GAME_TEXT_177 -.incbin "./build/us_1.0/assets/text/game/unknown_6_177.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_177.bin" glabel ASSET_GAME_TEXT_178 -.incbin "./build/us_1.0/assets/text/game/unknown_6_178.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_178.bin" glabel ASSET_GAME_TEXT_179 -.incbin "./build/us_1.0/assets/text/game/unknown_6_179.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_179.bin" glabel ASSET_GAME_TEXT_180 -.incbin "./build/us_1.0/assets/text/game/unknown_6_180.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_180.bin" glabel ASSET_GAME_TEXT_181 -.incbin "./build/us_1.0/assets/text/game/unknown_6_181.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_181.bin" glabel ASSET_GAME_TEXT_182 -.incbin "./build/us_1.0/assets/text/game/unknown_6_182.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_182.bin" glabel ASSET_GAME_TEXT_183 -.incbin "./build/us_1.0/assets/text/game/unknown_6_183.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_183.bin" glabel ASSET_GAME_TEXT_184 -.incbin "./build/us_1.0/assets/text/game/unknown_6_184.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_184.bin" glabel ASSET_GAME_TEXT_185 -.incbin "./build/us_1.0/assets/text/game/unknown_6_185.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_185.bin" glabel ASSET_GAME_TEXT_186 -.incbin "./build/us_1.0/assets/text/game/unknown_6_186.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_186.bin" glabel ASSET_GAME_TEXT_187 -.incbin "./build/us_1.0/assets/text/game/unknown_6_187.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_187.bin" glabel ASSET_GAME_TEXT_188 -.incbin "./build/us_1.0/assets/text/game/unknown_6_188.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_188.bin" glabel ASSET_GAME_TEXT_189 -.incbin "./build/us_1.0/assets/text/game/unknown_6_189.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_189.bin" glabel ASSET_GAME_TEXT_190 -.incbin "./build/us_1.0/assets/text/game/unknown_6_190.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_190.bin" glabel ASSET_GAME_TEXT_191 -.incbin "./build/us_1.0/assets/text/game/unknown_6_191.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_191.bin" glabel ASSET_GAME_TEXT_192 -.incbin "./build/us_1.0/assets/text/game/unknown_6_192.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_192.bin" glabel ASSET_GAME_TEXT_193 -.incbin "./build/us_1.0/assets/text/game/unknown_6_193.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_193.bin" glabel ASSET_GAME_TEXT_194 -.incbin "./build/us_1.0/assets/text/game/unknown_6_194.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_194.bin" glabel ASSET_GAME_TEXT_195 -.incbin "./build/us_1.0/assets/text/game/unknown_6_195.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_195.bin" glabel ASSET_GAME_TEXT_196 -.incbin "./build/us_1.0/assets/text/game/unknown_6_196.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_196.bin" glabel ASSET_GAME_TEXT_197 -.incbin "./build/us_1.0/assets/text/game/unknown_6_197.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_197.bin" glabel ASSET_GAME_TEXT_198 -.incbin "./build/us_1.0/assets/text/game/unknown_6_198.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_198.bin" glabel ASSET_GAME_TEXT_199 -.incbin "./build/us_1.0/assets/text/game/unknown_6_199.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_199.bin" glabel ASSET_GAME_TEXT_200 -.incbin "./build/us_1.0/assets/text/game/unknown_6_200.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_200.bin" glabel ASSET_GAME_TEXT_201 -.incbin "./build/us_1.0/assets/text/game/unknown_6_201.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_201.bin" glabel ASSET_GAME_TEXT_202 -.incbin "./build/us_1.0/assets/text/game/unknown_6_202.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_202.bin" glabel ASSET_GAME_TEXT_203 -.incbin "./build/us_1.0/assets/text/game/unknown_6_203.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_203.bin" glabel ASSET_GAME_TEXT_204 -.incbin "./build/us_1.0/assets/text/game/unknown_6_204.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_204.bin" glabel ASSET_GAME_TEXT_205 -.incbin "./build/us_1.0/assets/text/game/unknown_6_205.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_205.bin" glabel ASSET_GAME_TEXT_206 -.incbin "./build/us_1.0/assets/text/game/unknown_6_206.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_206.bin" glabel ASSET_GAME_TEXT_207 -.incbin "./build/us_1.0/assets/text/game/unknown_6_207.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_207.bin" glabel ASSET_GAME_TEXT_208 -.incbin "./build/us_1.0/assets/text/game/unknown_6_208.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_208.bin" glabel ASSET_GAME_TEXT_209 -.incbin "./build/us_1.0/assets/text/game/unknown_6_209.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_209.bin" glabel ASSET_GAME_TEXT_210 -.incbin "./build/us_1.0/assets/text/game/unknown_6_210.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_210.bin" glabel ASSET_GAME_TEXT_211 -.incbin "./build/us_1.0/assets/text/game/unknown_6_211.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_211.bin" glabel ASSET_GAME_TEXT_212 -.incbin "./build/us_1.0/assets/text/game/unknown_6_212.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_212.bin" glabel ASSET_GAME_TEXT_213 -.incbin "./build/us_1.0/assets/text/game/unknown_6_213.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_213.bin" glabel ASSET_GAME_TEXT_214 -.incbin "./build/us_1.0/assets/text/game/unknown_6_214.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_214.bin" glabel ASSET_GAME_TEXT_215 -.incbin "./build/us_1.0/assets/text/game/unknown_6_215.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_215.bin" glabel ASSET_GAME_TEXT_216 -.incbin "./build/us_1.0/assets/text/game/unknown_6_216.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_216.bin" glabel ASSET_GAME_TEXT_217 -.incbin "./build/us_1.0/assets/text/game/unknown_6_217.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_217.bin" glabel ASSET_GAME_TEXT_218 -.incbin "./build/us_1.0/assets/text/game/unknown_6_218.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_218.bin" glabel ASSET_GAME_TEXT_219 -.incbin "./build/us_1.0/assets/text/game/unknown_6_219.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_219.bin" glabel ASSET_GAME_TEXT_220 -.incbin "./build/us_1.0/assets/text/game/unknown_6_220.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_220.bin" glabel ASSET_GAME_TEXT_221 -.incbin "./build/us_1.0/assets/text/game/unknown_6_221.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_221.bin" glabel ASSET_GAME_TEXT_222 -.incbin "./build/us_1.0/assets/text/game/unknown_6_222.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_222.bin" glabel ASSET_GAME_TEXT_223 -.incbin "./build/us_1.0/assets/text/game/unknown_6_223.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_223.bin" glabel ASSET_GAME_TEXT_224 -.incbin "./build/us_1.0/assets/text/game/unknown_6_224.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_224.bin" glabel ASSET_GAME_TEXT_225 -.incbin "./build/us_1.0/assets/text/game/unknown_6_225.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_225.bin" glabel ASSET_GAME_TEXT_226 -.incbin "./build/us_1.0/assets/text/game/unknown_6_226.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_226.bin" glabel ASSET_GAME_TEXT_227 -.incbin "./build/us_1.0/assets/text/game/unknown_6_227.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_227.bin" glabel ASSET_GAME_TEXT_228 -.incbin "./build/us_1.0/assets/text/game/unknown_6_228.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_228.bin" glabel ASSET_GAME_TEXT_229 -.incbin "./build/us_1.0/assets/text/game/unknown_6_229.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_229.bin" glabel ASSET_GAME_TEXT_230 -.incbin "./build/us_1.0/assets/text/game/unknown_6_230.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_230.bin" glabel ASSET_GAME_TEXT_231 -.incbin "./build/us_1.0/assets/text/game/unknown_6_231.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_231.bin" glabel ASSET_GAME_TEXT_232 -.incbin "./build/us_1.0/assets/text/game/unknown_6_232.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_232.bin" glabel ASSET_GAME_TEXT_233 -.incbin "./build/us_1.0/assets/text/game/unknown_6_233.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_233.bin" glabel ASSET_GAME_TEXT_234 -.incbin "./build/us_1.0/assets/text/game/unknown_6_234.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_234.bin" glabel ASSET_GAME_TEXT_235 -.incbin "./build/us_1.0/assets/text/game/unknown_6_235.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_235.bin" glabel ASSET_GAME_TEXT_236 -.incbin "./build/us_1.0/assets/text/game/unknown_6_236.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_236.bin" glabel ASSET_GAME_TEXT_237 -.incbin "./build/us_1.0/assets/text/game/unknown_6_237.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_237.bin" glabel ASSET_GAME_TEXT_238 -.incbin "./build/us_1.0/assets/text/game/unknown_6_238.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_238.bin" glabel ASSET_GAME_TEXT_239 -.incbin "./build/us_1.0/assets/text/game/unknown_6_239.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_239.bin" glabel ASSET_GAME_TEXT_240 -.incbin "./build/us_1.0/assets/text/game/unknown_6_240.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_240.bin" glabel ASSET_GAME_TEXT_241 -.incbin "./build/us_1.0/assets/text/game/unknown_6_241.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_241.bin" glabel ASSET_GAME_TEXT_242 -.incbin "./build/us_1.0/assets/text/game/unknown_6_242.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_242.bin" glabel ASSET_GAME_TEXT_243 -.incbin "./build/us_1.0/assets/text/game/unknown_6_243.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_243.bin" glabel ASSET_GAME_TEXT_244 -.incbin "./build/us_1.0/assets/text/game/unknown_6_244.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_244.bin" glabel ASSET_GAME_TEXT_245 -.incbin "./build/us_1.0/assets/text/game/unknown_6_245.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_245.bin" glabel ASSET_GAME_TEXT_246 -.incbin "./build/us_1.0/assets/text/game/unknown_6_246.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_246.bin" glabel ASSET_GAME_TEXT_247 -.incbin "./build/us_1.0/assets/text/game/unknown_6_247.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_247.bin" glabel ASSET_GAME_TEXT_248 -.incbin "./build/us_1.0/assets/text/game/unknown_6_248.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_248.bin" glabel ASSET_GAME_TEXT_249 -.incbin "./build/us_1.0/assets/text/game/unknown_6_249.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_249.bin" glabel ASSET_GAME_TEXT_250 -.incbin "./build/us_1.0/assets/text/game/unknown_6_250.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_250.bin" glabel ASSET_GAME_TEXT_251 -.incbin "./build/us_1.0/assets/text/game/unknown_6_251.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_251.bin" glabel ASSET_GAME_TEXT_252 -.incbin "./build/us_1.0/assets/text/game/unknown_6_252.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_252.bin" glabel ASSET_GAME_TEXT_253 -.incbin "./build/us_1.0/assets/text/game/unknown_6_253.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_253.bin" glabel ASSET_GAME_TEXT_254 -.incbin "./build/us_1.0/assets/text/game/unknown_6_254.bin" +.incbin "./build/us_1.0/assets/text/game/asset_game_text_254.bin" glabel ASSET_GAME_TEXT_END /********** ASSET_GAME_TEXT_TABLE **********/ @@ -7829,6 +7832,7 @@ glabel ASSET_GAME_TEXT_TABLE .word (ASSET_GAME_TEXT_254 - ASSET_GAME_TEXT) | 0x80000000 .word ASSET_GAME_TEXT_END - ASSET_GAME_TEXT .word 0xFFFFFFFF +glabel ASSET_GAME_TEXT_TABLE_END /********** ASSET_MENU_TEXT **********/ @@ -7848,13 +7852,14 @@ glabel ASSET_MENU_TEXT_END .balign 16 glabel ASSET_MENU_TEXT_TABLE -.word 186 # Number of text entries for the languages +.word 186 .word ASSET_MENU_TEXT_ENGLISH - ASSET_MENU_TEXT .word ASSET_MENU_TEXT_FRENCH - ASSET_MENU_TEXT .word ASSET_MENU_TEXT_GERMAN - ASSET_MENU_TEXT .word ASSET_MENU_TEXT_JAPANESE - ASSET_MENU_TEXT .word ASSET_MENU_TEXT_END - ASSET_MENU_TEXT .word 0xFFFFFFFF +glabel ASSET_MENU_TEXT_TABLE_END /********** ASSET_SCREENS **********/ @@ -7868,6 +7873,7 @@ glabel ASSET_SCREENS_END glabel ASSET_SCREENS_TABLE .word ASSET_SCREENS_END - ASSET_SCREENS .word 0xFFFFFFFF +glabel ASSET_SCREENS_TABLE_END /********** ASSET_SPRITES **********/ @@ -8460,6 +8466,7 @@ glabel ASSET_SPRITES_TABLE .word ASSET_SPRITE_MENU_ICONTTAMULET - ASSET_SPRITES .word ASSET_SPRITES_END - ASSET_SPRITES .word 0xFFFFFFFF +glabel ASSET_SPRITES_TABLE_END /********** ASSET_EMPTY_14 **********/ @@ -8472,145 +8479,145 @@ glabel ASSET_EMPTY_14_END .balign 16 glabel ASSET_MISC glabel ASSET_MISC_0 -.incbin "./build/us_1.0/assets/misc/unlabeled/unknown_15_0.bin" +.incbin "./build/us_1.0/assets/misc/unlabeled/asset_misc_0.bin" glabel ASSET_MISC_1 -.incbin "./build/us_1.0/assets/misc/unlabeled/unknown_15_1.bin" +.incbin "./build/us_1.0/assets/misc/unlabeled/asset_misc_1.bin" glabel ASSET_MISC_2 -.incbin "./build/us_1.0/assets/misc/unlabeled/unknown_15_2.bin" +.incbin "./build/us_1.0/assets/misc/unlabeled/asset_misc_2.bin" glabel ASSET_MISC_3 -.incbin "./build/us_1.0/assets/misc/unlabeled/unknown_15_3.bin" +.incbin "./build/us_1.0/assets/misc/unlabeled/asset_misc_3.bin" glabel ASSET_MISC_4 -.incbin "./build/us_1.0/assets/misc/unlabeled/unknown_15_4.bin" -glabel ASSET_MISC_TRICKY_BOSS_DATA -.incbin "./build/us_1.0/assets/misc/unlabeled/tricky_boss_data.bin" -glabel ASSET_MISC_BLUEY_BOSS_DATA -.incbin "./build/us_1.0/assets/misc/unlabeled/bluey_boss_data.bin" -glabel ASSET_MISC_SMOKEY_BOSS_DATA -.incbin "./build/us_1.0/assets/misc/unlabeled/smokey_boss_data.bin" +.incbin "./build/us_1.0/assets/misc/unlabeled/asset_misc_4.bin" +glabel ASSET_MISC_5 +.incbin "./build/us_1.0/assets/misc/unlabeled/asset_misc_5.bin" +glabel ASSET_MISC_6 +.incbin "./build/us_1.0/assets/misc/unlabeled/asset_misc_6.bin" +glabel ASSET_MISC_7 +.incbin "./build/us_1.0/assets/misc/unlabeled/asset_misc_7.bin" glabel ASSET_MISC_8 -.incbin "./build/us_1.0/assets/misc/unlabeled/unknown_15_8.bin" +.incbin "./build/us_1.0/assets/misc/unlabeled/asset_misc_8.bin" glabel ASSET_MISC_RACER_WEIGHT -.incbin "./build/us_1.0/assets/misc/unlabeled/racer_weight_data.bin" +.incbin "./build/us_1.0/assets/misc/racer_stats/racer_weight_data.bin" glabel ASSET_MISC_RACER_HANDLING -.incbin "./build/us_1.0/assets/misc/unlabeled/racer_handling_data.bin" +.incbin "./build/us_1.0/assets/misc/racer_stats/racer_handling_data.bin" glabel ASSET_MISC_RACER_UNUSED_11 -.incbin "./build/us_1.0/assets/misc/unlabeled/racer_unused_11_data.bin" +.incbin "./build/us_1.0/assets/misc/racer_stats/racer_unused_11_data.bin" glabel ASSET_MISC_12 -.incbin "./build/us_1.0/assets/misc/unlabeled/unknown_15_12.bin" +.incbin "./build/us_1.0/assets/misc/unlabeled/asset_misc_12.bin" glabel ASSET_MISC_13 -.incbin "./build/us_1.0/assets/misc/unlabeled/unknown_15_13.bin" +.incbin "./build/us_1.0/assets/misc/unlabeled/asset_misc_13.bin" glabel ASSET_MISC_14 -.incbin "./build/us_1.0/assets/misc/unlabeled/unknown_15_14.bin" +.incbin "./build/us_1.0/assets/misc/unlabeled/asset_misc_14.bin" glabel ASSET_MISC_15 -.incbin "./build/us_1.0/assets/misc/unlabeled/unknown_15_15.bin" +.incbin "./build/us_1.0/assets/misc/unlabeled/asset_misc_15.bin" glabel ASSET_MISC_16 -.incbin "./build/us_1.0/assets/misc/unlabeled/unknown_15_16.bin" +.incbin "./build/us_1.0/assets/misc/unlabeled/asset_misc_16.bin" glabel ASSET_MISC_17 -.incbin "./build/us_1.0/assets/misc/unlabeled/unknown_15_17.bin" +.incbin "./build/us_1.0/assets/misc/unlabeled/asset_misc_17.bin" glabel ASSET_MISC_18 -.incbin "./build/us_1.0/assets/misc/unlabeled/unknown_15_18.bin" +.incbin "./build/us_1.0/assets/misc/unlabeled/asset_misc_18.bin" glabel ASSET_MISC_19 -.incbin "./build/us_1.0/assets/misc/unlabeled/unknown_15_19.bin" +.incbin "./build/us_1.0/assets/misc/unlabeled/asset_misc_19.bin" glabel ASSET_MISC_20 -.incbin "./build/us_1.0/assets/misc/unlabeled/unknown_15_20.bin" +.incbin "./build/us_1.0/assets/misc/unlabeled/asset_misc_20.bin" glabel ASSET_MISC_SHIELD_DATA .incbin "./build/us_1.0/assets/misc/unlabeled/shield_data.bin" glabel ASSET_MISC_MAGNET_DATA .incbin "./build/us_1.0/assets/misc/unlabeled/magnet_data.bin" glabel ASSET_MISC_23 -.incbin "./build/us_1.0/assets/misc/unlabeled/unknown_15_23.bin" +.incbin "./build/us_1.0/assets/misc/unlabeled/asset_misc_23.bin" glabel ASSET_MISC_24 -.incbin "./build/us_1.0/assets/misc/unlabeled/unknown_15_24.bin" +.incbin "./build/us_1.0/assets/misc/unlabeled/asset_misc_24.bin" glabel ASSET_MISC_25 -.incbin "./build/us_1.0/assets/misc/unlabeled/unknown_15_25.bin" +.incbin "./build/us_1.0/assets/misc/unlabeled/asset_misc_25.bin" glabel ASSET_MISC_TRACKS_MENU_IDS -.incbin "./build/us_1.0/assets/misc/unlabeled/tracks_menu_ids.bin" +.incbin "./build/us_1.0/assets/misc/track_ids/tracks_menu_ids.bin" glabel ASSET_MISC_HUB_AREA_IDS -.incbin "./build/us_1.0/assets/misc/unlabeled/hub_area_ids.bin" +.incbin "./build/us_1.0/assets/misc/track_ids/hub_area_ids.bin" glabel ASSET_MISC_MAIN_TRACKS_IDS -.incbin "./build/us_1.0/assets/misc/unlabeled/main_tracks_ids.bin" +.incbin "./build/us_1.0/assets/misc/track_ids/main_tracks_ids.bin" glabel ASSET_MISC_BATTLE_TRACKS_IDS -.incbin "./build/us_1.0/assets/misc/unlabeled/battle_tracks_ids.bin" +.incbin "./build/us_1.0/assets/misc/track_ids/battle_tracks_ids.bin" glabel ASSET_MISC_BOSS_TRACKS_IDS -.incbin "./build/us_1.0/assets/misc/unlabeled/boss_tracks_ids.bin" +.incbin "./build/us_1.0/assets/misc/track_ids/boss_tracks_ids.bin" glabel ASSET_MISC_31 -.incbin "./build/us_1.0/assets/misc/unlabeled/unknown_15_31.bin" +.incbin "./build/us_1.0/assets/misc/unlabeled/asset_misc_31.bin" glabel ASSET_MISC_32 -.incbin "./build/us_1.0/assets/misc/unlabeled/unknown_15_32.bin" -glabel ASSET_MISC_RACERSTATS_UNKNOWN0 -.incbin "./build/us_1.0/assets/misc/unlabeled/RacerStats_Unknown0.bin" -glabel ASSET_MISC_RACERSTATS_DIDDY -.incbin "./build/us_1.0/assets/misc/unlabeled/RacerStats_Diddy.bin" -glabel ASSET_MISC_RACERSTATS_TT -.incbin "./build/us_1.0/assets/misc/unlabeled/RacerStats_TT.bin" -glabel ASSET_MISC_RACERSTATS_UNKNOWN1 -.incbin "./build/us_1.0/assets/misc/unlabeled/RacerStats_Unknown1.bin" -glabel ASSET_MISC_RACERSTATS_KRUNCH -.incbin "./build/us_1.0/assets/misc/unlabeled/RacerStats_Krunch.bin" -glabel ASSET_MISC_RACERSTATS_BUMPER -.incbin "./build/us_1.0/assets/misc/unlabeled/RacerStats_Bumper.bin" -glabel ASSET_MISC_RACERSTATS_TIPTUP -.incbin "./build/us_1.0/assets/misc/unlabeled/RacerStats_Tiptup.bin" -glabel ASSET_MISC_RACERSTATS_CONKER -.incbin "./build/us_1.0/assets/misc/unlabeled/RacerStats_Conker.bin" -glabel ASSET_MISC_RACERSTATS_TIMBER -.incbin "./build/us_1.0/assets/misc/unlabeled/RacerStats_Timber.bin" -glabel ASSET_MISC_RACERSTATS_BANJO -.incbin "./build/us_1.0/assets/misc/unlabeled/RacerStats_Banjo.bin" -glabel ASSET_MISC_RACERSTATS_DRUMSTICK -.incbin "./build/us_1.0/assets/misc/unlabeled/RacerStats_Drumstick.bin" -glabel ASSET_MISC_RACERSTATS_PIPSY -.incbin "./build/us_1.0/assets/misc/unlabeled/RacerStats_Pipsy.bin" -glabel ASSET_MISC_RACERSTATS_UNKNOWN2 -.incbin "./build/us_1.0/assets/misc/unlabeled/RacerStats_Unknown2.bin" +.incbin "./build/us_1.0/assets/misc/unlabeled/asset_misc_32.bin" +glabel ASSET_MISC_RACERACCELERATION_UNKNOWN0 +.incbin "./build/us_1.0/assets/misc/racer_stats/RacerAcceleration_Unknown0.bin" +glabel ASSET_MISC_RACERACCELERATION_DIDDY +.incbin "./build/us_1.0/assets/misc/racer_stats/RacerAcceleration_Diddy.bin" +glabel ASSET_MISC_RACERACCELERATION_TT +.incbin "./build/us_1.0/assets/misc/racer_stats/RacerAcceleration_TT.bin" +glabel ASSET_MISC_RACERACCELERATION_UNKNOWN1 +.incbin "./build/us_1.0/assets/misc/racer_stats/RacerAcceleration_Unknown1.bin" +glabel ASSET_MISC_RACERACCELERATION_KRUNCH +.incbin "./build/us_1.0/assets/misc/racer_stats/RacerAcceleration_Krunch.bin" +glabel ASSET_MISC_RACERACCELERATION_BUMPER +.incbin "./build/us_1.0/assets/misc/racer_stats/RacerAcceleration_Bumper.bin" +glabel ASSET_MISC_RACERACCELERATION_TIPTUP +.incbin "./build/us_1.0/assets/misc/racer_stats/RacerAcceleration_Tiptup.bin" +glabel ASSET_MISC_RACERACCELERATION_CONKER +.incbin "./build/us_1.0/assets/misc/racer_stats/RacerAcceleration_Conker.bin" +glabel ASSET_MISC_RACERACCELERATION_TIMBER +.incbin "./build/us_1.0/assets/misc/racer_stats/RacerAcceleration_Timber.bin" +glabel ASSET_MISC_RACERACCELERATION_BANJO +.incbin "./build/us_1.0/assets/misc/racer_stats/RacerAcceleration_Banjo.bin" +glabel ASSET_MISC_RACERACCELERATION_DRUMSTICK +.incbin "./build/us_1.0/assets/misc/racer_stats/RacerAcceleration_Drumstick.bin" +glabel ASSET_MISC_RACERACCELERATION_PIPSY +.incbin "./build/us_1.0/assets/misc/racer_stats/RacerAcceleration_Pipsy.bin" +glabel ASSET_MISC_RACERACCELERATION_UNKNOWN2 +.incbin "./build/us_1.0/assets/misc/racer_stats/RacerAcceleration_Unknown2.bin" glabel ASSET_MISC_46 -.incbin "./build/us_1.0/assets/misc/unlabeled/unknown_15_46.bin" +.incbin "./build/us_1.0/assets/misc/unlabeled/asset_misc_46.bin" glabel ASSET_MISC_47 -.incbin "./build/us_1.0/assets/misc/unlabeled/unknown_15_47.bin" +.incbin "./build/us_1.0/assets/misc/unlabeled/asset_misc_47.bin" glabel ASSET_MISC_48 -.incbin "./build/us_1.0/assets/misc/unlabeled/unknown_15_48.bin" +.incbin "./build/us_1.0/assets/misc/unlabeled/asset_misc_48.bin" glabel ASSET_MISC_49 -.incbin "./build/us_1.0/assets/misc/unlabeled/unknown_15_49.bin" +.incbin "./build/us_1.0/assets/misc/unlabeled/asset_misc_49.bin" glabel ASSET_MISC_50 -.incbin "./build/us_1.0/assets/misc/unlabeled/unknown_15_50.bin" +.incbin "./build/us_1.0/assets/misc/unlabeled/asset_misc_50.bin" glabel ASSET_MISC_51 -.incbin "./build/us_1.0/assets/misc/unlabeled/unknown_15_51.bin" +.incbin "./build/us_1.0/assets/misc/unlabeled/asset_misc_51.bin" glabel ASSET_MISC_52 -.incbin "./build/us_1.0/assets/misc/unlabeled/unknown_15_52.bin" +.incbin "./build/us_1.0/assets/misc/unlabeled/asset_misc_52.bin" glabel ASSET_MISC_53 -.incbin "./build/us_1.0/assets/misc/unlabeled/unknown_15_53.bin" +.incbin "./build/us_1.0/assets/misc/unlabeled/asset_misc_53.bin" glabel ASSET_MISC_54 -.incbin "./build/us_1.0/assets/misc/unlabeled/unknown_15_54.bin" +.incbin "./build/us_1.0/assets/misc/unlabeled/asset_misc_54.bin" glabel ASSET_MISC_55 -.incbin "./build/us_1.0/assets/misc/unlabeled/unknown_15_55.bin" +.incbin "./build/us_1.0/assets/misc/unlabeled/asset_misc_55.bin" glabel ASSET_MISC_RACER_HITBOX_SIZE .incbin "./build/us_1.0/assets/misc/unlabeled/racer_hitbox_size.bin" glabel ASSET_MISC_57 -.incbin "./build/us_1.0/assets/misc/unlabeled/unknown_15_57.bin" +.incbin "./build/us_1.0/assets/misc/unlabeled/asset_misc_57.bin" glabel ASSET_MISC_58 -.incbin "./build/us_1.0/assets/misc/unlabeled/unknown_15_58.bin" +.incbin "./build/us_1.0/assets/misc/unlabeled/asset_misc_58.bin" glabel ASSET_MISC_59 -.incbin "./build/us_1.0/assets/misc/unlabeled/unknown_15_59.bin" +.incbin "./build/us_1.0/assets/misc/unlabeled/asset_misc_59.bin" glabel ASSET_MISC_60 -.incbin "./build/us_1.0/assets/misc/unlabeled/unknown_15_60.bin" +.incbin "./build/us_1.0/assets/misc/unlabeled/asset_misc_60.bin" glabel ASSET_MISC_61 -.incbin "./build/us_1.0/assets/misc/unlabeled/unknown_15_61.bin" +.incbin "./build/us_1.0/assets/misc/unlabeled/asset_misc_61.bin" glabel ASSET_MISC_62 -.incbin "./build/us_1.0/assets/misc/unlabeled/unknown_15_62.bin" +.incbin "./build/us_1.0/assets/misc/unlabeled/asset_misc_62.bin" glabel ASSET_MISC_63 -.incbin "./build/us_1.0/assets/misc/unlabeled/unknown_15_63.bin" +.incbin "./build/us_1.0/assets/misc/unlabeled/asset_misc_63.bin" glabel ASSET_MISC_64 -.incbin "./build/us_1.0/assets/misc/unlabeled/unknown_15_64.bin" +.incbin "./build/us_1.0/assets/misc/unlabeled/asset_misc_64.bin" glabel ASSET_MISC_MAGIC_CODES -.incbin "./build/us_1.0/assets/misc/unlabeled/magic_codes.bin" +.incbin "./build/us_1.0/assets/misc/cheats/magic_codes.bin" glabel ASSET_MISC_TITLE_SCREEN_DEMO_IDS -.incbin "./build/us_1.0/assets/misc/unlabeled/title_screen_demo_ids.bin" +.incbin "./build/us_1.0/assets/misc/title_screen/title_screen_demo_ids.bin" glabel ASSET_MISC_67 -.incbin "./build/us_1.0/assets/misc/unlabeled/unknown_15_67.bin" +.incbin "./build/us_1.0/assets/misc/unlabeled/asset_misc_67.bin" glabel ASSET_MISC_68 -.incbin "./build/us_1.0/assets/misc/unlabeled/unknown_15_68.bin" +.incbin "./build/us_1.0/assets/misc/unlabeled/asset_misc_68.bin" glabel ASSET_MISC_69 -.incbin "./build/us_1.0/assets/misc/unlabeled/unknown_15_69.bin" +.incbin "./build/us_1.0/assets/misc/unlabeled/asset_misc_69.bin" glabel ASSET_MISC_END /********** ASSET_MISC_TABLE **********/ @@ -8622,9 +8629,9 @@ glabel ASSET_MISC_TABLE .word (ASSET_MISC_2 - ASSET_MISC) / 4 .word (ASSET_MISC_3 - ASSET_MISC) / 4 .word (ASSET_MISC_4 - ASSET_MISC) / 4 -.word (ASSET_MISC_TRICKY_BOSS_DATA - ASSET_MISC) / 4 -.word (ASSET_MISC_BLUEY_BOSS_DATA - ASSET_MISC) / 4 -.word (ASSET_MISC_SMOKEY_BOSS_DATA - ASSET_MISC) / 4 +.word (ASSET_MISC_5 - ASSET_MISC) / 4 +.word (ASSET_MISC_6 - ASSET_MISC) / 4 +.word (ASSET_MISC_7 - ASSET_MISC) / 4 .word (ASSET_MISC_8 - ASSET_MISC) / 4 .word (ASSET_MISC_RACER_WEIGHT - ASSET_MISC) / 4 .word (ASSET_MISC_RACER_HANDLING - ASSET_MISC) / 4 @@ -8650,19 +8657,19 @@ glabel ASSET_MISC_TABLE .word (ASSET_MISC_BOSS_TRACKS_IDS - ASSET_MISC) / 4 .word (ASSET_MISC_31 - ASSET_MISC) / 4 .word (ASSET_MISC_32 - ASSET_MISC) / 4 -.word (ASSET_MISC_RACERSTATS_UNKNOWN0 - ASSET_MISC) / 4 -.word (ASSET_MISC_RACERSTATS_DIDDY - ASSET_MISC) / 4 -.word (ASSET_MISC_RACERSTATS_TT - ASSET_MISC) / 4 -.word (ASSET_MISC_RACERSTATS_UNKNOWN1 - ASSET_MISC) / 4 -.word (ASSET_MISC_RACERSTATS_KRUNCH - ASSET_MISC) / 4 -.word (ASSET_MISC_RACERSTATS_BUMPER - ASSET_MISC) / 4 -.word (ASSET_MISC_RACERSTATS_TIPTUP - ASSET_MISC) / 4 -.word (ASSET_MISC_RACERSTATS_CONKER - ASSET_MISC) / 4 -.word (ASSET_MISC_RACERSTATS_TIMBER - ASSET_MISC) / 4 -.word (ASSET_MISC_RACERSTATS_BANJO - ASSET_MISC) / 4 -.word (ASSET_MISC_RACERSTATS_DRUMSTICK - ASSET_MISC) / 4 -.word (ASSET_MISC_RACERSTATS_PIPSY - ASSET_MISC) / 4 -.word (ASSET_MISC_RACERSTATS_UNKNOWN2 - ASSET_MISC) / 4 +.word (ASSET_MISC_RACERACCELERATION_UNKNOWN0 - ASSET_MISC) / 4 +.word (ASSET_MISC_RACERACCELERATION_DIDDY - ASSET_MISC) / 4 +.word (ASSET_MISC_RACERACCELERATION_TT - ASSET_MISC) / 4 +.word (ASSET_MISC_RACERACCELERATION_UNKNOWN1 - ASSET_MISC) / 4 +.word (ASSET_MISC_RACERACCELERATION_KRUNCH - ASSET_MISC) / 4 +.word (ASSET_MISC_RACERACCELERATION_BUMPER - ASSET_MISC) / 4 +.word (ASSET_MISC_RACERACCELERATION_TIPTUP - ASSET_MISC) / 4 +.word (ASSET_MISC_RACERACCELERATION_CONKER - ASSET_MISC) / 4 +.word (ASSET_MISC_RACERACCELERATION_TIMBER - ASSET_MISC) / 4 +.word (ASSET_MISC_RACERACCELERATION_BANJO - ASSET_MISC) / 4 +.word (ASSET_MISC_RACERACCELERATION_DRUMSTICK - ASSET_MISC) / 4 +.word (ASSET_MISC_RACERACCELERATION_PIPSY - ASSET_MISC) / 4 +.word (ASSET_MISC_RACERACCELERATION_UNKNOWN2 - ASSET_MISC) / 4 .word (ASSET_MISC_46 - ASSET_MISC) / 4 .word (ASSET_MISC_47 - ASSET_MISC) / 4 .word (ASSET_MISC_48 - ASSET_MISC) / 4 @@ -8689,6 +8696,7 @@ glabel ASSET_MISC_TABLE .word (ASSET_MISC_69 - ASSET_MISC) / 4 .word (ASSET_MISC_END - ASSET_MISC) / 4 .word 0xFFFFFFFF +glabel ASSET_MISC_TABLE_END /********** ASSET_HUD_ELEMENT_IDS **********/ @@ -8855,287 +8863,288 @@ glabel ASSET_LEVEL_OBJECT_MAPS_TABLE .word ASSET_LEVEL_OBJECT_MAPS_137 - ASSET_LEVEL_OBJECT_MAPS .word ASSET_LEVEL_OBJECT_MAPS_END - ASSET_LEVEL_OBJECT_MAPS .word 0xFFFFFFFF +glabel ASSET_LEVEL_OBJECT_MAPS_TABLE_END /********** ASSET_LEVEL_OBJECT_MAPS **********/ .balign 16 glabel ASSET_LEVEL_OBJECT_MAPS glabel ASSET_LEVEL_OBJECT_MAPS_0 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_0.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_0.bin" glabel ASSET_LEVEL_OBJECT_MAPS_1 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_1.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_1.bin" glabel ASSET_LEVEL_OBJECT_MAPS_2 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_2.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_2.bin" glabel ASSET_LEVEL_OBJECT_MAPS_3 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_3.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_3.bin" glabel ASSET_LEVEL_OBJECT_MAPS_4 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_4.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_4.bin" glabel ASSET_LEVEL_OBJECT_MAPS_5 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_5.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_5.bin" glabel ASSET_LEVEL_OBJECT_MAPS_6 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_6.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_6.bin" glabel ASSET_LEVEL_OBJECT_MAPS_7 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_7.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_7.bin" glabel ASSET_LEVEL_OBJECT_MAPS_8 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_8.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_8.bin" glabel ASSET_LEVEL_OBJECT_MAPS_9 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_9.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_9.bin" glabel ASSET_LEVEL_OBJECT_MAPS_10 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_10.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_10.bin" glabel ASSET_LEVEL_OBJECT_MAPS_11 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_11.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_11.bin" glabel ASSET_LEVEL_OBJECT_MAPS_12 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_12.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_12.bin" glabel ASSET_LEVEL_OBJECT_MAPS_13 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_13.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_13.bin" glabel ASSET_LEVEL_OBJECT_MAPS_14 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_14.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_14.bin" glabel ASSET_LEVEL_OBJECT_MAPS_15 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_15.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_15.bin" glabel ASSET_LEVEL_OBJECT_MAPS_16 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_16.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_16.bin" glabel ASSET_LEVEL_OBJECT_MAPS_17 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_17.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_17.bin" glabel ASSET_LEVEL_OBJECT_MAPS_18 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_18.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_18.bin" glabel ASSET_LEVEL_OBJECT_MAPS_19 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_19.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_19.bin" glabel ASSET_LEVEL_OBJECT_MAPS_20 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_20.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_20.bin" glabel ASSET_LEVEL_OBJECT_MAPS_21 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_21.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_21.bin" glabel ASSET_LEVEL_OBJECT_MAPS_22 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_22.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_22.bin" glabel ASSET_LEVEL_OBJECT_MAPS_23 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_23.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_23.bin" glabel ASSET_LEVEL_OBJECT_MAPS_24 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_24.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_24.bin" glabel ASSET_LEVEL_OBJECT_MAPS_25 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_25.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_25.bin" glabel ASSET_LEVEL_OBJECT_MAPS_26 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_26.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_26.bin" glabel ASSET_LEVEL_OBJECT_MAPS_27 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_27.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_27.bin" glabel ASSET_LEVEL_OBJECT_MAPS_28 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_28.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_28.bin" glabel ASSET_LEVEL_OBJECT_MAPS_29 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_29.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_29.bin" glabel ASSET_LEVEL_OBJECT_MAPS_30 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_30.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_30.bin" glabel ASSET_LEVEL_OBJECT_MAPS_31 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_31.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_31.bin" glabel ASSET_LEVEL_OBJECT_MAPS_32 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_32.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_32.bin" glabel ASSET_LEVEL_OBJECT_MAPS_33 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_33.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_33.bin" glabel ASSET_LEVEL_OBJECT_MAPS_34 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_34.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_34.bin" glabel ASSET_LEVEL_OBJECT_MAPS_35 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_35.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_35.bin" glabel ASSET_LEVEL_OBJECT_MAPS_36 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_36.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_36.bin" glabel ASSET_LEVEL_OBJECT_MAPS_37 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_37.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_37.bin" glabel ASSET_LEVEL_OBJECT_MAPS_38 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_38.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_38.bin" glabel ASSET_LEVEL_OBJECT_MAPS_39 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_39.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_39.bin" glabel ASSET_LEVEL_OBJECT_MAPS_40 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_40.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_40.bin" glabel ASSET_LEVEL_OBJECT_MAPS_41 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_41.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_41.bin" glabel ASSET_LEVEL_OBJECT_MAPS_42 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_42.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_42.bin" glabel ASSET_LEVEL_OBJECT_MAPS_43 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_43.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_43.bin" glabel ASSET_LEVEL_OBJECT_MAPS_44 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_44.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_44.bin" glabel ASSET_LEVEL_OBJECT_MAPS_45 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_45.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_45.bin" glabel ASSET_LEVEL_OBJECT_MAPS_46 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_46.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_46.bin" glabel ASSET_LEVEL_OBJECT_MAPS_47 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_47.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_47.bin" glabel ASSET_LEVEL_OBJECT_MAPS_48 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_48.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_48.bin" glabel ASSET_LEVEL_OBJECT_MAPS_49 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_49.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_49.bin" glabel ASSET_LEVEL_OBJECT_MAPS_50 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_50.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_50.bin" glabel ASSET_LEVEL_OBJECT_MAPS_51 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_51.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_51.bin" glabel ASSET_LEVEL_OBJECT_MAPS_52 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_52.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_52.bin" glabel ASSET_LEVEL_OBJECT_MAPS_53 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_53.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_53.bin" glabel ASSET_LEVEL_OBJECT_MAPS_54 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_54.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_54.bin" glabel ASSET_LEVEL_OBJECT_MAPS_55 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_55.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_55.bin" glabel ASSET_LEVEL_OBJECT_MAPS_56 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_56.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_56.bin" glabel ASSET_LEVEL_OBJECT_MAPS_57 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_57.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_57.bin" glabel ASSET_LEVEL_OBJECT_MAPS_58 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_58.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_58.bin" glabel ASSET_LEVEL_OBJECT_MAPS_59 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_59.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_59.bin" glabel ASSET_LEVEL_OBJECT_MAPS_60 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_60.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_60.bin" glabel ASSET_LEVEL_OBJECT_MAPS_61 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_61.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_61.bin" glabel ASSET_LEVEL_OBJECT_MAPS_62 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_62.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_62.bin" glabel ASSET_LEVEL_OBJECT_MAPS_63 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_63.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_63.bin" glabel ASSET_LEVEL_OBJECT_MAPS_64 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_64.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_64.bin" glabel ASSET_LEVEL_OBJECT_MAPS_65 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_65.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_65.bin" glabel ASSET_LEVEL_OBJECT_MAPS_66 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_66.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_66.bin" glabel ASSET_LEVEL_OBJECT_MAPS_67 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_67.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_67.bin" glabel ASSET_LEVEL_OBJECT_MAPS_68 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_68.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_68.bin" glabel ASSET_LEVEL_OBJECT_MAPS_69 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_69.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_69.bin" glabel ASSET_LEVEL_OBJECT_MAPS_70 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_70.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_70.bin" glabel ASSET_LEVEL_OBJECT_MAPS_71 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_71.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_71.bin" glabel ASSET_LEVEL_OBJECT_MAPS_72 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_72.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_72.bin" glabel ASSET_LEVEL_OBJECT_MAPS_73 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_73.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_73.bin" glabel ASSET_LEVEL_OBJECT_MAPS_74 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_74.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_74.bin" glabel ASSET_LEVEL_OBJECT_MAPS_75 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_75.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_75.bin" glabel ASSET_LEVEL_OBJECT_MAPS_76 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_76.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_76.bin" glabel ASSET_LEVEL_OBJECT_MAPS_77 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_77.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_77.bin" glabel ASSET_LEVEL_OBJECT_MAPS_78 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_78.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_78.bin" glabel ASSET_LEVEL_OBJECT_MAPS_79 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_79.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_79.bin" glabel ASSET_LEVEL_OBJECT_MAPS_80 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_80.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_80.bin" glabel ASSET_LEVEL_OBJECT_MAPS_81 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_81.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_81.bin" glabel ASSET_LEVEL_OBJECT_MAPS_82 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_82.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_82.bin" glabel ASSET_LEVEL_OBJECT_MAPS_83 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_83.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_83.bin" glabel ASSET_LEVEL_OBJECT_MAPS_84 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_84.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_84.bin" glabel ASSET_LEVEL_OBJECT_MAPS_85 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_85.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_85.bin" glabel ASSET_LEVEL_OBJECT_MAPS_86 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_86.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_86.bin" glabel ASSET_LEVEL_OBJECT_MAPS_87 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_87.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_87.bin" glabel ASSET_LEVEL_OBJECT_MAPS_88 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_88.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_88.bin" glabel ASSET_LEVEL_OBJECT_MAPS_89 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_89.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_89.bin" glabel ASSET_LEVEL_OBJECT_MAPS_90 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_90.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_90.bin" glabel ASSET_LEVEL_OBJECT_MAPS_91 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_91.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_91.bin" glabel ASSET_LEVEL_OBJECT_MAPS_92 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_92.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_92.bin" glabel ASSET_LEVEL_OBJECT_MAPS_93 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_93.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_93.bin" glabel ASSET_LEVEL_OBJECT_MAPS_94 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_94.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_94.bin" glabel ASSET_LEVEL_OBJECT_MAPS_95 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_95.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_95.bin" glabel ASSET_LEVEL_OBJECT_MAPS_96 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_96.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_96.bin" glabel ASSET_LEVEL_OBJECT_MAPS_97 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_97.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_97.bin" glabel ASSET_LEVEL_OBJECT_MAPS_98 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_98.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_98.bin" glabel ASSET_LEVEL_OBJECT_MAPS_99 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_99.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_99.bin" glabel ASSET_LEVEL_OBJECT_MAPS_100 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_100.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_100.bin" glabel ASSET_LEVEL_OBJECT_MAPS_101 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_101.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_101.bin" glabel ASSET_LEVEL_OBJECT_MAPS_102 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_102.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_102.bin" glabel ASSET_LEVEL_OBJECT_MAPS_103 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_103.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_103.bin" glabel ASSET_LEVEL_OBJECT_MAPS_104 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_104.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_104.bin" glabel ASSET_LEVEL_OBJECT_MAPS_105 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_105.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_105.bin" glabel ASSET_LEVEL_OBJECT_MAPS_106 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_106.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_106.bin" glabel ASSET_LEVEL_OBJECT_MAPS_107 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_107.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_107.bin" glabel ASSET_LEVEL_OBJECT_MAPS_108 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_108.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_108.bin" glabel ASSET_LEVEL_OBJECT_MAPS_109 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_109.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_109.bin" glabel ASSET_LEVEL_OBJECT_MAPS_110 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_110.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_110.bin" glabel ASSET_LEVEL_OBJECT_MAPS_111 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_111.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_111.bin" glabel ASSET_LEVEL_OBJECT_MAPS_112 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_112.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_112.bin" glabel ASSET_LEVEL_OBJECT_MAPS_113 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_113.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_113.bin" glabel ASSET_LEVEL_OBJECT_MAPS_114 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_114.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_114.bin" glabel ASSET_LEVEL_OBJECT_MAPS_115 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_115.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_115.bin" glabel ASSET_LEVEL_OBJECT_MAPS_116 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_116.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_116.bin" glabel ASSET_LEVEL_OBJECT_MAPS_117 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_117.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_117.bin" glabel ASSET_LEVEL_OBJECT_MAPS_118 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_118.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_118.bin" glabel ASSET_LEVEL_OBJECT_MAPS_119 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_119.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_119.bin" glabel ASSET_LEVEL_OBJECT_MAPS_120 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_120.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_120.bin" glabel ASSET_LEVEL_OBJECT_MAPS_121 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_121.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_121.bin" glabel ASSET_LEVEL_OBJECT_MAPS_122 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_122.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_122.bin" glabel ASSET_LEVEL_OBJECT_MAPS_123 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_123.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_123.bin" glabel ASSET_LEVEL_OBJECT_MAPS_124 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_124.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_124.bin" glabel ASSET_LEVEL_OBJECT_MAPS_125 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_125.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_125.bin" glabel ASSET_LEVEL_OBJECT_MAPS_126 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_126.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_126.bin" glabel ASSET_LEVEL_OBJECT_MAPS_127 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_127.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_127.bin" glabel ASSET_LEVEL_OBJECT_MAPS_128 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_128.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_128.bin" glabel ASSET_LEVEL_OBJECT_MAPS_129 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_129.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_129.bin" glabel ASSET_LEVEL_OBJECT_MAPS_130 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_130.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_130.bin" glabel ASSET_LEVEL_OBJECT_MAPS_131 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_131.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_131.bin" glabel ASSET_LEVEL_OBJECT_MAPS_132 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_132.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_132.bin" glabel ASSET_LEVEL_OBJECT_MAPS_133 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_133.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_133.bin" glabel ASSET_LEVEL_OBJECT_MAPS_134 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_134.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_134.bin" glabel ASSET_LEVEL_OBJECT_MAPS_135 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_135.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_135.bin" glabel ASSET_LEVEL_OBJECT_MAPS_136 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_136.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_136.bin" glabel ASSET_LEVEL_OBJECT_MAPS_137 -.incbin "./build/us_1.0/assets/levels/objectMaps/unknown_21_137.bin" +.incbin "./build/us_1.0/assets/levels/objectMaps/asset_level_object_maps_137.bin" glabel ASSET_LEVEL_OBJECT_MAPS_END /********** ASSET_LEVEL_HEADERS_TABLE **********/ @@ -9209,6 +9218,7 @@ glabel ASSET_LEVEL_HEADERS_TABLE .word ASSET_LEVEL_LASTBITB - ASSET_LEVEL_HEADERS .word ASSET_LEVEL_HEADERS_END - ASSET_LEVEL_HEADERS .word 0xFFFFFFFF +glabel ASSET_LEVEL_HEADERS_TABLE_END /********** ASSET_LEVEL_HEADERS **********/ @@ -9350,208 +9360,209 @@ glabel ASSET_LEVEL_HEADERS_END .balign 16 glabel ASSET_LEVEL_NAMES_TABLE -.word ASSET_LEVELNAME_CENTRALAREAHUB - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_BLUEY1 - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_DRAGONFORESTHUB - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_FOSSILCANYON - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_PIRATELAGOON - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_ANCIENTLAKE - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_WALRUSCOVE - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_HOTTOPVOLCANO - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_WHALEBAY - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_SNOWBALLVALLEY - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_CRESCENTISLAND - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_FIREMOUNTAIN - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_DINODOMAINHUB - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_EVERFROSTPEAK - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_SHERBETISLANDHUB - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_SPACEPORTALPHA - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_HORSESHOEGULCH - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_SPACEDUSTALLEY - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_GREENWOODVILLAGE - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_BOULDERCANYON - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_WINDMILLPLAINS - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_FRONTEND - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_CHARACTERSELECT - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_TITLESCREENSEQUENCE - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_SNOWFLAKEMOUNTAINHUB - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_SMOKEYCASTLE - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_DARKWATERBEACH - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_ICICLEPYRAMID - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_FROSTYVILLAGE - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_JUNGLEFALLS - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_TREASURECAVES - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_HAUNTEDWOODS - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_DARKMOONCAVERNS - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_STARCITY - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_TROPHYRACE - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_FUTUREFUNLANDHUB - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_OPENINGSEQUENCE - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_WIZPIG1 - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_TRICKYTOPS1 - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_OPTIONSBACKGROUND - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_BUBBLER1 - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_SMOKEY1 - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_WIZPIGMOUTHSEQUENCE - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_WIZPIGAMULETSEQUENCE - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_TTAMULETSEQUENCE - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_ROCKETSEQUENCE - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_TRICKYTOPS2 - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_DINODOMAINTROPHYANIM - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_SNOWFLAKEMOUNTAINTROPHYANIM - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_SHERBETISLANDTROPHYANIM - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_DRAGONFORESTTROPHYANIM - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_FUTUREFUNLANDTROPHYANIM - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_BLUEY2 - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_BUBBLER2 - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_SMOKEY2 - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_WIZPIG2 - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_PARTYSEQUENCE - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_TRICKTOPSANIM - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_SMOKEYANIM - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_BLUEYANIM - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_WIZPIG1ANIM - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_BUBBLERANIM - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_WIZPIG2ANIM - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_LASTBIT - ASSET_LEVEL_NAMES -.word ASSET_LEVELNAME_LASTBITB - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_CENTRALAREAHUB_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_BLUEY1_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_DRAGONFORESTHUB_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_FOSSILCANYON_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_PIRATELAGOON_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_ANCIENTLAKE_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_WALRUSCOVE_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_HOTTOPVOLCANO_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_WHALEBAY_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_SNOWBALLVALLEY_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_CRESCENTISLAND_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_FIREMOUNTAIN_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_DINODOMAINHUB_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_EVERFROSTPEAK_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_SHERBETISLANDHUB_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_SPACEPORTALPHA_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_HORSESHOEGULCH_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_SPACEDUSTALLEY_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_GREENWOODVILLAGE_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_BOULDERCANYON_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_WINDMILLPLAINS_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_FRONTEND_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_CHARACTERSELECT_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_TITLESCREENSEQUENCE_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_SNOWFLAKEMOUNTAINHUB_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_SMOKEYCASTLE_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_DARKWATERBEACH_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_ICICLEPYRAMID_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_FROSTYVILLAGE_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_JUNGLEFALLS_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_TREASURECAVES_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_HAUNTEDWOODS_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_DARKMOONCAVERNS_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_STARCITY_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_TROPHYRACE_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_FUTUREFUNLANDHUB_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_OPENINGSEQUENCE_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_WIZPIG1_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_TRICKYTOPS1_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_OPTIONSBACKGROUND_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_BUBBLER1_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_SMOKEY1_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_WIZPIGMOUTHSEQUENCE_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_WIZPIGAMULETSEQUENCE_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_TTAMULETSEQUENCE_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_ROCKETSEQUENCE_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_TRICKYTOPS2_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_DINODOMAINTROPHYANIM_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_SNOWFLAKEMOUNTAINTROPHYANIM_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_SHERBETISLANDTROPHYANIM_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_DRAGONFORESTTROPHYANIM_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_FUTUREFUNLANDTROPHYANIM_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_BLUEY2_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_BUBBLER2_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_SMOKEY2_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_WIZPIG2_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_PARTYSEQUENCE_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_TRICKTOPSANIM_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_SMOKEYANIM_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_BLUEYANIM_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_WIZPIG1ANIM_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_BUBBLERANIM_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_WIZPIG2ANIM_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_LASTBIT_NAME - ASSET_LEVEL_NAMES +.word ASSET_LEVEL_LASTBITB_NAME - ASSET_LEVEL_NAMES .word ASSET_LEVEL_NAMES_END - ASSET_LEVEL_NAMES .word 0xFFFFFFFF +glabel ASSET_LEVEL_NAMES_TABLE_END /********** ASSET_LEVEL_NAMES **********/ .balign 16 glabel ASSET_LEVEL_NAMES -glabel ASSET_LEVELNAME_CENTRALAREAHUB -.incbin "./build/us_1.0/assets/levels/names/CentralAreaHubName.bin" -glabel ASSET_LEVELNAME_BLUEY1 -.incbin "./build/us_1.0/assets/levels/names/Bluey1Name.bin" -glabel ASSET_LEVELNAME_DRAGONFORESTHUB -.incbin "./build/us_1.0/assets/levels/names/DragonForestHubName.bin" -glabel ASSET_LEVELNAME_FOSSILCANYON -.incbin "./build/us_1.0/assets/levels/names/FossilCanyonName.bin" -glabel ASSET_LEVELNAME_PIRATELAGOON -.incbin "./build/us_1.0/assets/levels/names/PirateLagoonName.bin" -glabel ASSET_LEVELNAME_ANCIENTLAKE -.incbin "./build/us_1.0/assets/levels/names/AncientLakeName.bin" -glabel ASSET_LEVELNAME_WALRUSCOVE -.incbin "./build/us_1.0/assets/levels/names/WalrusCoveName.bin" -glabel ASSET_LEVELNAME_HOTTOPVOLCANO -.incbin "./build/us_1.0/assets/levels/names/HotTopVolcanoName.bin" -glabel ASSET_LEVELNAME_WHALEBAY -.incbin "./build/us_1.0/assets/levels/names/WhaleBayName.bin" -glabel ASSET_LEVELNAME_SNOWBALLVALLEY -.incbin "./build/us_1.0/assets/levels/names/SnowballValleyName.bin" -glabel ASSET_LEVELNAME_CRESCENTISLAND -.incbin "./build/us_1.0/assets/levels/names/CrescentIslandName.bin" -glabel ASSET_LEVELNAME_FIREMOUNTAIN -.incbin "./build/us_1.0/assets/levels/names/FireMountainName.bin" -glabel ASSET_LEVELNAME_DINODOMAINHUB -.incbin "./build/us_1.0/assets/levels/names/DinoDomainHubName.bin" -glabel ASSET_LEVELNAME_EVERFROSTPEAK -.incbin "./build/us_1.0/assets/levels/names/EverfrostPeakName.bin" -glabel ASSET_LEVELNAME_SHERBETISLANDHUB -.incbin "./build/us_1.0/assets/levels/names/SherbetIslandHubName.bin" -glabel ASSET_LEVELNAME_SPACEPORTALPHA -.incbin "./build/us_1.0/assets/levels/names/SpaceportAlphaName.bin" -glabel ASSET_LEVELNAME_HORSESHOEGULCH -.incbin "./build/us_1.0/assets/levels/names/HorseshoeGulchName.bin" -glabel ASSET_LEVELNAME_SPACEDUSTALLEY -.incbin "./build/us_1.0/assets/levels/names/SpacedustAlleyName.bin" -glabel ASSET_LEVELNAME_GREENWOODVILLAGE -.incbin "./build/us_1.0/assets/levels/names/GreenwoodVillageName.bin" -glabel ASSET_LEVELNAME_BOULDERCANYON -.incbin "./build/us_1.0/assets/levels/names/BoulderCanyonName.bin" -glabel ASSET_LEVELNAME_WINDMILLPLAINS -.incbin "./build/us_1.0/assets/levels/names/WindmillPlainsName.bin" -glabel ASSET_LEVELNAME_FRONTEND -.incbin "./build/us_1.0/assets/levels/names/FrontEndName.bin" -glabel ASSET_LEVELNAME_CHARACTERSELECT -.incbin "./build/us_1.0/assets/levels/names/CharacterSelectName.bin" -glabel ASSET_LEVELNAME_TITLESCREENSEQUENCE -.incbin "./build/us_1.0/assets/levels/names/TitleScreenSequenceName.bin" -glabel ASSET_LEVELNAME_SNOWFLAKEMOUNTAINHUB -.incbin "./build/us_1.0/assets/levels/names/SnowflakeMountainHubName.bin" -glabel ASSET_LEVELNAME_SMOKEYCASTLE -.incbin "./build/us_1.0/assets/levels/names/SmokeyCastleName.bin" -glabel ASSET_LEVELNAME_DARKWATERBEACH -.incbin "./build/us_1.0/assets/levels/names/DarkwaterBeachName.bin" -glabel ASSET_LEVELNAME_ICICLEPYRAMID -.incbin "./build/us_1.0/assets/levels/names/IciclePyramidName.bin" -glabel ASSET_LEVELNAME_FROSTYVILLAGE -.incbin "./build/us_1.0/assets/levels/names/FrostyVillageName.bin" -glabel ASSET_LEVELNAME_JUNGLEFALLS -.incbin "./build/us_1.0/assets/levels/names/JungleFallsName.bin" -glabel ASSET_LEVELNAME_TREASURECAVES -.incbin "./build/us_1.0/assets/levels/names/TreasureCavesName.bin" -glabel ASSET_LEVELNAME_HAUNTEDWOODS -.incbin "./build/us_1.0/assets/levels/names/HauntedWoodsName.bin" -glabel ASSET_LEVELNAME_DARKMOONCAVERNS -.incbin "./build/us_1.0/assets/levels/names/DarkmoonCavernsName.bin" -glabel ASSET_LEVELNAME_STARCITY -.incbin "./build/us_1.0/assets/levels/names/StarCityName.bin" -glabel ASSET_LEVELNAME_TROPHYRACE -.incbin "./build/us_1.0/assets/levels/names/TrophyRaceName.bin" -glabel ASSET_LEVELNAME_FUTUREFUNLANDHUB -.incbin "./build/us_1.0/assets/levels/names/FutureFunLandHubName.bin" -glabel ASSET_LEVELNAME_OPENINGSEQUENCE -.incbin "./build/us_1.0/assets/levels/names/OpeningSequenceName.bin" -glabel ASSET_LEVELNAME_WIZPIG1 -.incbin "./build/us_1.0/assets/levels/names/Wizpig1Name.bin" -glabel ASSET_LEVELNAME_TRICKYTOPS1 -.incbin "./build/us_1.0/assets/levels/names/Trickytops1Name.bin" -glabel ASSET_LEVELNAME_OPTIONSBACKGROUND -.incbin "./build/us_1.0/assets/levels/names/OptionsBackgroundName.bin" -glabel ASSET_LEVELNAME_BUBBLER1 -.incbin "./build/us_1.0/assets/levels/names/Bubbler1Name.bin" -glabel ASSET_LEVELNAME_SMOKEY1 -.incbin "./build/us_1.0/assets/levels/names/Smokey1Name.bin" -glabel ASSET_LEVELNAME_WIZPIGMOUTHSEQUENCE -.incbin "./build/us_1.0/assets/levels/names/WizpigMouthSequenceName.bin" -glabel ASSET_LEVELNAME_WIZPIGAMULETSEQUENCE -.incbin "./build/us_1.0/assets/levels/names/WizpigAmuletSequenceName.bin" -glabel ASSET_LEVELNAME_TTAMULETSEQUENCE -.incbin "./build/us_1.0/assets/levels/names/TTAmuletSequenceName.bin" -glabel ASSET_LEVELNAME_ROCKETSEQUENCE -.incbin "./build/us_1.0/assets/levels/names/RocketSequenceName.bin" -glabel ASSET_LEVELNAME_TRICKYTOPS2 -.incbin "./build/us_1.0/assets/levels/names/Trickytops2Name.bin" -glabel ASSET_LEVELNAME_DINODOMAINTROPHYANIM -.incbin "./build/us_1.0/assets/levels/names/DinoDomainTrophyAnimName.bin" -glabel ASSET_LEVELNAME_SNOWFLAKEMOUNTAINTROPHYANIM -.incbin "./build/us_1.0/assets/levels/names/SnowflakeMountainTrophyAnimName.bin" -glabel ASSET_LEVELNAME_SHERBETISLANDTROPHYANIM -.incbin "./build/us_1.0/assets/levels/names/SherbetIslandTrophyAnimName.bin" -glabel ASSET_LEVELNAME_DRAGONFORESTTROPHYANIM -.incbin "./build/us_1.0/assets/levels/names/DragonForestTrophyAnimName.bin" -glabel ASSET_LEVELNAME_FUTUREFUNLANDTROPHYANIM -.incbin "./build/us_1.0/assets/levels/names/FutureFunLandTrophyAnimName.bin" -glabel ASSET_LEVELNAME_BLUEY2 -.incbin "./build/us_1.0/assets/levels/names/Bluey2Name.bin" -glabel ASSET_LEVELNAME_BUBBLER2 -.incbin "./build/us_1.0/assets/levels/names/Bubbler2Name.bin" -glabel ASSET_LEVELNAME_SMOKEY2 -.incbin "./build/us_1.0/assets/levels/names/Smokey2Name.bin" -glabel ASSET_LEVELNAME_WIZPIG2 -.incbin "./build/us_1.0/assets/levels/names/Wizpig2Name.bin" -glabel ASSET_LEVELNAME_PARTYSEQUENCE -.incbin "./build/us_1.0/assets/levels/names/PartySequenceName.bin" -glabel ASSET_LEVELNAME_TRICKTOPSANIM -.incbin "./build/us_1.0/assets/levels/names/TricktopsAnimName.bin" -glabel ASSET_LEVELNAME_SMOKEYANIM -.incbin "./build/us_1.0/assets/levels/names/SmokeyAnimName.bin" -glabel ASSET_LEVELNAME_BLUEYANIM -.incbin "./build/us_1.0/assets/levels/names/BlueyAnimName.bin" -glabel ASSET_LEVELNAME_WIZPIG1ANIM -.incbin "./build/us_1.0/assets/levels/names/Wizpig1AnimName.bin" -glabel ASSET_LEVELNAME_BUBBLERANIM -.incbin "./build/us_1.0/assets/levels/names/BubblerAnimName.bin" -glabel ASSET_LEVELNAME_WIZPIG2ANIM -.incbin "./build/us_1.0/assets/levels/names/Wizpig2AnimName.bin" -glabel ASSET_LEVELNAME_LASTBIT -.incbin "./build/us_1.0/assets/levels/names/LastBitName.bin" -glabel ASSET_LEVELNAME_LASTBITB -.incbin "./build/us_1.0/assets/levels/names/LastBitBName.bin" +glabel ASSET_LEVEL_CENTRALAREAHUB_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/CentralAreaHub.bin" +glabel ASSET_LEVEL_BLUEY1_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/Bluey1.bin" +glabel ASSET_LEVEL_DRAGONFORESTHUB_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/DragonForestHub.bin" +glabel ASSET_LEVEL_FOSSILCANYON_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/FossilCanyon.bin" +glabel ASSET_LEVEL_PIRATELAGOON_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/PirateLagoon.bin" +glabel ASSET_LEVEL_ANCIENTLAKE_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/AncientLake.bin" +glabel ASSET_LEVEL_WALRUSCOVE_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/WalrusCove.bin" +glabel ASSET_LEVEL_HOTTOPVOLCANO_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/HotTopVolcano.bin" +glabel ASSET_LEVEL_WHALEBAY_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/WhaleBay.bin" +glabel ASSET_LEVEL_SNOWBALLVALLEY_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/SnowballValley.bin" +glabel ASSET_LEVEL_CRESCENTISLAND_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/CrescentIsland.bin" +glabel ASSET_LEVEL_FIREMOUNTAIN_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/FireMountain.bin" +glabel ASSET_LEVEL_DINODOMAINHUB_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/DinoDomainHub.bin" +glabel ASSET_LEVEL_EVERFROSTPEAK_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/EverfrostPeak.bin" +glabel ASSET_LEVEL_SHERBETISLANDHUB_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/SherbetIslandHub.bin" +glabel ASSET_LEVEL_SPACEPORTALPHA_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/SpaceportAlpha.bin" +glabel ASSET_LEVEL_HORSESHOEGULCH_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/HorseshoeGulch.bin" +glabel ASSET_LEVEL_SPACEDUSTALLEY_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/SpacedustAlley.bin" +glabel ASSET_LEVEL_GREENWOODVILLAGE_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/GreenwoodVillage.bin" +glabel ASSET_LEVEL_BOULDERCANYON_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/BoulderCanyon.bin" +glabel ASSET_LEVEL_WINDMILLPLAINS_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/WindmillPlains.bin" +glabel ASSET_LEVEL_FRONTEND_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/FrontEnd.bin" +glabel ASSET_LEVEL_CHARACTERSELECT_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/CharacterSelect.bin" +glabel ASSET_LEVEL_TITLESCREENSEQUENCE_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/TitleScreenSequence.bin" +glabel ASSET_LEVEL_SNOWFLAKEMOUNTAINHUB_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/SnowflakeMountainHub.bin" +glabel ASSET_LEVEL_SMOKEYCASTLE_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/SmokeyCastle.bin" +glabel ASSET_LEVEL_DARKWATERBEACH_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/DarkwaterBeach.bin" +glabel ASSET_LEVEL_ICICLEPYRAMID_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/IciclePyramid.bin" +glabel ASSET_LEVEL_FROSTYVILLAGE_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/FrostyVillage.bin" +glabel ASSET_LEVEL_JUNGLEFALLS_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/JungleFalls.bin" +glabel ASSET_LEVEL_TREASURECAVES_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/TreasureCaves.bin" +glabel ASSET_LEVEL_HAUNTEDWOODS_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/HauntedWoods.bin" +glabel ASSET_LEVEL_DARKMOONCAVERNS_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/DarkmoonCaverns.bin" +glabel ASSET_LEVEL_STARCITY_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/StarCity.bin" +glabel ASSET_LEVEL_TROPHYRACE_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/TrophyRace.bin" +glabel ASSET_LEVEL_FUTUREFUNLANDHUB_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/FutureFunLandHub.bin" +glabel ASSET_LEVEL_OPENINGSEQUENCE_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/OpeningSequence.bin" +glabel ASSET_LEVEL_WIZPIG1_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/Wizpig1.bin" +glabel ASSET_LEVEL_TRICKYTOPS1_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/Trickytops1.bin" +glabel ASSET_LEVEL_OPTIONSBACKGROUND_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/OptionsBackground.bin" +glabel ASSET_LEVEL_BUBBLER1_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/Bubbler1.bin" +glabel ASSET_LEVEL_SMOKEY1_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/Smokey1.bin" +glabel ASSET_LEVEL_WIZPIGMOUTHSEQUENCE_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/WizpigMouthSequence.bin" +glabel ASSET_LEVEL_WIZPIGAMULETSEQUENCE_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/WizpigAmuletSequence.bin" +glabel ASSET_LEVEL_TTAMULETSEQUENCE_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/TTAmuletSequence.bin" +glabel ASSET_LEVEL_ROCKETSEQUENCE_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/RocketSequence.bin" +glabel ASSET_LEVEL_TRICKYTOPS2_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/Trickytops2.bin" +glabel ASSET_LEVEL_DINODOMAINTROPHYANIM_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/DinoDomainTrophyAnim.bin" +glabel ASSET_LEVEL_SNOWFLAKEMOUNTAINTROPHYANIM_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/SnowflakeMountainTrophyAnim.bin" +glabel ASSET_LEVEL_SHERBETISLANDTROPHYANIM_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/SherbetIslandTrophyAnim.bin" +glabel ASSET_LEVEL_DRAGONFORESTTROPHYANIM_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/DragonForestTrophyAnim.bin" +glabel ASSET_LEVEL_FUTUREFUNLANDTROPHYANIM_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/FutureFunLandTrophyAnim.bin" +glabel ASSET_LEVEL_BLUEY2_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/Bluey2.bin" +glabel ASSET_LEVEL_BUBBLER2_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/Bubbler2.bin" +glabel ASSET_LEVEL_SMOKEY2_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/Smokey2.bin" +glabel ASSET_LEVEL_WIZPIG2_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/Wizpig2.bin" +glabel ASSET_LEVEL_PARTYSEQUENCE_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/PartySequence.bin" +glabel ASSET_LEVEL_TRICKTOPSANIM_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/TricktopsAnim.bin" +glabel ASSET_LEVEL_SMOKEYANIM_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/SmokeyAnim.bin" +glabel ASSET_LEVEL_BLUEYANIM_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/BlueyAnim.bin" +glabel ASSET_LEVEL_WIZPIG1ANIM_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/Wizpig1Anim.bin" +glabel ASSET_LEVEL_BUBBLERANIM_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/BubblerAnim.bin" +glabel ASSET_LEVEL_WIZPIG2ANIM_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/Wizpig2Anim.bin" +glabel ASSET_LEVEL_LASTBIT_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/LastBit.bin" +glabel ASSET_LEVEL_LASTBITB_NAME +.incbin "./build/us_1.0/assets/levels/headers/../names/LastBitB.bin" glabel ASSET_LEVEL_NAMES_END /********** ASSET_LEVEL_MODELS_TABLE **********/ @@ -9615,6 +9626,7 @@ glabel ASSET_LEVEL_MODELS_TABLE .word ASSET_LEVELMODEL_ENDINGPART2 - ASSET_LEVEL_MODELS .word ASSET_LEVEL_MODELS_END - ASSET_LEVEL_MODELS .word 0xFFFFFFFF +glabel ASSET_LEVEL_MODELS_TABLE_END /********** ASSET_LEVEL_MODELS **********/ @@ -10128,6 +10140,7 @@ glabel ASSET_OBJECT_MODELS_TABLE .word ASSET_OBJECTMODEL_MAGNETFX - ASSET_OBJECT_MODELS .word ASSET_OBJECT_MODELS_END - ASSET_OBJECT_MODELS .word 0xFFFFFFFF +glabel ASSET_OBJECT_MODELS_TABLE_END /********** ASSET_OBJECT_MODELS **********/ @@ -11398,1877 +11411,1879 @@ glabel ASSET_OBJECT_ANIMATIONS_TABLE .word ASSET_OBJECT_ANIMATIONS_469 - ASSET_OBJECT_ANIMATIONS .word ASSET_OBJECT_ANIMATIONS_END - ASSET_OBJECT_ANIMATIONS .word 0xFFFFFFFF +glabel ASSET_OBJECT_ANIMATIONS_TABLE_END /********** ASSET_OBJECT_ANIMATIONS **********/ .balign 16 glabel ASSET_OBJECT_ANIMATIONS glabel ASSET_OBJECT_ANIMATIONS_0 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_0.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_0.bin" glabel ASSET_OBJECT_ANIMATIONS_1 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_1.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_1.bin" glabel ASSET_OBJECT_ANIMATIONS_2 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_2.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_2.bin" glabel ASSET_OBJECT_ANIMATIONS_3 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_3.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_3.bin" glabel ASSET_OBJECT_ANIMATIONS_4 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_4.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_4.bin" glabel ASSET_OBJECT_ANIMATIONS_5 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_5.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_5.bin" glabel ASSET_OBJECT_ANIMATIONS_6 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_6.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_6.bin" glabel ASSET_OBJECT_ANIMATIONS_7 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_7.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_7.bin" glabel ASSET_OBJECT_ANIMATIONS_8 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_8.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_8.bin" glabel ASSET_OBJECT_ANIMATIONS_9 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_9.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_9.bin" glabel ASSET_OBJECT_ANIMATIONS_10 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_10.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_10.bin" glabel ASSET_OBJECT_ANIMATIONS_11 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_11.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_11.bin" glabel ASSET_OBJECT_ANIMATIONS_12 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_12.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_12.bin" glabel ASSET_OBJECT_ANIMATIONS_13 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_13.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_13.bin" glabel ASSET_OBJECT_ANIMATIONS_14 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_14.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_14.bin" glabel ASSET_OBJECT_ANIMATIONS_15 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_15.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_15.bin" glabel ASSET_OBJECT_ANIMATIONS_16 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_16.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_16.bin" glabel ASSET_OBJECT_ANIMATIONS_17 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_17.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_17.bin" glabel ASSET_OBJECT_ANIMATIONS_18 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_18.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_18.bin" glabel ASSET_OBJECT_ANIMATIONS_19 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_19.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_19.bin" glabel ASSET_OBJECT_ANIMATIONS_20 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_20.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_20.bin" glabel ASSET_OBJECT_ANIMATIONS_21 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_21.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_21.bin" glabel ASSET_OBJECT_ANIMATIONS_22 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_22.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_22.bin" glabel ASSET_OBJECT_ANIMATIONS_23 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_23.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_23.bin" glabel ASSET_OBJECT_ANIMATIONS_24 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_24.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_24.bin" glabel ASSET_OBJECT_ANIMATIONS_25 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_25.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_25.bin" glabel ASSET_OBJECT_ANIMATIONS_26 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_26.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_26.bin" glabel ASSET_OBJECT_ANIMATIONS_27 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_27.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_27.bin" glabel ASSET_OBJECT_ANIMATIONS_28 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_28.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_28.bin" glabel ASSET_OBJECT_ANIMATIONS_29 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_29.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_29.bin" glabel ASSET_OBJECT_ANIMATIONS_30 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_30.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_30.bin" glabel ASSET_OBJECT_ANIMATIONS_31 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_31.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_31.bin" glabel ASSET_OBJECT_ANIMATIONS_32 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_32.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_32.bin" glabel ASSET_OBJECT_ANIMATIONS_33 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_33.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_33.bin" glabel ASSET_OBJECT_ANIMATIONS_34 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_34.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_34.bin" glabel ASSET_OBJECT_ANIMATIONS_35 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_35.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_35.bin" glabel ASSET_OBJECT_ANIMATIONS_36 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_36.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_36.bin" glabel ASSET_OBJECT_ANIMATIONS_37 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_37.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_37.bin" glabel ASSET_OBJECT_ANIMATIONS_38 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_38.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_38.bin" glabel ASSET_OBJECT_ANIMATIONS_39 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_39.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_39.bin" glabel ASSET_OBJECT_ANIMATIONS_40 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_40.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_40.bin" glabel ASSET_OBJECT_ANIMATIONS_41 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_41.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_41.bin" glabel ASSET_OBJECT_ANIMATIONS_42 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_42.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_42.bin" glabel ASSET_OBJECT_ANIMATIONS_43 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_43.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_43.bin" glabel ASSET_OBJECT_ANIMATIONS_44 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_44.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_44.bin" glabel ASSET_OBJECT_ANIMATIONS_45 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_45.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_45.bin" glabel ASSET_OBJECT_ANIMATIONS_46 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_46.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_46.bin" glabel ASSET_OBJECT_ANIMATIONS_47 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_47.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_47.bin" glabel ASSET_OBJECT_ANIMATIONS_48 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_48.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_48.bin" glabel ASSET_OBJECT_ANIMATIONS_49 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_49.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_49.bin" glabel ASSET_OBJECT_ANIMATIONS_50 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_50.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_50.bin" glabel ASSET_OBJECT_ANIMATIONS_51 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_51.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_51.bin" glabel ASSET_OBJECT_ANIMATIONS_52 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_52.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_52.bin" glabel ASSET_OBJECT_ANIMATIONS_53 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_53.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_53.bin" glabel ASSET_OBJECT_ANIMATIONS_54 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_54.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_54.bin" glabel ASSET_OBJECT_ANIMATIONS_55 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_55.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_55.bin" glabel ASSET_OBJECT_ANIMATIONS_56 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_56.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_56.bin" glabel ASSET_OBJECT_ANIMATIONS_57 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_57.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_57.bin" glabel ASSET_OBJECT_ANIMATIONS_58 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_58.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_58.bin" glabel ASSET_OBJECT_ANIMATIONS_59 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_59.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_59.bin" glabel ASSET_OBJECT_ANIMATIONS_60 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_60.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_60.bin" glabel ASSET_OBJECT_ANIMATIONS_61 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_61.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_61.bin" glabel ASSET_OBJECT_ANIMATIONS_62 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_62.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_62.bin" glabel ASSET_OBJECT_ANIMATIONS_63 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_63.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_63.bin" glabel ASSET_OBJECT_ANIMATIONS_64 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_64.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_64.bin" glabel ASSET_OBJECT_ANIMATIONS_65 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_65.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_65.bin" glabel ASSET_OBJECT_ANIMATIONS_66 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_66.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_66.bin" glabel ASSET_OBJECT_ANIMATIONS_67 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_67.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_67.bin" glabel ASSET_OBJECT_ANIMATIONS_68 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_68.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_68.bin" glabel ASSET_OBJECT_ANIMATIONS_69 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_69.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_69.bin" glabel ASSET_OBJECT_ANIMATIONS_70 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_70.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_70.bin" glabel ASSET_OBJECT_ANIMATIONS_71 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_71.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_71.bin" glabel ASSET_OBJECT_ANIMATIONS_72 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_72.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_72.bin" glabel ASSET_OBJECT_ANIMATIONS_73 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_73.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_73.bin" glabel ASSET_OBJECT_ANIMATIONS_74 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_74.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_74.bin" glabel ASSET_OBJECT_ANIMATIONS_75 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_75.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_75.bin" glabel ASSET_OBJECT_ANIMATIONS_76 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_76.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_76.bin" glabel ASSET_OBJECT_ANIMATIONS_77 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_77.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_77.bin" glabel ASSET_OBJECT_ANIMATIONS_78 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_78.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_78.bin" glabel ASSET_OBJECT_ANIMATIONS_79 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_79.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_79.bin" glabel ASSET_OBJECT_ANIMATIONS_80 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_80.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_80.bin" glabel ASSET_OBJECT_ANIMATIONS_81 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_81.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_81.bin" glabel ASSET_OBJECT_ANIMATIONS_82 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_82.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_82.bin" glabel ASSET_OBJECT_ANIMATIONS_83 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_83.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_83.bin" glabel ASSET_OBJECT_ANIMATIONS_84 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_84.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_84.bin" glabel ASSET_OBJECT_ANIMATIONS_85 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_85.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_85.bin" glabel ASSET_OBJECT_ANIMATIONS_86 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_86.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_86.bin" glabel ASSET_OBJECT_ANIMATIONS_87 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_87.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_87.bin" glabel ASSET_OBJECT_ANIMATIONS_88 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_88.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_88.bin" glabel ASSET_OBJECT_ANIMATIONS_89 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_89.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_89.bin" glabel ASSET_OBJECT_ANIMATIONS_90 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_90.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_90.bin" glabel ASSET_OBJECT_ANIMATIONS_91 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_91.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_91.bin" glabel ASSET_OBJECT_ANIMATIONS_92 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_92.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_92.bin" glabel ASSET_OBJECT_ANIMATIONS_93 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_93.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_93.bin" glabel ASSET_OBJECT_ANIMATIONS_94 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_94.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_94.bin" glabel ASSET_OBJECT_ANIMATIONS_95 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_95.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_95.bin" glabel ASSET_OBJECT_ANIMATIONS_96 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_96.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_96.bin" glabel ASSET_OBJECT_ANIMATIONS_97 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_97.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_97.bin" glabel ASSET_OBJECT_ANIMATIONS_98 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_98.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_98.bin" glabel ASSET_OBJECT_ANIMATIONS_99 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_99.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_99.bin" glabel ASSET_OBJECT_ANIMATIONS_100 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_100.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_100.bin" glabel ASSET_OBJECT_ANIMATIONS_101 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_101.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_101.bin" glabel ASSET_OBJECT_ANIMATIONS_102 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_102.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_102.bin" glabel ASSET_OBJECT_ANIMATIONS_103 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_103.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_103.bin" glabel ASSET_OBJECT_ANIMATIONS_104 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_104.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_104.bin" glabel ASSET_OBJECT_ANIMATIONS_105 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_105.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_105.bin" glabel ASSET_OBJECT_ANIMATIONS_106 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_106.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_106.bin" glabel ASSET_OBJECT_ANIMATIONS_107 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_107.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_107.bin" glabel ASSET_OBJECT_ANIMATIONS_108 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_108.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_108.bin" glabel ASSET_OBJECT_ANIMATIONS_109 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_109.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_109.bin" glabel ASSET_OBJECT_ANIMATIONS_110 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_110.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_110.bin" glabel ASSET_OBJECT_ANIMATIONS_111 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_111.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_111.bin" glabel ASSET_OBJECT_ANIMATIONS_112 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_112.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_112.bin" glabel ASSET_OBJECT_ANIMATIONS_113 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_113.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_113.bin" glabel ASSET_OBJECT_ANIMATIONS_114 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_114.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_114.bin" glabel ASSET_OBJECT_ANIMATIONS_115 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_115.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_115.bin" glabel ASSET_OBJECT_ANIMATIONS_116 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_116.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_116.bin" glabel ASSET_OBJECT_ANIMATIONS_117 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_117.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_117.bin" glabel ASSET_OBJECT_ANIMATIONS_118 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_118.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_118.bin" glabel ASSET_OBJECT_ANIMATIONS_119 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_119.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_119.bin" glabel ASSET_OBJECT_ANIMATIONS_120 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_120.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_120.bin" glabel ASSET_OBJECT_ANIMATIONS_121 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_121.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_121.bin" glabel ASSET_OBJECT_ANIMATIONS_122 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_122.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_122.bin" glabel ASSET_OBJECT_ANIMATIONS_123 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_123.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_123.bin" glabel ASSET_OBJECT_ANIMATIONS_124 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_124.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_124.bin" glabel ASSET_OBJECT_ANIMATIONS_125 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_125.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_125.bin" glabel ASSET_OBJECT_ANIMATIONS_126 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_126.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_126.bin" glabel ASSET_OBJECT_ANIMATIONS_127 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_127.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_127.bin" glabel ASSET_OBJECT_ANIMATIONS_128 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_128.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_128.bin" glabel ASSET_OBJECT_ANIMATIONS_129 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_129.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_129.bin" glabel ASSET_OBJECT_ANIMATIONS_130 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_130.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_130.bin" glabel ASSET_OBJECT_ANIMATIONS_131 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_131.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_131.bin" glabel ASSET_OBJECT_ANIMATIONS_132 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_132.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_132.bin" glabel ASSET_OBJECT_ANIMATIONS_133 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_133.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_133.bin" glabel ASSET_OBJECT_ANIMATIONS_134 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_134.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_134.bin" glabel ASSET_OBJECT_ANIMATIONS_135 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_135.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_135.bin" glabel ASSET_OBJECT_ANIMATIONS_136 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_136.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_136.bin" glabel ASSET_OBJECT_ANIMATIONS_137 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_137.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_137.bin" glabel ASSET_OBJECT_ANIMATIONS_138 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_138.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_138.bin" glabel ASSET_OBJECT_ANIMATIONS_139 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_139.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_139.bin" glabel ASSET_OBJECT_ANIMATIONS_140 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_140.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_140.bin" glabel ASSET_OBJECT_ANIMATIONS_141 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_141.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_141.bin" glabel ASSET_OBJECT_ANIMATIONS_142 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_142.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_142.bin" glabel ASSET_OBJECT_ANIMATIONS_143 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_143.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_143.bin" glabel ASSET_OBJECT_ANIMATIONS_144 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_144.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_144.bin" glabel ASSET_OBJECT_ANIMATIONS_145 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_145.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_145.bin" glabel ASSET_OBJECT_ANIMATIONS_146 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_146.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_146.bin" glabel ASSET_OBJECT_ANIMATIONS_147 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_147.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_147.bin" glabel ASSET_OBJECT_ANIMATIONS_148 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_148.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_148.bin" glabel ASSET_OBJECT_ANIMATIONS_149 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_149.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_149.bin" glabel ASSET_OBJECT_ANIMATIONS_150 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_150.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_150.bin" glabel ASSET_OBJECT_ANIMATIONS_151 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_151.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_151.bin" glabel ASSET_OBJECT_ANIMATIONS_152 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_152.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_152.bin" glabel ASSET_OBJECT_ANIMATIONS_153 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_153.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_153.bin" glabel ASSET_OBJECT_ANIMATIONS_154 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_154.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_154.bin" glabel ASSET_OBJECT_ANIMATIONS_155 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_155.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_155.bin" glabel ASSET_OBJECT_ANIMATIONS_156 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_156.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_156.bin" glabel ASSET_OBJECT_ANIMATIONS_157 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_157.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_157.bin" glabel ASSET_OBJECT_ANIMATIONS_158 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_158.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_158.bin" glabel ASSET_OBJECT_ANIMATIONS_159 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_159.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_159.bin" glabel ASSET_OBJECT_ANIMATIONS_160 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_160.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_160.bin" glabel ASSET_OBJECT_ANIMATIONS_161 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_161.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_161.bin" glabel ASSET_OBJECT_ANIMATIONS_162 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_162.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_162.bin" glabel ASSET_OBJECT_ANIMATIONS_163 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_163.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_163.bin" glabel ASSET_OBJECT_ANIMATIONS_164 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_164.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_164.bin" glabel ASSET_OBJECT_ANIMATIONS_165 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_165.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_165.bin" glabel ASSET_OBJECT_ANIMATIONS_166 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_166.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_166.bin" glabel ASSET_OBJECT_ANIMATIONS_167 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_167.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_167.bin" glabel ASSET_OBJECT_ANIMATIONS_168 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_168.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_168.bin" glabel ASSET_OBJECT_ANIMATIONS_169 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_169.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_169.bin" glabel ASSET_OBJECT_ANIMATIONS_170 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_170.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_170.bin" glabel ASSET_OBJECT_ANIMATIONS_171 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_171.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_171.bin" glabel ASSET_OBJECT_ANIMATIONS_172 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_172.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_172.bin" glabel ASSET_OBJECT_ANIMATIONS_173 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_173.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_173.bin" glabel ASSET_OBJECT_ANIMATIONS_174 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_174.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_174.bin" glabel ASSET_OBJECT_ANIMATIONS_175 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_175.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_175.bin" glabel ASSET_OBJECT_ANIMATIONS_176 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_176.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_176.bin" glabel ASSET_OBJECT_ANIMATIONS_177 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_177.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_177.bin" glabel ASSET_OBJECT_ANIMATIONS_178 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_178.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_178.bin" glabel ASSET_OBJECT_ANIMATIONS_179 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_179.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_179.bin" glabel ASSET_OBJECT_ANIMATIONS_180 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_180.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_180.bin" glabel ASSET_OBJECT_ANIMATIONS_181 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_181.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_181.bin" glabel ASSET_OBJECT_ANIMATIONS_182 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_182.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_182.bin" glabel ASSET_OBJECT_ANIMATIONS_183 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_183.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_183.bin" glabel ASSET_OBJECT_ANIMATIONS_184 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_184.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_184.bin" glabel ASSET_OBJECT_ANIMATIONS_185 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_185.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_185.bin" glabel ASSET_OBJECT_ANIMATIONS_186 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_186.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_186.bin" glabel ASSET_OBJECT_ANIMATIONS_187 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_187.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_187.bin" glabel ASSET_OBJECT_ANIMATIONS_188 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_188.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_188.bin" glabel ASSET_OBJECT_ANIMATIONS_189 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_189.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_189.bin" glabel ASSET_OBJECT_ANIMATIONS_190 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_190.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_190.bin" glabel ASSET_OBJECT_ANIMATIONS_191 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_191.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_191.bin" glabel ASSET_OBJECT_ANIMATIONS_192 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_192.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_192.bin" glabel ASSET_OBJECT_ANIMATIONS_193 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_193.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_193.bin" glabel ASSET_OBJECT_ANIMATIONS_194 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_194.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_194.bin" glabel ASSET_OBJECT_ANIMATIONS_195 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_195.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_195.bin" glabel ASSET_OBJECT_ANIMATIONS_196 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_196.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_196.bin" glabel ASSET_OBJECT_ANIMATIONS_197 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_197.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_197.bin" glabel ASSET_OBJECT_ANIMATIONS_198 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_198.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_198.bin" glabel ASSET_OBJECT_ANIMATIONS_199 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_199.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_199.bin" glabel ASSET_OBJECT_ANIMATIONS_200 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_200.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_200.bin" glabel ASSET_OBJECT_ANIMATIONS_201 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_201.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_201.bin" glabel ASSET_OBJECT_ANIMATIONS_202 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_202.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_202.bin" glabel ASSET_OBJECT_ANIMATIONS_203 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_203.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_203.bin" glabel ASSET_OBJECT_ANIMATIONS_204 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_204.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_204.bin" glabel ASSET_OBJECT_ANIMATIONS_205 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_205.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_205.bin" glabel ASSET_OBJECT_ANIMATIONS_206 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_206.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_206.bin" glabel ASSET_OBJECT_ANIMATIONS_207 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_207.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_207.bin" glabel ASSET_OBJECT_ANIMATIONS_208 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_208.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_208.bin" glabel ASSET_OBJECT_ANIMATIONS_209 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_209.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_209.bin" glabel ASSET_OBJECT_ANIMATIONS_210 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_210.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_210.bin" glabel ASSET_OBJECT_ANIMATIONS_211 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_211.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_211.bin" glabel ASSET_OBJECT_ANIMATIONS_212 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_212.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_212.bin" glabel ASSET_OBJECT_ANIMATIONS_213 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_213.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_213.bin" glabel ASSET_OBJECT_ANIMATIONS_214 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_214.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_214.bin" glabel ASSET_OBJECT_ANIMATIONS_215 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_215.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_215.bin" glabel ASSET_OBJECT_ANIMATIONS_216 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_216.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_216.bin" glabel ASSET_OBJECT_ANIMATIONS_217 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_217.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_217.bin" glabel ASSET_OBJECT_ANIMATIONS_218 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_218.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_218.bin" glabel ASSET_OBJECT_ANIMATIONS_219 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_219.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_219.bin" glabel ASSET_OBJECT_ANIMATIONS_220 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_220.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_220.bin" glabel ASSET_OBJECT_ANIMATIONS_221 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_221.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_221.bin" glabel ASSET_OBJECT_ANIMATIONS_222 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_222.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_222.bin" glabel ASSET_OBJECT_ANIMATIONS_223 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_223.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_223.bin" glabel ASSET_OBJECT_ANIMATIONS_224 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_224.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_224.bin" glabel ASSET_OBJECT_ANIMATIONS_225 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_225.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_225.bin" glabel ASSET_OBJECT_ANIMATIONS_226 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_226.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_226.bin" glabel ASSET_OBJECT_ANIMATIONS_227 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_227.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_227.bin" glabel ASSET_OBJECT_ANIMATIONS_228 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_228.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_228.bin" glabel ASSET_OBJECT_ANIMATIONS_229 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_229.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_229.bin" glabel ASSET_OBJECT_ANIMATIONS_230 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_230.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_230.bin" glabel ASSET_OBJECT_ANIMATIONS_231 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_231.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_231.bin" glabel ASSET_OBJECT_ANIMATIONS_232 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_232.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_232.bin" glabel ASSET_OBJECT_ANIMATIONS_233 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_233.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_233.bin" glabel ASSET_OBJECT_ANIMATIONS_234 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_234.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_234.bin" glabel ASSET_OBJECT_ANIMATIONS_235 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_235.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_235.bin" glabel ASSET_OBJECT_ANIMATIONS_236 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_236.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_236.bin" glabel ASSET_OBJECT_ANIMATIONS_237 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_237.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_237.bin" glabel ASSET_OBJECT_ANIMATIONS_238 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_238.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_238.bin" glabel ASSET_OBJECT_ANIMATIONS_239 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_239.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_239.bin" glabel ASSET_OBJECT_ANIMATIONS_240 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_240.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_240.bin" glabel ASSET_OBJECT_ANIMATIONS_241 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_241.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_241.bin" glabel ASSET_OBJECT_ANIMATIONS_242 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_242.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_242.bin" glabel ASSET_OBJECT_ANIMATIONS_243 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_243.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_243.bin" glabel ASSET_OBJECT_ANIMATIONS_244 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_244.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_244.bin" glabel ASSET_OBJECT_ANIMATIONS_245 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_245.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_245.bin" glabel ASSET_OBJECT_ANIMATIONS_246 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_246.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_246.bin" glabel ASSET_OBJECT_ANIMATIONS_247 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_247.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_247.bin" glabel ASSET_OBJECT_ANIMATIONS_248 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_248.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_248.bin" glabel ASSET_OBJECT_ANIMATIONS_249 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_249.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_249.bin" glabel ASSET_OBJECT_ANIMATIONS_250 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_250.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_250.bin" glabel ASSET_OBJECT_ANIMATIONS_251 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_251.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_251.bin" glabel ASSET_OBJECT_ANIMATIONS_252 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_252.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_252.bin" glabel ASSET_OBJECT_ANIMATIONS_253 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_253.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_253.bin" glabel ASSET_OBJECT_ANIMATIONS_254 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_254.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_254.bin" glabel ASSET_OBJECT_ANIMATIONS_255 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_255.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_255.bin" glabel ASSET_OBJECT_ANIMATIONS_256 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_256.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_256.bin" glabel ASSET_OBJECT_ANIMATIONS_257 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_257.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_257.bin" glabel ASSET_OBJECT_ANIMATIONS_258 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_258.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_258.bin" glabel ASSET_OBJECT_ANIMATIONS_259 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_259.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_259.bin" glabel ASSET_OBJECT_ANIMATIONS_260 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_260.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_260.bin" glabel ASSET_OBJECT_ANIMATIONS_261 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_261.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_261.bin" glabel ASSET_OBJECT_ANIMATIONS_262 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_262.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_262.bin" glabel ASSET_OBJECT_ANIMATIONS_263 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_263.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_263.bin" glabel ASSET_OBJECT_ANIMATIONS_264 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_264.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_264.bin" glabel ASSET_OBJECT_ANIMATIONS_265 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_265.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_265.bin" glabel ASSET_OBJECT_ANIMATIONS_266 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_266.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_266.bin" glabel ASSET_OBJECT_ANIMATIONS_267 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_267.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_267.bin" glabel ASSET_OBJECT_ANIMATIONS_268 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_268.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_268.bin" glabel ASSET_OBJECT_ANIMATIONS_269 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_269.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_269.bin" glabel ASSET_OBJECT_ANIMATIONS_270 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_270.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_270.bin" glabel ASSET_OBJECT_ANIMATIONS_271 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_271.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_271.bin" glabel ASSET_OBJECT_ANIMATIONS_272 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_272.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_272.bin" glabel ASSET_OBJECT_ANIMATIONS_273 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_273.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_273.bin" glabel ASSET_OBJECT_ANIMATIONS_274 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_274.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_274.bin" glabel ASSET_OBJECT_ANIMATIONS_275 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_275.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_275.bin" glabel ASSET_OBJECT_ANIMATIONS_276 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_276.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_276.bin" glabel ASSET_OBJECT_ANIMATIONS_277 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_277.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_277.bin" glabel ASSET_OBJECT_ANIMATIONS_278 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_278.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_278.bin" glabel ASSET_OBJECT_ANIMATIONS_279 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_279.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_279.bin" glabel ASSET_OBJECT_ANIMATIONS_280 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_280.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_280.bin" glabel ASSET_OBJECT_ANIMATIONS_281 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_281.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_281.bin" glabel ASSET_OBJECT_ANIMATIONS_282 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_282.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_282.bin" glabel ASSET_OBJECT_ANIMATIONS_283 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_283.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_283.bin" glabel ASSET_OBJECT_ANIMATIONS_284 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_284.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_284.bin" glabel ASSET_OBJECT_ANIMATIONS_285 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_285.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_285.bin" glabel ASSET_OBJECT_ANIMATIONS_286 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_286.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_286.bin" glabel ASSET_OBJECT_ANIMATIONS_287 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_287.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_287.bin" glabel ASSET_OBJECT_ANIMATIONS_288 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_288.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_288.bin" glabel ASSET_OBJECT_ANIMATIONS_289 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_289.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_289.bin" glabel ASSET_OBJECT_ANIMATIONS_290 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_290.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_290.bin" glabel ASSET_OBJECT_ANIMATIONS_291 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_291.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_291.bin" glabel ASSET_OBJECT_ANIMATIONS_292 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_292.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_292.bin" glabel ASSET_OBJECT_ANIMATIONS_293 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_293.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_293.bin" glabel ASSET_OBJECT_ANIMATIONS_294 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_294.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_294.bin" glabel ASSET_OBJECT_ANIMATIONS_295 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_295.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_295.bin" glabel ASSET_OBJECT_ANIMATIONS_296 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_296.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_296.bin" glabel ASSET_OBJECT_ANIMATIONS_297 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_297.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_297.bin" glabel ASSET_OBJECT_ANIMATIONS_298 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_298.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_298.bin" glabel ASSET_OBJECT_ANIMATIONS_299 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_299.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_299.bin" glabel ASSET_OBJECT_ANIMATIONS_300 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_300.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_300.bin" glabel ASSET_OBJECT_ANIMATIONS_301 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_301.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_301.bin" glabel ASSET_OBJECT_ANIMATIONS_302 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_302.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_302.bin" glabel ASSET_OBJECT_ANIMATIONS_303 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_303.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_303.bin" glabel ASSET_OBJECT_ANIMATIONS_304 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_304.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_304.bin" glabel ASSET_OBJECT_ANIMATIONS_305 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_305.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_305.bin" glabel ASSET_OBJECT_ANIMATIONS_306 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_306.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_306.bin" glabel ASSET_OBJECT_ANIMATIONS_307 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_307.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_307.bin" glabel ASSET_OBJECT_ANIMATIONS_308 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_308.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_308.bin" glabel ASSET_OBJECT_ANIMATIONS_309 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_309.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_309.bin" glabel ASSET_OBJECT_ANIMATIONS_310 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_310.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_310.bin" glabel ASSET_OBJECT_ANIMATIONS_311 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_311.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_311.bin" glabel ASSET_OBJECT_ANIMATIONS_312 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_312.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_312.bin" glabel ASSET_OBJECT_ANIMATIONS_313 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_313.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_313.bin" glabel ASSET_OBJECT_ANIMATIONS_314 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_314.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_314.bin" glabel ASSET_OBJECT_ANIMATIONS_315 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_315.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_315.bin" glabel ASSET_OBJECT_ANIMATIONS_316 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_316.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_316.bin" glabel ASSET_OBJECT_ANIMATIONS_317 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_317.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_317.bin" glabel ASSET_OBJECT_ANIMATIONS_318 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_318.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_318.bin" glabel ASSET_OBJECT_ANIMATIONS_319 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_319.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_319.bin" glabel ASSET_OBJECT_ANIMATIONS_320 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_320.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_320.bin" glabel ASSET_OBJECT_ANIMATIONS_321 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_321.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_321.bin" glabel ASSET_OBJECT_ANIMATIONS_322 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_322.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_322.bin" glabel ASSET_OBJECT_ANIMATIONS_323 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_323.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_323.bin" glabel ASSET_OBJECT_ANIMATIONS_324 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_324.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_324.bin" glabel ASSET_OBJECT_ANIMATIONS_325 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_325.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_325.bin" glabel ASSET_OBJECT_ANIMATIONS_326 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_326.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_326.bin" glabel ASSET_OBJECT_ANIMATIONS_327 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_327.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_327.bin" glabel ASSET_OBJECT_ANIMATIONS_328 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_328.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_328.bin" glabel ASSET_OBJECT_ANIMATIONS_329 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_329.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_329.bin" glabel ASSET_OBJECT_ANIMATIONS_330 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_330.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_330.bin" glabel ASSET_OBJECT_ANIMATIONS_331 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_331.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_331.bin" glabel ASSET_OBJECT_ANIMATIONS_332 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_332.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_332.bin" glabel ASSET_OBJECT_ANIMATIONS_333 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_333.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_333.bin" glabel ASSET_OBJECT_ANIMATIONS_334 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_334.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_334.bin" glabel ASSET_OBJECT_ANIMATIONS_335 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_335.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_335.bin" glabel ASSET_OBJECT_ANIMATIONS_336 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_336.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_336.bin" glabel ASSET_OBJECT_ANIMATIONS_337 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_337.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_337.bin" glabel ASSET_OBJECT_ANIMATIONS_338 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_338.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_338.bin" glabel ASSET_OBJECT_ANIMATIONS_339 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_339.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_339.bin" glabel ASSET_OBJECT_ANIMATIONS_340 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_340.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_340.bin" glabel ASSET_OBJECT_ANIMATIONS_341 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_341.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_341.bin" glabel ASSET_OBJECT_ANIMATIONS_342 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_342.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_342.bin" glabel ASSET_OBJECT_ANIMATIONS_343 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_343.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_343.bin" glabel ASSET_OBJECT_ANIMATIONS_344 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_344.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_344.bin" glabel ASSET_OBJECT_ANIMATIONS_345 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_345.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_345.bin" glabel ASSET_OBJECT_ANIMATIONS_346 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_346.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_346.bin" glabel ASSET_OBJECT_ANIMATIONS_347 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_347.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_347.bin" glabel ASSET_OBJECT_ANIMATIONS_348 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_348.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_348.bin" glabel ASSET_OBJECT_ANIMATIONS_349 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_349.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_349.bin" glabel ASSET_OBJECT_ANIMATIONS_350 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_350.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_350.bin" glabel ASSET_OBJECT_ANIMATIONS_351 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_351.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_351.bin" glabel ASSET_OBJECT_ANIMATIONS_352 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_352.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_352.bin" glabel ASSET_OBJECT_ANIMATIONS_353 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_353.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_353.bin" glabel ASSET_OBJECT_ANIMATIONS_354 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_354.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_354.bin" glabel ASSET_OBJECT_ANIMATIONS_355 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_355.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_355.bin" glabel ASSET_OBJECT_ANIMATIONS_356 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_356.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_356.bin" glabel ASSET_OBJECT_ANIMATIONS_357 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_357.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_357.bin" glabel ASSET_OBJECT_ANIMATIONS_358 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_358.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_358.bin" glabel ASSET_OBJECT_ANIMATIONS_359 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_359.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_359.bin" glabel ASSET_OBJECT_ANIMATIONS_360 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_360.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_360.bin" glabel ASSET_OBJECT_ANIMATIONS_361 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_361.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_361.bin" glabel ASSET_OBJECT_ANIMATIONS_362 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_362.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_362.bin" glabel ASSET_OBJECT_ANIMATIONS_363 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_363.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_363.bin" glabel ASSET_OBJECT_ANIMATIONS_364 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_364.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_364.bin" glabel ASSET_OBJECT_ANIMATIONS_365 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_365.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_365.bin" glabel ASSET_OBJECT_ANIMATIONS_366 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_366.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_366.bin" glabel ASSET_OBJECT_ANIMATIONS_367 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_367.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_367.bin" glabel ASSET_OBJECT_ANIMATIONS_368 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_368.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_368.bin" glabel ASSET_OBJECT_ANIMATIONS_369 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_369.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_369.bin" glabel ASSET_OBJECT_ANIMATIONS_370 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_370.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_370.bin" glabel ASSET_OBJECT_ANIMATIONS_371 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_371.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_371.bin" glabel ASSET_OBJECT_ANIMATIONS_372 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_372.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_372.bin" glabel ASSET_OBJECT_ANIMATIONS_373 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_373.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_373.bin" glabel ASSET_OBJECT_ANIMATIONS_374 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_374.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_374.bin" glabel ASSET_OBJECT_ANIMATIONS_375 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_375.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_375.bin" glabel ASSET_OBJECT_ANIMATIONS_376 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_376.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_376.bin" glabel ASSET_OBJECT_ANIMATIONS_377 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_377.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_377.bin" glabel ASSET_OBJECT_ANIMATIONS_378 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_378.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_378.bin" glabel ASSET_OBJECT_ANIMATIONS_379 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_379.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_379.bin" glabel ASSET_OBJECT_ANIMATIONS_380 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_380.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_380.bin" glabel ASSET_OBJECT_ANIMATIONS_381 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_381.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_381.bin" glabel ASSET_OBJECT_ANIMATIONS_382 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_382.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_382.bin" glabel ASSET_OBJECT_ANIMATIONS_383 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_383.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_383.bin" glabel ASSET_OBJECT_ANIMATIONS_384 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_384.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_384.bin" glabel ASSET_OBJECT_ANIMATIONS_385 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_385.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_385.bin" glabel ASSET_OBJECT_ANIMATIONS_386 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_386.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_386.bin" glabel ASSET_OBJECT_ANIMATIONS_387 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_387.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_387.bin" glabel ASSET_OBJECT_ANIMATIONS_388 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_388.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_388.bin" glabel ASSET_OBJECT_ANIMATIONS_389 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_389.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_389.bin" glabel ASSET_OBJECT_ANIMATIONS_390 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_390.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_390.bin" glabel ASSET_OBJECT_ANIMATIONS_391 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_391.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_391.bin" glabel ASSET_OBJECT_ANIMATIONS_392 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_392.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_392.bin" glabel ASSET_OBJECT_ANIMATIONS_393 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_393.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_393.bin" glabel ASSET_OBJECT_ANIMATIONS_394 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_394.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_394.bin" glabel ASSET_OBJECT_ANIMATIONS_395 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_395.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_395.bin" glabel ASSET_OBJECT_ANIMATIONS_396 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_396.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_396.bin" glabel ASSET_OBJECT_ANIMATIONS_397 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_397.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_397.bin" glabel ASSET_OBJECT_ANIMATIONS_398 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_398.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_398.bin" glabel ASSET_OBJECT_ANIMATIONS_399 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_399.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_399.bin" glabel ASSET_OBJECT_ANIMATIONS_400 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_400.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_400.bin" glabel ASSET_OBJECT_ANIMATIONS_401 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_401.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_401.bin" glabel ASSET_OBJECT_ANIMATIONS_402 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_402.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_402.bin" glabel ASSET_OBJECT_ANIMATIONS_403 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_403.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_403.bin" glabel ASSET_OBJECT_ANIMATIONS_404 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_404.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_404.bin" glabel ASSET_OBJECT_ANIMATIONS_405 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_405.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_405.bin" glabel ASSET_OBJECT_ANIMATIONS_406 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_406.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_406.bin" glabel ASSET_OBJECT_ANIMATIONS_407 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_407.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_407.bin" glabel ASSET_OBJECT_ANIMATIONS_408 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_408.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_408.bin" glabel ASSET_OBJECT_ANIMATIONS_409 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_409.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_409.bin" glabel ASSET_OBJECT_ANIMATIONS_410 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_410.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_410.bin" glabel ASSET_OBJECT_ANIMATIONS_411 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_411.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_411.bin" glabel ASSET_OBJECT_ANIMATIONS_412 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_412.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_412.bin" glabel ASSET_OBJECT_ANIMATIONS_413 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_413.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_413.bin" glabel ASSET_OBJECT_ANIMATIONS_414 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_414.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_414.bin" glabel ASSET_OBJECT_ANIMATIONS_415 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_415.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_415.bin" glabel ASSET_OBJECT_ANIMATIONS_416 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_416.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_416.bin" glabel ASSET_OBJECT_ANIMATIONS_417 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_417.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_417.bin" glabel ASSET_OBJECT_ANIMATIONS_418 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_418.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_418.bin" glabel ASSET_OBJECT_ANIMATIONS_419 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_419.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_419.bin" glabel ASSET_OBJECT_ANIMATIONS_420 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_420.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_420.bin" glabel ASSET_OBJECT_ANIMATIONS_421 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_421.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_421.bin" glabel ASSET_OBJECT_ANIMATIONS_422 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_422.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_422.bin" glabel ASSET_OBJECT_ANIMATIONS_423 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_423.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_423.bin" glabel ASSET_OBJECT_ANIMATIONS_424 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_424.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_424.bin" glabel ASSET_OBJECT_ANIMATIONS_425 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_425.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_425.bin" glabel ASSET_OBJECT_ANIMATIONS_426 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_426.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_426.bin" glabel ASSET_OBJECT_ANIMATIONS_427 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_427.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_427.bin" glabel ASSET_OBJECT_ANIMATIONS_428 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_428.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_428.bin" glabel ASSET_OBJECT_ANIMATIONS_429 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_429.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_429.bin" glabel ASSET_OBJECT_ANIMATIONS_430 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_430.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_430.bin" glabel ASSET_OBJECT_ANIMATIONS_431 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_431.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_431.bin" glabel ASSET_OBJECT_ANIMATIONS_432 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_432.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_432.bin" glabel ASSET_OBJECT_ANIMATIONS_433 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_433.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_433.bin" glabel ASSET_OBJECT_ANIMATIONS_434 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_434.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_434.bin" glabel ASSET_OBJECT_ANIMATIONS_435 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_435.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_435.bin" glabel ASSET_OBJECT_ANIMATIONS_436 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_436.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_436.bin" glabel ASSET_OBJECT_ANIMATIONS_437 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_437.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_437.bin" glabel ASSET_OBJECT_ANIMATIONS_438 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_438.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_438.bin" glabel ASSET_OBJECT_ANIMATIONS_439 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_439.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_439.bin" glabel ASSET_OBJECT_ANIMATIONS_440 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_440.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_440.bin" glabel ASSET_OBJECT_ANIMATIONS_441 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_441.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_441.bin" glabel ASSET_OBJECT_ANIMATIONS_442 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_442.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_442.bin" glabel ASSET_OBJECT_ANIMATIONS_443 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_443.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_443.bin" glabel ASSET_OBJECT_ANIMATIONS_444 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_444.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_444.bin" glabel ASSET_OBJECT_ANIMATIONS_445 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_445.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_445.bin" glabel ASSET_OBJECT_ANIMATIONS_446 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_446.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_446.bin" glabel ASSET_OBJECT_ANIMATIONS_447 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_447.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_447.bin" glabel ASSET_OBJECT_ANIMATIONS_448 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_448.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_448.bin" glabel ASSET_OBJECT_ANIMATIONS_449 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_449.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_449.bin" glabel ASSET_OBJECT_ANIMATIONS_450 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_450.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_450.bin" glabel ASSET_OBJECT_ANIMATIONS_451 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_451.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_451.bin" glabel ASSET_OBJECT_ANIMATIONS_452 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_452.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_452.bin" glabel ASSET_OBJECT_ANIMATIONS_453 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_453.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_453.bin" glabel ASSET_OBJECT_ANIMATIONS_454 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_454.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_454.bin" glabel ASSET_OBJECT_ANIMATIONS_455 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_455.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_455.bin" glabel ASSET_OBJECT_ANIMATIONS_456 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_456.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_456.bin" glabel ASSET_OBJECT_ANIMATIONS_457 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_457.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_457.bin" glabel ASSET_OBJECT_ANIMATIONS_458 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_458.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_458.bin" glabel ASSET_OBJECT_ANIMATIONS_459 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_459.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_459.bin" glabel ASSET_OBJECT_ANIMATIONS_460 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_460.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_460.bin" glabel ASSET_OBJECT_ANIMATIONS_461 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_461.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_461.bin" glabel ASSET_OBJECT_ANIMATIONS_462 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_462.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_462.bin" glabel ASSET_OBJECT_ANIMATIONS_463 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_463.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_463.bin" glabel ASSET_OBJECT_ANIMATIONS_464 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_464.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_464.bin" glabel ASSET_OBJECT_ANIMATIONS_465 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_465.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_465.bin" glabel ASSET_OBJECT_ANIMATIONS_466 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_466.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_466.bin" glabel ASSET_OBJECT_ANIMATIONS_467 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_467.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_467.bin" glabel ASSET_OBJECT_ANIMATIONS_468 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_468.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_468.bin" glabel ASSET_OBJECT_ANIMATIONS_469 -.incbin "./build/us_1.0/assets/objects/animations/unknown_32_469.bin" +.incbin "./build/us_1.0/assets/objects/animations/asset_object_animations_469.bin" glabel ASSET_OBJECT_ANIMATIONS_END /********** ASSET_OBJECT_HEADERS_TABLE **********/ .balign 16 glabel ASSET_OBJECT_HEADERS_TABLE -.word ASSET_OBJHEADER_DIDDYCAR - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_SWCAR - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_KREMCAR - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_BADGERCAR - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_TORTCAR - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_CONKACAR - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_TIGERCAR - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_BANJOCAR - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_CHICKENCAR - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_MOUSECAR - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_DIDDYHOVER - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_TICKTOCKHOVER - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_KREMLINHOVER - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_BADGERHOVER - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_TORTHOVER - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_CONKAHOVER - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_TIGERHOVER - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_BANJOHOVER - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_CHICKENHOVER - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_MOUSEHOVER - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_DIDDYPLANE - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_TICKTOCKPLANE - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_KREMPLANE - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_BADGERPLANE - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_TORTPLANE - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_CONKA - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_TIGPLANE - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_BANJOPLANE - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_CHICKENPLANE - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_MOUSEPLANE - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_FLYINGCARPET - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_TIMBERDANCER - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_CHICKENCHARACTE - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_PIPSYDANCER - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_BANJODANCER - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_TICKTOCKDANCER - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_WIZPIGSHIP - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_CONKADANCER - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_EMPTYHOVER - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_STOPWATCHMAN - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_STOPWATCHSELECT - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_PARKWARDEN - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_SMARTIETREE - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_BLUEBERRYBUSH - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_RUBBERSNOWTREE - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_SKINNYSNOWTREE - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_XMASTREE - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_ALPINESNOWTREE - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_RUBBERTREE - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_BEACHTREE - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_PALMTREETOP - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_PALMPLANT - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_PALMTREETOPCHEA - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_FIRTREE - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_SPACETREE - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_LAMPPOST - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_FLOWERS - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_REEDS - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_SMOKE - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_DINOSAUR1 - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_DINOSAUR2 - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_DINOSAUR3 - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_WHALE - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_SNOWMEN - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_SIGNS - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_FLAMINGTORCH - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_MIST - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_SNOWBALL - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_BUOY - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_PIRATESHIP - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_LOG - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_PIGLOG - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_BOULDER - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_AIRZIPPERS - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_WATERZIPPERS - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_LEVELDOOR - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_KEITHPIGDOOR - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_CHALDOOR - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_BOSSDOOR - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_BIGBOSSDOOR - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_WORLDGATE - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_TTDOOR - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_RAMPSWITCH - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_NOENTRYDOOR - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_RAMPWHALE - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_SEAMONSTER - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_DINOISLE - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_SKYCONTROL - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_CHECKPOINT - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_CHECKARROW - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_MODECHANGE - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_TRIGGER - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_FOGCHANGER - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_AINODE - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_EXIT - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_BONUS - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_CAMERA_CONTROL - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_SETUPPOINT - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_ANIMATOR - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_TEXSCROLL - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_RGBALIGHT - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_INTROCAM - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_WEATHER - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_LENSFLARE - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_LENSFLARESWITCH - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_INFOPOINT - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_WAVEGENERATOR - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_WAVEPOWER - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_RANGETRIGGER - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_LAVASPURT - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_BOMBEXPLOSION - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_WARDENSMOKE - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_BUBBLER - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_WEAPONBALLOON - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_WBALLOONPOP - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_MISSILEGLOW - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_HOMINGGLOW - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_MISSILE - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_HOMING - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_OILSLICK - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_SMOKECLOUD - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_BOMB - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_BUBBLEWEAPON - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_WORLDKEY - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_COINCREATOR - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_TREASURESUCKER - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_COIN - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_SILVERCOIN - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_GOLDCOIN - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_BONUSGEM - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_COLLECTEGG - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_EGGCREATOR - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_CHARACTERFLAG - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_ANIMATION - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_OVERRIDEPOS - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_ANIMCAMERA - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_ANIMCAR - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_ANIMDOME - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_WIZGHOSTS - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_N64LOGO - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_ASTEROID - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_PILLAR - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_BOULDERANIM - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_PIGHEADCOLOURS - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_PIGFACEANIMATOR - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_PTERODACTYL - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_AMULETPIECE1 - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_AMULETPIECE2 - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_AMULETPIECE3 - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_AMULETPIECE4 - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_SWAMULET1 - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_SWAMULET2 - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_SWAMULET3 - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_SWAMULET4 - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_ANIMKEY - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_SPACESHIP1 - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_MINISHIP - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_MONORAIL - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_SPACESHIP2 - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_SPACESHIP3 - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_LIGHTHOUSE - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_ROCKETSIGNPOST - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_LIGHTHOUSE1 - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_LIGHTHOUSE2 - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_SELECTIONHILL - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_WIDESCREEN - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_TIGERANIMPLANE - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_BADGERANIMWALK - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_TIMBERANIMCAR - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_KREMSELECT - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_CONKSELECT - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_BADGERSELECT - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_TORTSELECT - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_TIGERSELECT - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_DIDDYSELECT - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_BANJOSELECT - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_CHICKSELECT - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_MOUSESELECT - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_MAGICCARPET - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_POLYGOLDBALOON - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_ANIMGENIE - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_ANIMGENIE3 - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_BUTTERFLYBAIT - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_AUDIO - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_AUDIOLINE - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_AUDIOSEQLINE - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_AUDIOSEQ - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_AUDIOREVERB - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_FRONTTYRE - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_BACKTYRE - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_PLANETYRE - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_FAN - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_JETENGINE - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_GLOVE - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_LEEFAN - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_MAGICRING - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_DOME - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_DOME1 - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_DOME2 - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_DOME3 - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_DOME4 - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_DOME5 - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_DOME6 - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_DOME7 - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_DOME8 - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_DOME9 - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_DOME10 - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_DOME11 - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_DOME12 - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_DOME13 - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_DOME14 - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_DOME15 - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_DOME16 - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_DOME17 - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_SELECTIONSHADOW - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_POSTFORPARTY - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_RARELOGO - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_SPARKLYTHING - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_DOOROPENER - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_ANIMDINOSAUR2 - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_TIMERANIMHOVER - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_ANIMBADGERPLANE - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_ANIMDINOSAUR1 - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_ANIMMOUSECAR - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_ANIMTORT - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_CHICKENANIMPLAN - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_EMPTYHOVERANIM - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_KREMANIM - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_MOUSEHOVERANIM - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_TORTRUNNER - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_ANIMBANJOPLANE - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_CONKAANIMCAR - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_GBPARKWARDEN - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_WIZPIG - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_WIZPIGROCKET - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_PIGBOSS - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_PIGBOSS2 - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_PIGROCKETEER - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_PARTICLES2 - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_PIGBOULDER - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_BIGPLANET - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_ROCKETBIT1 - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_ROCKETBIT2 - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_GENIEHEAD - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_PIGBOULDER2 - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_PIGBOULDER3 - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_PIGBOULDER4 - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_PIGBOULDER5 - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_TRICKYTOPS - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_TRICKYANIM - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_TRICKYANIM2 - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_TRICKYANIM3 - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_WALRUS_ANIM - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_TERRYBOSS - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_DRAGONBOSS - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_DRAGONANIM - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_WALRUS - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_SNOWBALLBOSS - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_ANIMOCTO - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_OCTOPUS - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_GOLDBALOONSPRIT - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_SPACECOLUMN1 - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_SPACECOLUMN2 - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_SPACECOLUMN3 - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_HAYSTACK - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_ANIMGENIE2 - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_BRIGHTSTAR - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_BUTTERFLY - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_FISH - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_FROG - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_BOOST - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_MAGNETFX - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_STILLFROG - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_STOPWATCHICON - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_STOPWATCHHAND - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_BRIDGE - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_POSARROW - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_HITTESTER - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_MIDIFADE - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_WINDSAIL - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_EFFECTBOX - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_TROPHYCAB - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_FLYCOIN - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_GOLDENBALLOON - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_LASERBOLT - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_LASERGUN - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_BOLTGLOW - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_GROUNDZIPPER - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_PWSAFETELEPOINT - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_HEADFORPOINT - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_FIREBALLATTRACT - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_FIREBALL - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_OCTOBUBBLE - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_OCTOBOMB - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_GOLDTROPHY - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_PARKTROPHY - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_TICKTROPHY - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_TROPHY - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_TELEPORT - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_SHIELD - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_LIGHTNING - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_MIDIFADEPOINT - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_LEVELNAME - ASSET_OBJECT_HEADERS -.word ASSET_OBJHEADER_MIDICHSET - ASSET_OBJECT_HEADERS -.word ASSET_OBJECT_HEADERS_END - ASSET_OBJECT_HEADERS +.word ASSET_OBJECT_DIDDYCAR - ASSET_OBJECTS +.word ASSET_OBJECT_SWCAR - ASSET_OBJECTS +.word ASSET_OBJECT_KREMCAR - ASSET_OBJECTS +.word ASSET_OBJECT_BADGERCAR - ASSET_OBJECTS +.word ASSET_OBJECT_TORTCAR - ASSET_OBJECTS +.word ASSET_OBJECT_CONKACAR - ASSET_OBJECTS +.word ASSET_OBJECT_TIGERCAR - ASSET_OBJECTS +.word ASSET_OBJECT_BANJOCAR - ASSET_OBJECTS +.word ASSET_OBJECT_CHICKENCAR - ASSET_OBJECTS +.word ASSET_OBJECT_MOUSECAR - ASSET_OBJECTS +.word ASSET_OBJECT_DIDDYHOVER - ASSET_OBJECTS +.word ASSET_OBJECT_TICKTOCKHOVER - ASSET_OBJECTS +.word ASSET_OBJECT_KREMLINHOVER - ASSET_OBJECTS +.word ASSET_OBJECT_BADGERHOVER - ASSET_OBJECTS +.word ASSET_OBJECT_TORTHOVER - ASSET_OBJECTS +.word ASSET_OBJECT_CONKAHOVER - ASSET_OBJECTS +.word ASSET_OBJECT_TIGERHOVER - ASSET_OBJECTS +.word ASSET_OBJECT_BANJOHOVER - ASSET_OBJECTS +.word ASSET_OBJECT_CHICKENHOVER - ASSET_OBJECTS +.word ASSET_OBJECT_MOUSEHOVER - ASSET_OBJECTS +.word ASSET_OBJECT_DIDDYPLANE - ASSET_OBJECTS +.word ASSET_OBJECT_TICKTOCKPLANE - ASSET_OBJECTS +.word ASSET_OBJECT_KREMPLANE - ASSET_OBJECTS +.word ASSET_OBJECT_BADGERPLANE - ASSET_OBJECTS +.word ASSET_OBJECT_TORTPLANE - ASSET_OBJECTS +.word ASSET_OBJECT_CONKA - ASSET_OBJECTS +.word ASSET_OBJECT_TIGPLANE - ASSET_OBJECTS +.word ASSET_OBJECT_BANJOPLANE - ASSET_OBJECTS +.word ASSET_OBJECT_CHICKENPLANE - ASSET_OBJECTS +.word ASSET_OBJECT_MOUSEPLANE - ASSET_OBJECTS +.word ASSET_OBJECT_FLYINGCARPET - ASSET_OBJECTS +.word ASSET_OBJECT_TIMBERDANCER - ASSET_OBJECTS +.word ASSET_OBJECT_CHICKENCHARACTE - ASSET_OBJECTS +.word ASSET_OBJECT_PIPSYDANCER - ASSET_OBJECTS +.word ASSET_OBJECT_BANJODANCER - ASSET_OBJECTS +.word ASSET_OBJECT_TICKTOCKDANCER - ASSET_OBJECTS +.word ASSET_OBJECT_WIZPIGSHIP - ASSET_OBJECTS +.word ASSET_OBJECT_CONKADANCER - ASSET_OBJECTS +.word ASSET_OBJECT_EMPTYHOVER - ASSET_OBJECTS +.word ASSET_OBJECT_STOPWATCHMAN - ASSET_OBJECTS +.word ASSET_OBJECT_STOPWATCHSELECT - ASSET_OBJECTS +.word ASSET_OBJECT_PARKWARDEN - ASSET_OBJECTS +.word ASSET_OBJECT_SMARTIETREE - ASSET_OBJECTS +.word ASSET_OBJECT_BLUEBERRYBUSH - ASSET_OBJECTS +.word ASSET_OBJECT_RUBBERSNOWTREE - ASSET_OBJECTS +.word ASSET_OBJECT_SKINNYSNOWTREE - ASSET_OBJECTS +.word ASSET_OBJECT_XMASTREE - ASSET_OBJECTS +.word ASSET_OBJECT_ALPINESNOWTREE - ASSET_OBJECTS +.word ASSET_OBJECT_RUBBERTREE - ASSET_OBJECTS +.word ASSET_OBJECT_BEACHTREE - ASSET_OBJECTS +.word ASSET_OBJECT_PALMTREETOP - ASSET_OBJECTS +.word ASSET_OBJECT_PALMPLANT - ASSET_OBJECTS +.word ASSET_OBJECT_PALMTREETOPCHEA - ASSET_OBJECTS +.word ASSET_OBJECT_FIRTREE - ASSET_OBJECTS +.word ASSET_OBJECT_SPACETREE - ASSET_OBJECTS +.word ASSET_OBJECT_LAMPPOST - ASSET_OBJECTS +.word ASSET_OBJECT_FLOWERS - ASSET_OBJECTS +.word ASSET_OBJECT_REEDS - ASSET_OBJECTS +.word ASSET_OBJECT_SMOKE - ASSET_OBJECTS +.word ASSET_OBJECT_DINOSAUR1 - ASSET_OBJECTS +.word ASSET_OBJECT_DINOSAUR2 - ASSET_OBJECTS +.word ASSET_OBJECT_DINOSAUR3 - ASSET_OBJECTS +.word ASSET_OBJECT_WHALE - ASSET_OBJECTS +.word ASSET_OBJECT_SNOWMEN - ASSET_OBJECTS +.word ASSET_OBJECT_SIGNS - ASSET_OBJECTS +.word ASSET_OBJECT_FLAMINGTORCH - ASSET_OBJECTS +.word ASSET_OBJECT_MIST - ASSET_OBJECTS +.word ASSET_OBJECT_SNOWBALL - ASSET_OBJECTS +.word ASSET_OBJECT_BUOY - ASSET_OBJECTS +.word ASSET_OBJECT_PIRATESHIP - ASSET_OBJECTS +.word ASSET_OBJECT_LOG - ASSET_OBJECTS +.word ASSET_OBJECT_PIGLOG - ASSET_OBJECTS +.word ASSET_OBJECT_BOULDER - ASSET_OBJECTS +.word ASSET_OBJECT_AIRZIPPERS - ASSET_OBJECTS +.word ASSET_OBJECT_WATERZIPPERS - ASSET_OBJECTS +.word ASSET_OBJECT_LEVELDOOR - ASSET_OBJECTS +.word ASSET_OBJECT_KEITHPIGDOOR - ASSET_OBJECTS +.word ASSET_OBJECT_CHALDOOR - ASSET_OBJECTS +.word ASSET_OBJECT_BOSSDOOR - ASSET_OBJECTS +.word ASSET_OBJECT_BIGBOSSDOOR - ASSET_OBJECTS +.word ASSET_OBJECT_WORLDGATE - ASSET_OBJECTS +.word ASSET_OBJECT_TTDOOR - ASSET_OBJECTS +.word ASSET_OBJECT_RAMPSWITCH - ASSET_OBJECTS +.word ASSET_OBJECT_NOENTRYDOOR - ASSET_OBJECTS +.word ASSET_OBJECT_RAMPWHALE - ASSET_OBJECTS +.word ASSET_OBJECT_SEAMONSTER - ASSET_OBJECTS +.word ASSET_OBJECT_DINOISLE - ASSET_OBJECTS +.word ASSET_OBJECT_SKYCONTROL - ASSET_OBJECTS +.word ASSET_OBJECT_CHECKPOINT - ASSET_OBJECTS +.word ASSET_OBJECT_CHECKARROW - ASSET_OBJECTS +.word ASSET_OBJECT_MODECHANGE - ASSET_OBJECTS +.word ASSET_OBJECT_TRIGGER - ASSET_OBJECTS +.word ASSET_OBJECT_FOGCHANGER - ASSET_OBJECTS +.word ASSET_OBJECT_AINODE - ASSET_OBJECTS +.word ASSET_OBJECT_EXIT - ASSET_OBJECTS +.word ASSET_OBJECT_BONUS - ASSET_OBJECTS +.word ASSET_OBJECT_CAMERA_CONTROL - ASSET_OBJECTS +.word ASSET_OBJECT_SETUPPOINT - ASSET_OBJECTS +.word ASSET_OBJECT_ANIMATOR - ASSET_OBJECTS +.word ASSET_OBJECT_TEXSCROLL - ASSET_OBJECTS +.word ASSET_OBJECT_RGBALIGHT - ASSET_OBJECTS +.word ASSET_OBJECT_INTROCAM - ASSET_OBJECTS +.word ASSET_OBJECT_WEATHER - ASSET_OBJECTS +.word ASSET_OBJECT_LENSFLARE - ASSET_OBJECTS +.word ASSET_OBJECT_LENSFLARESWITCH - ASSET_OBJECTS +.word ASSET_OBJECT_INFOPOINT - ASSET_OBJECTS +.word ASSET_OBJECT_WAVEGENERATOR - ASSET_OBJECTS +.word ASSET_OBJECT_WAVEPOWER - ASSET_OBJECTS +.word ASSET_OBJECT_RANGETRIGGER - ASSET_OBJECTS +.word ASSET_OBJECT_LAVASPURT - ASSET_OBJECTS +.word ASSET_OBJECT_BOMBEXPLOSION - ASSET_OBJECTS +.word ASSET_OBJECT_WARDENSMOKE - ASSET_OBJECTS +.word ASSET_OBJECT_BUBBLER - ASSET_OBJECTS +.word ASSET_OBJECT_WEAPONBALLOON - ASSET_OBJECTS +.word ASSET_OBJECT_WBALLOONPOP - ASSET_OBJECTS +.word ASSET_OBJECT_MISSILEGLOW - ASSET_OBJECTS +.word ASSET_OBJECT_HOMINGGLOW - ASSET_OBJECTS +.word ASSET_OBJECT_MISSILE - ASSET_OBJECTS +.word ASSET_OBJECT_HOMING - ASSET_OBJECTS +.word ASSET_OBJECT_OILSLICK - ASSET_OBJECTS +.word ASSET_OBJECT_SMOKECLOUD - ASSET_OBJECTS +.word ASSET_OBJECT_BOMB - ASSET_OBJECTS +.word ASSET_OBJECT_BUBBLEWEAPON - ASSET_OBJECTS +.word ASSET_OBJECT_WORLDKEY - ASSET_OBJECTS +.word ASSET_OBJECT_COINCREATOR - ASSET_OBJECTS +.word ASSET_OBJECT_TREASURESUCKER - ASSET_OBJECTS +.word ASSET_OBJECT_COIN - ASSET_OBJECTS +.word ASSET_OBJECT_SILVERCOIN - ASSET_OBJECTS +.word ASSET_OBJECT_GOLDCOIN - ASSET_OBJECTS +.word ASSET_OBJECT_BONUSGEM - ASSET_OBJECTS +.word ASSET_OBJECT_COLLECTEGG - ASSET_OBJECTS +.word ASSET_OBJECT_EGGCREATOR - ASSET_OBJECTS +.word ASSET_OBJECT_CHARACTERFLAG - ASSET_OBJECTS +.word ASSET_OBJECT_ANIMATION - ASSET_OBJECTS +.word ASSET_OBJECT_OVERRIDEPOS - ASSET_OBJECTS +.word ASSET_OBJECT_ANIMCAMERA - ASSET_OBJECTS +.word ASSET_OBJECT_ANIMCAR - ASSET_OBJECTS +.word ASSET_OBJECT_ANIMDOME - ASSET_OBJECTS +.word ASSET_OBJECT_WIZGHOSTS - ASSET_OBJECTS +.word ASSET_OBJECT_N64LOGO - ASSET_OBJECTS +.word ASSET_OBJECT_ASTEROID - ASSET_OBJECTS +.word ASSET_OBJECT_PILLAR - ASSET_OBJECTS +.word ASSET_OBJECT_BOULDERANIM - ASSET_OBJECTS +.word ASSET_OBJECT_PIGHEADCOLOURS - ASSET_OBJECTS +.word ASSET_OBJECT_PIGFACEANIMATOR - ASSET_OBJECTS +.word ASSET_OBJECT_PTERODACTYL - ASSET_OBJECTS +.word ASSET_OBJECT_AMULETPIECE1 - ASSET_OBJECTS +.word ASSET_OBJECT_AMULETPIECE2 - ASSET_OBJECTS +.word ASSET_OBJECT_AMULETPIECE3 - ASSET_OBJECTS +.word ASSET_OBJECT_AMULETPIECE4 - ASSET_OBJECTS +.word ASSET_OBJECT_SWAMULET1 - ASSET_OBJECTS +.word ASSET_OBJECT_SWAMULET2 - ASSET_OBJECTS +.word ASSET_OBJECT_SWAMULET3 - ASSET_OBJECTS +.word ASSET_OBJECT_SWAMULET4 - ASSET_OBJECTS +.word ASSET_OBJECT_ANIMKEY - ASSET_OBJECTS +.word ASSET_OBJECT_SPACESHIP1 - ASSET_OBJECTS +.word ASSET_OBJECT_MINISHIP - ASSET_OBJECTS +.word ASSET_OBJECT_MONORAIL - ASSET_OBJECTS +.word ASSET_OBJECT_SPACESHIP2 - ASSET_OBJECTS +.word ASSET_OBJECT_SPACESHIP3 - ASSET_OBJECTS +.word ASSET_OBJECT_LIGHTHOUSE - ASSET_OBJECTS +.word ASSET_OBJECT_ROCKETSIGNPOST - ASSET_OBJECTS +.word ASSET_OBJECT_LIGHTHOUSE1 - ASSET_OBJECTS +.word ASSET_OBJECT_LIGHTHOUSE2 - ASSET_OBJECTS +.word ASSET_OBJECT_SELECTIONHILL - ASSET_OBJECTS +.word ASSET_OBJECT_WIDESCREEN - ASSET_OBJECTS +.word ASSET_OBJECT_TIGERANIMPLANE - ASSET_OBJECTS +.word ASSET_OBJECT_BADGERANIMWALK - ASSET_OBJECTS +.word ASSET_OBJECT_TIMBERANIMCAR - ASSET_OBJECTS +.word ASSET_OBJECT_KREMSELECT - ASSET_OBJECTS +.word ASSET_OBJECT_CONKSELECT - ASSET_OBJECTS +.word ASSET_OBJECT_BADGERSELECT - ASSET_OBJECTS +.word ASSET_OBJECT_TORTSELECT - ASSET_OBJECTS +.word ASSET_OBJECT_TIGERSELECT - ASSET_OBJECTS +.word ASSET_OBJECT_DIDDYSELECT - ASSET_OBJECTS +.word ASSET_OBJECT_BANJOSELECT - ASSET_OBJECTS +.word ASSET_OBJECT_CHICKSELECT - ASSET_OBJECTS +.word ASSET_OBJECT_MOUSESELECT - ASSET_OBJECTS +.word ASSET_OBJECT_MAGICCARPET - ASSET_OBJECTS +.word ASSET_OBJECT_POLYGOLDBALOON - ASSET_OBJECTS +.word ASSET_OBJECT_ANIMGENIE - ASSET_OBJECTS +.word ASSET_OBJECT_ANIMGENIE3 - ASSET_OBJECTS +.word ASSET_OBJECT_BUTTERFLYBAIT - ASSET_OBJECTS +.word ASSET_OBJECT_AUDIO - ASSET_OBJECTS +.word ASSET_OBJECT_AUDIOLINE - ASSET_OBJECTS +.word ASSET_OBJECT_AUDIOSEQLINE - ASSET_OBJECTS +.word ASSET_OBJECT_AUDIOSEQ - ASSET_OBJECTS +.word ASSET_OBJECT_AUDIOREVERB - ASSET_OBJECTS +.word ASSET_OBJECT_FRONTTYRE - ASSET_OBJECTS +.word ASSET_OBJECT_BACKTYRE - ASSET_OBJECTS +.word ASSET_OBJECT_PLANETYRE - ASSET_OBJECTS +.word ASSET_OBJECT_FAN - ASSET_OBJECTS +.word ASSET_OBJECT_JETENGINE - ASSET_OBJECTS +.word ASSET_OBJECT_GLOVE - ASSET_OBJECTS +.word ASSET_OBJECT_LEEFAN - ASSET_OBJECTS +.word ASSET_OBJECT_MAGICRING - ASSET_OBJECTS +.word ASSET_OBJECT_DOME - ASSET_OBJECTS +.word ASSET_OBJECT_DOME1 - ASSET_OBJECTS +.word ASSET_OBJECT_DOME2 - ASSET_OBJECTS +.word ASSET_OBJECT_DOME3 - ASSET_OBJECTS +.word ASSET_OBJECT_DOME4 - ASSET_OBJECTS +.word ASSET_OBJECT_DOME5 - ASSET_OBJECTS +.word ASSET_OBJECT_DOME6 - ASSET_OBJECTS +.word ASSET_OBJECT_DOME7 - ASSET_OBJECTS +.word ASSET_OBJECT_DOME8 - ASSET_OBJECTS +.word ASSET_OBJECT_DOME9 - ASSET_OBJECTS +.word ASSET_OBJECT_DOME10 - ASSET_OBJECTS +.word ASSET_OBJECT_DOME11 - ASSET_OBJECTS +.word ASSET_OBJECT_DOME12 - ASSET_OBJECTS +.word ASSET_OBJECT_DOME13 - ASSET_OBJECTS +.word ASSET_OBJECT_DOME14 - ASSET_OBJECTS +.word ASSET_OBJECT_DOME15 - ASSET_OBJECTS +.word ASSET_OBJECT_DOME16 - ASSET_OBJECTS +.word ASSET_OBJECT_DOME17 - ASSET_OBJECTS +.word ASSET_OBJECT_SELECTIONSHADOW - ASSET_OBJECTS +.word ASSET_OBJECT_POSTFORPARTY - ASSET_OBJECTS +.word ASSET_OBJECT_RARELOGO - ASSET_OBJECTS +.word ASSET_OBJECT_SPARKLYTHING - ASSET_OBJECTS +.word ASSET_OBJECT_DOOROPENER - ASSET_OBJECTS +.word ASSET_OBJECT_ANIMDINOSAUR2 - ASSET_OBJECTS +.word ASSET_OBJECT_TIMERANIMHOVER - ASSET_OBJECTS +.word ASSET_OBJECT_ANIMBADGERPLANE - ASSET_OBJECTS +.word ASSET_OBJECT_ANIMDINOSAUR1 - ASSET_OBJECTS +.word ASSET_OBJECT_ANIMMOUSECAR - ASSET_OBJECTS +.word ASSET_OBJECT_ANIMTORT - ASSET_OBJECTS +.word ASSET_OBJECT_CHICKENANIMPLAN - ASSET_OBJECTS +.word ASSET_OBJECT_EMPTYHOVERANIM - ASSET_OBJECTS +.word ASSET_OBJECT_KREMANIM - ASSET_OBJECTS +.word ASSET_OBJECT_MOUSEHOVERANIM - ASSET_OBJECTS +.word ASSET_OBJECT_TORTRUNNER - ASSET_OBJECTS +.word ASSET_OBJECT_ANIMBANJOPLANE - ASSET_OBJECTS +.word ASSET_OBJECT_CONKAANIMCAR - ASSET_OBJECTS +.word ASSET_OBJECT_GBPARKWARDEN - ASSET_OBJECTS +.word ASSET_OBJECT_WIZPIG - ASSET_OBJECTS +.word ASSET_OBJECT_WIZPIGROCKET - ASSET_OBJECTS +.word ASSET_OBJECT_PIGBOSS - ASSET_OBJECTS +.word ASSET_OBJECT_PIGBOSS2 - ASSET_OBJECTS +.word ASSET_OBJECT_PIGROCKETEER - ASSET_OBJECTS +.word ASSET_OBJECT_PARTICLES2 - ASSET_OBJECTS +.word ASSET_OBJECT_PIGBOULDER - ASSET_OBJECTS +.word ASSET_OBJECT_BIGPLANET - ASSET_OBJECTS +.word ASSET_OBJECT_ROCKETBIT1 - ASSET_OBJECTS +.word ASSET_OBJECT_ROCKETBIT2 - ASSET_OBJECTS +.word ASSET_OBJECT_GENIEHEAD - ASSET_OBJECTS +.word ASSET_OBJECT_PIGBOULDER2 - ASSET_OBJECTS +.word ASSET_OBJECT_PIGBOULDER3 - ASSET_OBJECTS +.word ASSET_OBJECT_PIGBOULDER4 - ASSET_OBJECTS +.word ASSET_OBJECT_PIGBOULDER5 - ASSET_OBJECTS +.word ASSET_OBJECT_TRICKYTOPS - ASSET_OBJECTS +.word ASSET_OBJECT_TRICKYANIM - ASSET_OBJECTS +.word ASSET_OBJECT_TRICKYANIM2 - ASSET_OBJECTS +.word ASSET_OBJECT_TRICKYANIM3 - ASSET_OBJECTS +.word ASSET_OBJECT_WALRUS_ANIM - ASSET_OBJECTS +.word ASSET_OBJECT_TERRYBOSS - ASSET_OBJECTS +.word ASSET_OBJECT_DRAGONBOSS - ASSET_OBJECTS +.word ASSET_OBJECT_DRAGONANIM - ASSET_OBJECTS +.word ASSET_OBJECT_WALRUS - ASSET_OBJECTS +.word ASSET_OBJECT_SNOWBALLBOSS - ASSET_OBJECTS +.word ASSET_OBJECT_ANIMOCTO - ASSET_OBJECTS +.word ASSET_OBJECT_OCTOPUS - ASSET_OBJECTS +.word ASSET_OBJECT_GOLDBALOONSPRIT - ASSET_OBJECTS +.word ASSET_OBJECT_SPACECOLUMN1 - ASSET_OBJECTS +.word ASSET_OBJECT_SPACECOLUMN2 - ASSET_OBJECTS +.word ASSET_OBJECT_SPACECOLUMN3 - ASSET_OBJECTS +.word ASSET_OBJECT_HAYSTACK - ASSET_OBJECTS +.word ASSET_OBJECT_ANIMGENIE2 - ASSET_OBJECTS +.word ASSET_OBJECT_BRIGHTSTAR - ASSET_OBJECTS +.word ASSET_OBJECT_BUTTERFLY - ASSET_OBJECTS +.word ASSET_OBJECT_FISH - ASSET_OBJECTS +.word ASSET_OBJECT_FROG - ASSET_OBJECTS +.word ASSET_OBJECT_BOOST - ASSET_OBJECTS +.word ASSET_OBJECT_MAGNETFX - ASSET_OBJECTS +.word ASSET_OBJECT_STILLFROG - ASSET_OBJECTS +.word ASSET_OBJECT_STOPWATCHICON - ASSET_OBJECTS +.word ASSET_OBJECT_STOPWATCHHAND - ASSET_OBJECTS +.word ASSET_OBJECT_BRIDGE - ASSET_OBJECTS +.word ASSET_OBJECT_POSARROW - ASSET_OBJECTS +.word ASSET_OBJECT_HITTESTER - ASSET_OBJECTS +.word ASSET_OBJECT_MIDIFADE - ASSET_OBJECTS +.word ASSET_OBJECT_WINDSAIL - ASSET_OBJECTS +.word ASSET_OBJECT_EFFECTBOX - ASSET_OBJECTS +.word ASSET_OBJECT_TROPHYCAB - ASSET_OBJECTS +.word ASSET_OBJECT_FLYCOIN - ASSET_OBJECTS +.word ASSET_OBJECT_GOLDENBALLOON - ASSET_OBJECTS +.word ASSET_OBJECT_LASERBOLT - ASSET_OBJECTS +.word ASSET_OBJECT_LASERGUN - ASSET_OBJECTS +.word ASSET_OBJECT_BOLTGLOW - ASSET_OBJECTS +.word ASSET_OBJECT_GROUNDZIPPER - ASSET_OBJECTS +.word ASSET_OBJECT_PWSAFETELEPOINT - ASSET_OBJECTS +.word ASSET_OBJECT_HEADFORPOINT - ASSET_OBJECTS +.word ASSET_OBJECT_FIREBALLATTRACT - ASSET_OBJECTS +.word ASSET_OBJECT_FIREBALL - ASSET_OBJECTS +.word ASSET_OBJECT_OCTOBUBBLE - ASSET_OBJECTS +.word ASSET_OBJECT_OCTOBOMB - ASSET_OBJECTS +.word ASSET_OBJECT_GOLDTROPHY - ASSET_OBJECTS +.word ASSET_OBJECT_PARKTROPHY - ASSET_OBJECTS +.word ASSET_OBJECT_TICKTROPHY - ASSET_OBJECTS +.word ASSET_OBJECT_TROPHY - ASSET_OBJECTS +.word ASSET_OBJECT_TELEPORT - ASSET_OBJECTS +.word ASSET_OBJECT_SHIELD - ASSET_OBJECTS +.word ASSET_OBJECT_LIGHTNING - ASSET_OBJECTS +.word ASSET_OBJECT_MIDIFADEPOINT - ASSET_OBJECTS +.word ASSET_OBJECT_LEVELNAME - ASSET_OBJECTS +.word ASSET_OBJECT_MIDICHSET - ASSET_OBJECTS +.word ASSET_OBJECTS_END - ASSET_OBJECTS .word 0xFFFFFFFF +glabel ASSET_OBJECT_HEADERS_TABLE_END -/********** ASSET_OBJECT_HEADERS **********/ +/********** ASSET_OBJECTS **********/ .balign 16 -glabel ASSET_OBJECT_HEADERS -glabel ASSET_OBJHEADER_DIDDYCAR +glabel ASSET_OBJECTS +glabel ASSET_OBJECT_DIDDYCAR .incbin "./build/us_1.0/assets/objects/headers/diddycar.bin" -glabel ASSET_OBJHEADER_SWCAR +glabel ASSET_OBJECT_SWCAR .incbin "./build/us_1.0/assets/objects/headers/SWcar.bin" -glabel ASSET_OBJHEADER_KREMCAR +glabel ASSET_OBJECT_KREMCAR .incbin "./build/us_1.0/assets/objects/headers/KremCar.bin" -glabel ASSET_OBJHEADER_BADGERCAR +glabel ASSET_OBJECT_BADGERCAR .incbin "./build/us_1.0/assets/objects/headers/BadgerCar.bin" -glabel ASSET_OBJHEADER_TORTCAR +glabel ASSET_OBJECT_TORTCAR .incbin "./build/us_1.0/assets/objects/headers/TortCar.bin" -glabel ASSET_OBJHEADER_CONKACAR +glabel ASSET_OBJECT_CONKACAR .incbin "./build/us_1.0/assets/objects/headers/ConkaCar.bin" -glabel ASSET_OBJHEADER_TIGERCAR +glabel ASSET_OBJECT_TIGERCAR .incbin "./build/us_1.0/assets/objects/headers/TigerCar.bin" -glabel ASSET_OBJHEADER_BANJOCAR +glabel ASSET_OBJECT_BANJOCAR .incbin "./build/us_1.0/assets/objects/headers/BanjoCar.bin" -glabel ASSET_OBJHEADER_CHICKENCAR +glabel ASSET_OBJECT_CHICKENCAR .incbin "./build/us_1.0/assets/objects/headers/ChickenCar.bin" -glabel ASSET_OBJHEADER_MOUSECAR +glabel ASSET_OBJECT_MOUSECAR .incbin "./build/us_1.0/assets/objects/headers/MouseCar.bin" -glabel ASSET_OBJHEADER_DIDDYHOVER +glabel ASSET_OBJECT_DIDDYHOVER .incbin "./build/us_1.0/assets/objects/headers/diddyhover.bin" -glabel ASSET_OBJHEADER_TICKTOCKHOVER +glabel ASSET_OBJECT_TICKTOCKHOVER .incbin "./build/us_1.0/assets/objects/headers/ticktockhover.bin" -glabel ASSET_OBJHEADER_KREMLINHOVER +glabel ASSET_OBJECT_KREMLINHOVER .incbin "./build/us_1.0/assets/objects/headers/KremlinHover.bin" -glabel ASSET_OBJHEADER_BADGERHOVER +glabel ASSET_OBJECT_BADGERHOVER .incbin "./build/us_1.0/assets/objects/headers/BadgerHover.bin" -glabel ASSET_OBJHEADER_TORTHOVER +glabel ASSET_OBJECT_TORTHOVER .incbin "./build/us_1.0/assets/objects/headers/TortHover.bin" -glabel ASSET_OBJHEADER_CONKAHOVER +glabel ASSET_OBJECT_CONKAHOVER .incbin "./build/us_1.0/assets/objects/headers/ConkaHover.bin" -glabel ASSET_OBJHEADER_TIGERHOVER +glabel ASSET_OBJECT_TIGERHOVER .incbin "./build/us_1.0/assets/objects/headers/TigerHover.bin" -glabel ASSET_OBJHEADER_BANJOHOVER +glabel ASSET_OBJECT_BANJOHOVER .incbin "./build/us_1.0/assets/objects/headers/BanjoHover.bin" -glabel ASSET_OBJHEADER_CHICKENHOVER +glabel ASSET_OBJECT_CHICKENHOVER .incbin "./build/us_1.0/assets/objects/headers/ChickenHover.bin" -glabel ASSET_OBJHEADER_MOUSEHOVER +glabel ASSET_OBJECT_MOUSEHOVER .incbin "./build/us_1.0/assets/objects/headers/MouseHover.bin" -glabel ASSET_OBJHEADER_DIDDYPLANE +glabel ASSET_OBJECT_DIDDYPLANE .incbin "./build/us_1.0/assets/objects/headers/diddyplane.bin" -glabel ASSET_OBJHEADER_TICKTOCKPLANE +glabel ASSET_OBJECT_TICKTOCKPLANE .incbin "./build/us_1.0/assets/objects/headers/ticktockplane.bin" -glabel ASSET_OBJHEADER_KREMPLANE +glabel ASSET_OBJECT_KREMPLANE .incbin "./build/us_1.0/assets/objects/headers/KremPlane.bin" -glabel ASSET_OBJHEADER_BADGERPLANE +glabel ASSET_OBJECT_BADGERPLANE .incbin "./build/us_1.0/assets/objects/headers/BadgerPlane.bin" -glabel ASSET_OBJHEADER_TORTPLANE +glabel ASSET_OBJECT_TORTPLANE .incbin "./build/us_1.0/assets/objects/headers/TortPlane.bin" -glabel ASSET_OBJHEADER_CONKA +glabel ASSET_OBJECT_CONKA .incbin "./build/us_1.0/assets/objects/headers/Conka.bin" -glabel ASSET_OBJHEADER_TIGPLANE +glabel ASSET_OBJECT_TIGPLANE .incbin "./build/us_1.0/assets/objects/headers/TigPlane.bin" -glabel ASSET_OBJHEADER_BANJOPLANE +glabel ASSET_OBJECT_BANJOPLANE .incbin "./build/us_1.0/assets/objects/headers/BanjoPlane.bin" -glabel ASSET_OBJHEADER_CHICKENPLANE +glabel ASSET_OBJECT_CHICKENPLANE .incbin "./build/us_1.0/assets/objects/headers/ChickenPlane.bin" -glabel ASSET_OBJHEADER_MOUSEPLANE +glabel ASSET_OBJECT_MOUSEPLANE .incbin "./build/us_1.0/assets/objects/headers/MousePlane.bin" -glabel ASSET_OBJHEADER_FLYINGCARPET +glabel ASSET_OBJECT_FLYINGCARPET .incbin "./build/us_1.0/assets/objects/headers/FlyingCarpet.bin" -glabel ASSET_OBJHEADER_TIMBERDANCER +glabel ASSET_OBJECT_TIMBERDANCER .incbin "./build/us_1.0/assets/objects/headers/timberdancer.bin" -glabel ASSET_OBJHEADER_CHICKENCHARACTE +glabel ASSET_OBJECT_CHICKENCHARACTE .incbin "./build/us_1.0/assets/objects/headers/Chickencharacte.bin" -glabel ASSET_OBJHEADER_PIPSYDANCER +glabel ASSET_OBJECT_PIPSYDANCER .incbin "./build/us_1.0/assets/objects/headers/pipsydancer.bin" -glabel ASSET_OBJHEADER_BANJODANCER +glabel ASSET_OBJECT_BANJODANCER .incbin "./build/us_1.0/assets/objects/headers/banjodancer.bin" -glabel ASSET_OBJHEADER_TICKTOCKDANCER +glabel ASSET_OBJECT_TICKTOCKDANCER .incbin "./build/us_1.0/assets/objects/headers/ticktockdancer.bin" -glabel ASSET_OBJHEADER_WIZPIGSHIP +glabel ASSET_OBJECT_WIZPIGSHIP .incbin "./build/us_1.0/assets/objects/headers/wizpigship.bin" -glabel ASSET_OBJHEADER_CONKADANCER +glabel ASSET_OBJECT_CONKADANCER .incbin "./build/us_1.0/assets/objects/headers/conkadancer.bin" -glabel ASSET_OBJHEADER_EMPTYHOVER +glabel ASSET_OBJECT_EMPTYHOVER .incbin "./build/us_1.0/assets/objects/headers/EmptyHover.bin" -glabel ASSET_OBJHEADER_STOPWATCHMAN +glabel ASSET_OBJECT_STOPWATCHMAN .incbin "./build/us_1.0/assets/objects/headers/Stopwatch-man.bin" -glabel ASSET_OBJHEADER_STOPWATCHSELECT +glabel ASSET_OBJECT_STOPWATCHSELECT .incbin "./build/us_1.0/assets/objects/headers/stopwatchselect.bin" -glabel ASSET_OBJHEADER_PARKWARDEN +glabel ASSET_OBJECT_PARKWARDEN .incbin "./build/us_1.0/assets/objects/headers/Parkwarden.bin" -glabel ASSET_OBJHEADER_SMARTIETREE +glabel ASSET_OBJECT_SMARTIETREE .incbin "./build/us_1.0/assets/objects/headers/SmartieTree.bin" -glabel ASSET_OBJHEADER_BLUEBERRYBUSH +glabel ASSET_OBJECT_BLUEBERRYBUSH .incbin "./build/us_1.0/assets/objects/headers/BlueBerryBush.bin" -glabel ASSET_OBJHEADER_RUBBERSNOWTREE +glabel ASSET_OBJECT_RUBBERSNOWTREE .incbin "./build/us_1.0/assets/objects/headers/RubberSnowTree.bin" -glabel ASSET_OBJHEADER_SKINNYSNOWTREE +glabel ASSET_OBJECT_SKINNYSNOWTREE .incbin "./build/us_1.0/assets/objects/headers/SkinnySnowTree.bin" -glabel ASSET_OBJHEADER_XMASTREE +glabel ASSET_OBJECT_XMASTREE .incbin "./build/us_1.0/assets/objects/headers/XmasTree.bin" -glabel ASSET_OBJHEADER_ALPINESNOWTREE +glabel ASSET_OBJECT_ALPINESNOWTREE .incbin "./build/us_1.0/assets/objects/headers/AlpineSnowTree.bin" -glabel ASSET_OBJHEADER_RUBBERTREE +glabel ASSET_OBJECT_RUBBERTREE .incbin "./build/us_1.0/assets/objects/headers/RubberTree.bin" -glabel ASSET_OBJHEADER_BEACHTREE +glabel ASSET_OBJECT_BEACHTREE .incbin "./build/us_1.0/assets/objects/headers/Beachtree.bin" -glabel ASSET_OBJHEADER_PALMTREETOP +glabel ASSET_OBJECT_PALMTREETOP .incbin "./build/us_1.0/assets/objects/headers/PalmTreeTop.bin" -glabel ASSET_OBJHEADER_PALMPLANT +glabel ASSET_OBJECT_PALMPLANT .incbin "./build/us_1.0/assets/objects/headers/PalmPlant.bin" -glabel ASSET_OBJHEADER_PALMTREETOPCHEA +glabel ASSET_OBJECT_PALMTREETOPCHEA .incbin "./build/us_1.0/assets/objects/headers/PalmTreeTopChea.bin" -glabel ASSET_OBJHEADER_FIRTREE +glabel ASSET_OBJECT_FIRTREE .incbin "./build/us_1.0/assets/objects/headers/FirTree.bin" -glabel ASSET_OBJHEADER_SPACETREE +glabel ASSET_OBJECT_SPACETREE .incbin "./build/us_1.0/assets/objects/headers/SpaceTree.bin" -glabel ASSET_OBJHEADER_LAMPPOST +glabel ASSET_OBJECT_LAMPPOST .incbin "./build/us_1.0/assets/objects/headers/Lamppost.bin" -glabel ASSET_OBJHEADER_FLOWERS +glabel ASSET_OBJECT_FLOWERS .incbin "./build/us_1.0/assets/objects/headers/Flowers.bin" -glabel ASSET_OBJHEADER_REEDS +glabel ASSET_OBJECT_REEDS .incbin "./build/us_1.0/assets/objects/headers/Reeds.bin" -glabel ASSET_OBJHEADER_SMOKE +glabel ASSET_OBJECT_SMOKE .incbin "./build/us_1.0/assets/objects/headers/smoke.bin" -glabel ASSET_OBJHEADER_DINOSAUR1 +glabel ASSET_OBJECT_DINOSAUR1 .incbin "./build/us_1.0/assets/objects/headers/Dinosaur1.bin" -glabel ASSET_OBJHEADER_DINOSAUR2 +glabel ASSET_OBJECT_DINOSAUR2 .incbin "./build/us_1.0/assets/objects/headers/Dinosaur2.bin" -glabel ASSET_OBJHEADER_DINOSAUR3 +glabel ASSET_OBJECT_DINOSAUR3 .incbin "./build/us_1.0/assets/objects/headers/Dinosaur3.bin" -glabel ASSET_OBJHEADER_WHALE +glabel ASSET_OBJECT_WHALE .incbin "./build/us_1.0/assets/objects/headers/Whale.bin" -glabel ASSET_OBJHEADER_SNOWMEN +glabel ASSET_OBJECT_SNOWMEN .incbin "./build/us_1.0/assets/objects/headers/Snowmen.bin" -glabel ASSET_OBJHEADER_SIGNS +glabel ASSET_OBJECT_SIGNS .incbin "./build/us_1.0/assets/objects/headers/Signs.bin" -glabel ASSET_OBJHEADER_FLAMINGTORCH +glabel ASSET_OBJECT_FLAMINGTORCH .incbin "./build/us_1.0/assets/objects/headers/FlamingTorch.bin" -glabel ASSET_OBJHEADER_MIST +glabel ASSET_OBJECT_MIST .incbin "./build/us_1.0/assets/objects/headers/Mist.bin" -glabel ASSET_OBJHEADER_SNOWBALL +glabel ASSET_OBJECT_SNOWBALL .incbin "./build/us_1.0/assets/objects/headers/SnowBall.bin" -glabel ASSET_OBJHEADER_BUOY +glabel ASSET_OBJECT_BUOY .incbin "./build/us_1.0/assets/objects/headers/buoy.bin" -glabel ASSET_OBJHEADER_PIRATESHIP +glabel ASSET_OBJECT_PIRATESHIP .incbin "./build/us_1.0/assets/objects/headers/pirateship.bin" -glabel ASSET_OBJHEADER_LOG +glabel ASSET_OBJECT_LOG .incbin "./build/us_1.0/assets/objects/headers/log.bin" -glabel ASSET_OBJHEADER_PIGLOG +glabel ASSET_OBJECT_PIGLOG .incbin "./build/us_1.0/assets/objects/headers/piglog.bin" -glabel ASSET_OBJHEADER_BOULDER +glabel ASSET_OBJECT_BOULDER .incbin "./build/us_1.0/assets/objects/headers/boulder.bin" -glabel ASSET_OBJHEADER_AIRZIPPERS +glabel ASSET_OBJECT_AIRZIPPERS .incbin "./build/us_1.0/assets/objects/headers/AirZippers.bin" -glabel ASSET_OBJHEADER_WATERZIPPERS +glabel ASSET_OBJECT_WATERZIPPERS .incbin "./build/us_1.0/assets/objects/headers/WaterZippers.bin" -glabel ASSET_OBJHEADER_LEVELDOOR +glabel ASSET_OBJECT_LEVELDOOR .incbin "./build/us_1.0/assets/objects/headers/LevelDoor.bin" -glabel ASSET_OBJHEADER_KEITHPIGDOOR +glabel ASSET_OBJECT_KEITHPIGDOOR .incbin "./build/us_1.0/assets/objects/headers/KeithPigDoor.bin" -glabel ASSET_OBJHEADER_CHALDOOR +glabel ASSET_OBJECT_CHALDOOR .incbin "./build/us_1.0/assets/objects/headers/ChalDoor.bin" -glabel ASSET_OBJHEADER_BOSSDOOR +glabel ASSET_OBJECT_BOSSDOOR .incbin "./build/us_1.0/assets/objects/headers/BossDoor.bin" -glabel ASSET_OBJHEADER_BIGBOSSDOOR +glabel ASSET_OBJECT_BIGBOSSDOOR .incbin "./build/us_1.0/assets/objects/headers/bigbossdoor.bin" -glabel ASSET_OBJHEADER_WORLDGATE +glabel ASSET_OBJECT_WORLDGATE .incbin "./build/us_1.0/assets/objects/headers/WorldGate.bin" -glabel ASSET_OBJHEADER_TTDOOR +glabel ASSET_OBJECT_TTDOOR .incbin "./build/us_1.0/assets/objects/headers/TTDoor.bin" -glabel ASSET_OBJHEADER_RAMPSWITCH +glabel ASSET_OBJECT_RAMPSWITCH .incbin "./build/us_1.0/assets/objects/headers/RampSwitch.bin" -glabel ASSET_OBJHEADER_NOENTRYDOOR +glabel ASSET_OBJECT_NOENTRYDOOR .incbin "./build/us_1.0/assets/objects/headers/NoentryDoor.bin" -glabel ASSET_OBJHEADER_RAMPWHALE +glabel ASSET_OBJECT_RAMPWHALE .incbin "./build/us_1.0/assets/objects/headers/RampWhale.bin" -glabel ASSET_OBJHEADER_SEAMONSTER +glabel ASSET_OBJECT_SEAMONSTER .incbin "./build/us_1.0/assets/objects/headers/SeaMonster.bin" -glabel ASSET_OBJHEADER_DINOISLE +glabel ASSET_OBJECT_DINOISLE .incbin "./build/us_1.0/assets/objects/headers/Dinoisle.bin" -glabel ASSET_OBJHEADER_SKYCONTROL +glabel ASSET_OBJECT_SKYCONTROL .incbin "./build/us_1.0/assets/objects/headers/skycontrol.bin" -glabel ASSET_OBJHEADER_CHECKPOINT +glabel ASSET_OBJECT_CHECKPOINT .incbin "./build/us_1.0/assets/objects/headers/checkpoint.bin" -glabel ASSET_OBJHEADER_CHECKARROW +glabel ASSET_OBJECT_CHECKARROW .incbin "./build/us_1.0/assets/objects/headers/checkarrow.bin" -glabel ASSET_OBJHEADER_MODECHANGE +glabel ASSET_OBJECT_MODECHANGE .incbin "./build/us_1.0/assets/objects/headers/modechange.bin" -glabel ASSET_OBJHEADER_TRIGGER +glabel ASSET_OBJECT_TRIGGER .incbin "./build/us_1.0/assets/objects/headers/trigger.bin" -glabel ASSET_OBJHEADER_FOGCHANGER +glabel ASSET_OBJECT_FOGCHANGER .incbin "./build/us_1.0/assets/objects/headers/fogchanger.bin" -glabel ASSET_OBJHEADER_AINODE +glabel ASSET_OBJECT_AINODE .incbin "./build/us_1.0/assets/objects/headers/ai-node.bin" -glabel ASSET_OBJHEADER_EXIT +glabel ASSET_OBJECT_EXIT .incbin "./build/us_1.0/assets/objects/headers/exit.bin" -glabel ASSET_OBJHEADER_BONUS +glabel ASSET_OBJECT_BONUS .incbin "./build/us_1.0/assets/objects/headers/bonus.bin" -glabel ASSET_OBJHEADER_CAMERA_CONTROL +glabel ASSET_OBJECT_CAMERA_CONTROL .incbin "./build/us_1.0/assets/objects/headers/camera_control.bin" -glabel ASSET_OBJHEADER_SETUPPOINT +glabel ASSET_OBJECT_SETUPPOINT .incbin "./build/us_1.0/assets/objects/headers/setuppoint.bin" -glabel ASSET_OBJHEADER_ANIMATOR +glabel ASSET_OBJECT_ANIMATOR .incbin "./build/us_1.0/assets/objects/headers/animator.bin" -glabel ASSET_OBJHEADER_TEXSCROLL +glabel ASSET_OBJECT_TEXSCROLL .incbin "./build/us_1.0/assets/objects/headers/texscroll.bin" -glabel ASSET_OBJHEADER_RGBALIGHT +glabel ASSET_OBJECT_RGBALIGHT .incbin "./build/us_1.0/assets/objects/headers/rgbalight.bin" -glabel ASSET_OBJHEADER_INTROCAM +glabel ASSET_OBJECT_INTROCAM .incbin "./build/us_1.0/assets/objects/headers/introcam.bin" -glabel ASSET_OBJHEADER_WEATHER +glabel ASSET_OBJECT_WEATHER .incbin "./build/us_1.0/assets/objects/headers/weather.bin" -glabel ASSET_OBJHEADER_LENSFLARE +glabel ASSET_OBJECT_LENSFLARE .incbin "./build/us_1.0/assets/objects/headers/lensflare.bin" -glabel ASSET_OBJHEADER_LENSFLARESWITCH +glabel ASSET_OBJECT_LENSFLARESWITCH .incbin "./build/us_1.0/assets/objects/headers/lensflareswitch.bin" -glabel ASSET_OBJHEADER_INFOPOINT +glabel ASSET_OBJECT_INFOPOINT .incbin "./build/us_1.0/assets/objects/headers/InfoPoint.bin" -glabel ASSET_OBJHEADER_WAVEGENERATOR +glabel ASSET_OBJECT_WAVEGENERATOR .incbin "./build/us_1.0/assets/objects/headers/wavegenerator.bin" -glabel ASSET_OBJHEADER_WAVEPOWER +glabel ASSET_OBJECT_WAVEPOWER .incbin "./build/us_1.0/assets/objects/headers/wavepower.bin" -glabel ASSET_OBJHEADER_RANGETRIGGER +glabel ASSET_OBJECT_RANGETRIGGER .incbin "./build/us_1.0/assets/objects/headers/RangeTrigger.bin" -glabel ASSET_OBJHEADER_LAVASPURT +glabel ASSET_OBJECT_LAVASPURT .incbin "./build/us_1.0/assets/objects/headers/lavaspurt.bin" -glabel ASSET_OBJHEADER_BOMBEXPLOSION +glabel ASSET_OBJECT_BOMBEXPLOSION .incbin "./build/us_1.0/assets/objects/headers/bombexplosion.bin" -glabel ASSET_OBJHEADER_WARDENSMOKE +glabel ASSET_OBJECT_WARDENSMOKE .incbin "./build/us_1.0/assets/objects/headers/wardensmoke.bin" -glabel ASSET_OBJHEADER_BUBBLER +glabel ASSET_OBJECT_BUBBLER .incbin "./build/us_1.0/assets/objects/headers/bubbler.bin" -glabel ASSET_OBJHEADER_WEAPONBALLOON +glabel ASSET_OBJECT_WEAPONBALLOON .incbin "./build/us_1.0/assets/objects/headers/WeaponBalloon.bin" -glabel ASSET_OBJHEADER_WBALLOONPOP +glabel ASSET_OBJECT_WBALLOONPOP .incbin "./build/us_1.0/assets/objects/headers/wballoonpop.bin" -glabel ASSET_OBJHEADER_MISSILEGLOW +glabel ASSET_OBJECT_MISSILEGLOW .incbin "./build/us_1.0/assets/objects/headers/MissileGlow.bin" -glabel ASSET_OBJHEADER_HOMINGGLOW +glabel ASSET_OBJECT_HOMINGGLOW .incbin "./build/us_1.0/assets/objects/headers/HomingGlow.bin" -glabel ASSET_OBJHEADER_MISSILE +glabel ASSET_OBJECT_MISSILE .incbin "./build/us_1.0/assets/objects/headers/Missile.bin" -glabel ASSET_OBJHEADER_HOMING +glabel ASSET_OBJECT_HOMING .incbin "./build/us_1.0/assets/objects/headers/Homing.bin" -glabel ASSET_OBJHEADER_OILSLICK +glabel ASSET_OBJECT_OILSLICK .incbin "./build/us_1.0/assets/objects/headers/OilSlick.bin" -glabel ASSET_OBJHEADER_SMOKECLOUD +glabel ASSET_OBJECT_SMOKECLOUD .incbin "./build/us_1.0/assets/objects/headers/SmokeCloud.bin" -glabel ASSET_OBJHEADER_BOMB +glabel ASSET_OBJECT_BOMB .incbin "./build/us_1.0/assets/objects/headers/Bomb.bin" -glabel ASSET_OBJHEADER_BUBBLEWEAPON +glabel ASSET_OBJECT_BUBBLEWEAPON .incbin "./build/us_1.0/assets/objects/headers/BubbleWeapon.bin" -glabel ASSET_OBJHEADER_WORLDKEY +glabel ASSET_OBJECT_WORLDKEY .incbin "./build/us_1.0/assets/objects/headers/WorldKey.bin" -glabel ASSET_OBJHEADER_COINCREATOR +glabel ASSET_OBJECT_COINCREATOR .incbin "./build/us_1.0/assets/objects/headers/CoinCreator.bin" -glabel ASSET_OBJHEADER_TREASURESUCKER +glabel ASSET_OBJECT_TREASURESUCKER .incbin "./build/us_1.0/assets/objects/headers/TreasureSucker.bin" -glabel ASSET_OBJHEADER_COIN +glabel ASSET_OBJECT_COIN .incbin "./build/us_1.0/assets/objects/headers/Coin.bin" -glabel ASSET_OBJHEADER_SILVERCOIN +glabel ASSET_OBJECT_SILVERCOIN .incbin "./build/us_1.0/assets/objects/headers/SilverCoin.bin" -glabel ASSET_OBJHEADER_GOLDCOIN +glabel ASSET_OBJECT_GOLDCOIN .incbin "./build/us_1.0/assets/objects/headers/GoldCoin.bin" -glabel ASSET_OBJHEADER_BONUSGEM +glabel ASSET_OBJECT_BONUSGEM .incbin "./build/us_1.0/assets/objects/headers/BonusGem.bin" -glabel ASSET_OBJHEADER_COLLECTEGG +glabel ASSET_OBJECT_COLLECTEGG .incbin "./build/us_1.0/assets/objects/headers/CollectEgg.bin" -glabel ASSET_OBJHEADER_EGGCREATOR +glabel ASSET_OBJECT_EGGCREATOR .incbin "./build/us_1.0/assets/objects/headers/EggCreator.bin" -glabel ASSET_OBJHEADER_CHARACTERFLAG +glabel ASSET_OBJECT_CHARACTERFLAG .incbin "./build/us_1.0/assets/objects/headers/CharacterFlag.bin" -glabel ASSET_OBJHEADER_ANIMATION +glabel ASSET_OBJECT_ANIMATION .incbin "./build/us_1.0/assets/objects/headers/Animation.bin" -glabel ASSET_OBJHEADER_OVERRIDEPOS +glabel ASSET_OBJECT_OVERRIDEPOS .incbin "./build/us_1.0/assets/objects/headers/OverRidePos.bin" -glabel ASSET_OBJHEADER_ANIMCAMERA +glabel ASSET_OBJECT_ANIMCAMERA .incbin "./build/us_1.0/assets/objects/headers/AnimCamera.bin" -glabel ASSET_OBJHEADER_ANIMCAR +glabel ASSET_OBJECT_ANIMCAR .incbin "./build/us_1.0/assets/objects/headers/AnimCar.bin" -glabel ASSET_OBJHEADER_ANIMDOME +glabel ASSET_OBJECT_ANIMDOME .incbin "./build/us_1.0/assets/objects/headers/AnimDome.bin" -glabel ASSET_OBJHEADER_WIZGHOSTS +glabel ASSET_OBJECT_WIZGHOSTS .incbin "./build/us_1.0/assets/objects/headers/Wizghosts.bin" -glabel ASSET_OBJHEADER_N64LOGO +glabel ASSET_OBJECT_N64LOGO .incbin "./build/us_1.0/assets/objects/headers/N64logo.bin" -glabel ASSET_OBJHEADER_ASTEROID +glabel ASSET_OBJECT_ASTEROID .incbin "./build/us_1.0/assets/objects/headers/Asteroid.bin" -glabel ASSET_OBJHEADER_PILLAR +glabel ASSET_OBJECT_PILLAR .incbin "./build/us_1.0/assets/objects/headers/pillar.bin" -glabel ASSET_OBJHEADER_BOULDERANIM +glabel ASSET_OBJECT_BOULDERANIM .incbin "./build/us_1.0/assets/objects/headers/boulderanim.bin" -glabel ASSET_OBJHEADER_PIGHEADCOLOURS +glabel ASSET_OBJECT_PIGHEADCOLOURS .incbin "./build/us_1.0/assets/objects/headers/pigheadcolours.bin" -glabel ASSET_OBJHEADER_PIGFACEANIMATOR +glabel ASSET_OBJECT_PIGFACEANIMATOR .incbin "./build/us_1.0/assets/objects/headers/pigfaceanimator.bin" -glabel ASSET_OBJHEADER_PTERODACTYL +glabel ASSET_OBJECT_PTERODACTYL .incbin "./build/us_1.0/assets/objects/headers/pterodactyl.bin" -glabel ASSET_OBJHEADER_AMULETPIECE1 +glabel ASSET_OBJECT_AMULETPIECE1 .incbin "./build/us_1.0/assets/objects/headers/amuletpiece1.bin" -glabel ASSET_OBJHEADER_AMULETPIECE2 +glabel ASSET_OBJECT_AMULETPIECE2 .incbin "./build/us_1.0/assets/objects/headers/amuletpiece2.bin" -glabel ASSET_OBJHEADER_AMULETPIECE3 +glabel ASSET_OBJECT_AMULETPIECE3 .incbin "./build/us_1.0/assets/objects/headers/amuletpiece3.bin" -glabel ASSET_OBJHEADER_AMULETPIECE4 +glabel ASSET_OBJECT_AMULETPIECE4 .incbin "./build/us_1.0/assets/objects/headers/amuletpiece4.bin" -glabel ASSET_OBJHEADER_SWAMULET1 +glabel ASSET_OBJECT_SWAMULET1 .incbin "./build/us_1.0/assets/objects/headers/swamulet1.bin" -glabel ASSET_OBJHEADER_SWAMULET2 +glabel ASSET_OBJECT_SWAMULET2 .incbin "./build/us_1.0/assets/objects/headers/swamulet2.bin" -glabel ASSET_OBJHEADER_SWAMULET3 +glabel ASSET_OBJECT_SWAMULET3 .incbin "./build/us_1.0/assets/objects/headers/swamulet3.bin" -glabel ASSET_OBJHEADER_SWAMULET4 +glabel ASSET_OBJECT_SWAMULET4 .incbin "./build/us_1.0/assets/objects/headers/swamulet4.bin" -glabel ASSET_OBJHEADER_ANIMKEY +glabel ASSET_OBJECT_ANIMKEY .incbin "./build/us_1.0/assets/objects/headers/AnimKey.bin" -glabel ASSET_OBJHEADER_SPACESHIP1 +glabel ASSET_OBJECT_SPACESHIP1 .incbin "./build/us_1.0/assets/objects/headers/SpaceShip1.bin" -glabel ASSET_OBJHEADER_MINISHIP +glabel ASSET_OBJECT_MINISHIP .incbin "./build/us_1.0/assets/objects/headers/MiniShip.bin" -glabel ASSET_OBJHEADER_MONORAIL +glabel ASSET_OBJECT_MONORAIL .incbin "./build/us_1.0/assets/objects/headers/MonoRail.bin" -glabel ASSET_OBJHEADER_SPACESHIP2 +glabel ASSET_OBJECT_SPACESHIP2 .incbin "./build/us_1.0/assets/objects/headers/SpaceShip2.bin" -glabel ASSET_OBJHEADER_SPACESHIP3 +glabel ASSET_OBJECT_SPACESHIP3 .incbin "./build/us_1.0/assets/objects/headers/SpaceShip3.bin" -glabel ASSET_OBJHEADER_LIGHTHOUSE +glabel ASSET_OBJECT_LIGHTHOUSE .incbin "./build/us_1.0/assets/objects/headers/Lighthouse.bin" -glabel ASSET_OBJHEADER_ROCKETSIGNPOST +glabel ASSET_OBJECT_ROCKETSIGNPOST .incbin "./build/us_1.0/assets/objects/headers/rocketsignpost.bin" -glabel ASSET_OBJHEADER_LIGHTHOUSE1 +glabel ASSET_OBJECT_LIGHTHOUSE1 .incbin "./build/us_1.0/assets/objects/headers/lighthouse1.bin" -glabel ASSET_OBJHEADER_LIGHTHOUSE2 +glabel ASSET_OBJECT_LIGHTHOUSE2 .incbin "./build/us_1.0/assets/objects/headers/lighthouse2.bin" -glabel ASSET_OBJHEADER_SELECTIONHILL +glabel ASSET_OBJECT_SELECTIONHILL .incbin "./build/us_1.0/assets/objects/headers/SelectionHill.bin" -glabel ASSET_OBJHEADER_WIDESCREEN +glabel ASSET_OBJECT_WIDESCREEN .incbin "./build/us_1.0/assets/objects/headers/Widescreen.bin" -glabel ASSET_OBJHEADER_TIGERANIMPLANE +glabel ASSET_OBJECT_TIGERANIMPLANE .incbin "./build/us_1.0/assets/objects/headers/TigerAnimPlane.bin" -glabel ASSET_OBJHEADER_BADGERANIMWALK +glabel ASSET_OBJECT_BADGERANIMWALK .incbin "./build/us_1.0/assets/objects/headers/BadgerAnimWalk.bin" -glabel ASSET_OBJHEADER_TIMBERANIMCAR +glabel ASSET_OBJECT_TIMBERANIMCAR .incbin "./build/us_1.0/assets/objects/headers/Timberanimcar.bin" -glabel ASSET_OBJHEADER_KREMSELECT +glabel ASSET_OBJECT_KREMSELECT .incbin "./build/us_1.0/assets/objects/headers/KremSelect.bin" -glabel ASSET_OBJHEADER_CONKSELECT +glabel ASSET_OBJECT_CONKSELECT .incbin "./build/us_1.0/assets/objects/headers/ConkSelect.bin" -glabel ASSET_OBJHEADER_BADGERSELECT +glabel ASSET_OBJECT_BADGERSELECT .incbin "./build/us_1.0/assets/objects/headers/BadgerSelect.bin" -glabel ASSET_OBJHEADER_TORTSELECT +glabel ASSET_OBJECT_TORTSELECT .incbin "./build/us_1.0/assets/objects/headers/TortSelect.bin" -glabel ASSET_OBJHEADER_TIGERSELECT +glabel ASSET_OBJECT_TIGERSELECT .incbin "./build/us_1.0/assets/objects/headers/TigerSelect.bin" -glabel ASSET_OBJHEADER_DIDDYSELECT +glabel ASSET_OBJECT_DIDDYSELECT .incbin "./build/us_1.0/assets/objects/headers/DiddySelect.bin" -glabel ASSET_OBJHEADER_BANJOSELECT +glabel ASSET_OBJECT_BANJOSELECT .incbin "./build/us_1.0/assets/objects/headers/BanjoSelect.bin" -glabel ASSET_OBJHEADER_CHICKSELECT +glabel ASSET_OBJECT_CHICKSELECT .incbin "./build/us_1.0/assets/objects/headers/ChickSelect.bin" -glabel ASSET_OBJHEADER_MOUSESELECT +glabel ASSET_OBJECT_MOUSESELECT .incbin "./build/us_1.0/assets/objects/headers/MouseSelect.bin" -glabel ASSET_OBJHEADER_MAGICCARPET +glabel ASSET_OBJECT_MAGICCARPET .incbin "./build/us_1.0/assets/objects/headers/MagicCarpet.bin" -glabel ASSET_OBJHEADER_POLYGOLDBALOON +glabel ASSET_OBJECT_POLYGOLDBALOON .incbin "./build/us_1.0/assets/objects/headers/PolyGoldBaloon.bin" -glabel ASSET_OBJHEADER_ANIMGENIE +glabel ASSET_OBJECT_ANIMGENIE .incbin "./build/us_1.0/assets/objects/headers/AnimGenie.bin" -glabel ASSET_OBJHEADER_ANIMGENIE3 +glabel ASSET_OBJECT_ANIMGENIE3 .incbin "./build/us_1.0/assets/objects/headers/AnimGenie3.bin" -glabel ASSET_OBJHEADER_BUTTERFLYBAIT +glabel ASSET_OBJECT_BUTTERFLYBAIT .incbin "./build/us_1.0/assets/objects/headers/ButterflyBait.bin" -glabel ASSET_OBJHEADER_AUDIO +glabel ASSET_OBJECT_AUDIO .incbin "./build/us_1.0/assets/objects/headers/audio.bin" -glabel ASSET_OBJHEADER_AUDIOLINE +glabel ASSET_OBJECT_AUDIOLINE .incbin "./build/us_1.0/assets/objects/headers/audioline.bin" -glabel ASSET_OBJHEADER_AUDIOSEQLINE +glabel ASSET_OBJECT_AUDIOSEQLINE .incbin "./build/us_1.0/assets/objects/headers/audioseqline.bin" -glabel ASSET_OBJHEADER_AUDIOSEQ +glabel ASSET_OBJECT_AUDIOSEQ .incbin "./build/us_1.0/assets/objects/headers/audioseq.bin" -glabel ASSET_OBJHEADER_AUDIOREVERB +glabel ASSET_OBJECT_AUDIOREVERB .incbin "./build/us_1.0/assets/objects/headers/audioreverb.bin" -glabel ASSET_OBJHEADER_FRONTTYRE +glabel ASSET_OBJECT_FRONTTYRE .incbin "./build/us_1.0/assets/objects/headers/fronttyre.bin" -glabel ASSET_OBJHEADER_BACKTYRE +glabel ASSET_OBJECT_BACKTYRE .incbin "./build/us_1.0/assets/objects/headers/backtyre.bin" -glabel ASSET_OBJHEADER_PLANETYRE +glabel ASSET_OBJECT_PLANETYRE .incbin "./build/us_1.0/assets/objects/headers/planetyre.bin" -glabel ASSET_OBJHEADER_FAN +glabel ASSET_OBJECT_FAN .incbin "./build/us_1.0/assets/objects/headers/fan.bin" -glabel ASSET_OBJHEADER_JETENGINE +glabel ASSET_OBJECT_JETENGINE .incbin "./build/us_1.0/assets/objects/headers/jetengine.bin" -glabel ASSET_OBJHEADER_GLOVE +glabel ASSET_OBJECT_GLOVE .incbin "./build/us_1.0/assets/objects/headers/glove.bin" -glabel ASSET_OBJHEADER_LEEFAN +glabel ASSET_OBJECT_LEEFAN .incbin "./build/us_1.0/assets/objects/headers/Leefan.bin" -glabel ASSET_OBJHEADER_MAGICRING +glabel ASSET_OBJECT_MAGICRING .incbin "./build/us_1.0/assets/objects/headers/MagicRing.bin" -glabel ASSET_OBJHEADER_DOME +glabel ASSET_OBJECT_DOME .incbin "./build/us_1.0/assets/objects/headers/dome.bin" -glabel ASSET_OBJHEADER_DOME1 +glabel ASSET_OBJECT_DOME1 .incbin "./build/us_1.0/assets/objects/headers/dome1.bin" -glabel ASSET_OBJHEADER_DOME2 +glabel ASSET_OBJECT_DOME2 .incbin "./build/us_1.0/assets/objects/headers/dome2.bin" -glabel ASSET_OBJHEADER_DOME3 +glabel ASSET_OBJECT_DOME3 .incbin "./build/us_1.0/assets/objects/headers/dome3.bin" -glabel ASSET_OBJHEADER_DOME4 +glabel ASSET_OBJECT_DOME4 .incbin "./build/us_1.0/assets/objects/headers/dome4.bin" -glabel ASSET_OBJHEADER_DOME5 +glabel ASSET_OBJECT_DOME5 .incbin "./build/us_1.0/assets/objects/headers/dome5.bin" -glabel ASSET_OBJHEADER_DOME6 +glabel ASSET_OBJECT_DOME6 .incbin "./build/us_1.0/assets/objects/headers/dome6.bin" -glabel ASSET_OBJHEADER_DOME7 +glabel ASSET_OBJECT_DOME7 .incbin "./build/us_1.0/assets/objects/headers/dome7.bin" -glabel ASSET_OBJHEADER_DOME8 +glabel ASSET_OBJECT_DOME8 .incbin "./build/us_1.0/assets/objects/headers/dome8.bin" -glabel ASSET_OBJHEADER_DOME9 +glabel ASSET_OBJECT_DOME9 .incbin "./build/us_1.0/assets/objects/headers/dome9.bin" -glabel ASSET_OBJHEADER_DOME10 +glabel ASSET_OBJECT_DOME10 .incbin "./build/us_1.0/assets/objects/headers/dome10.bin" -glabel ASSET_OBJHEADER_DOME11 +glabel ASSET_OBJECT_DOME11 .incbin "./build/us_1.0/assets/objects/headers/dome11.bin" -glabel ASSET_OBJHEADER_DOME12 +glabel ASSET_OBJECT_DOME12 .incbin "./build/us_1.0/assets/objects/headers/dome12.bin" -glabel ASSET_OBJHEADER_DOME13 +glabel ASSET_OBJECT_DOME13 .incbin "./build/us_1.0/assets/objects/headers/dome13.bin" -glabel ASSET_OBJHEADER_DOME14 +glabel ASSET_OBJECT_DOME14 .incbin "./build/us_1.0/assets/objects/headers/dome14.bin" -glabel ASSET_OBJHEADER_DOME15 +glabel ASSET_OBJECT_DOME15 .incbin "./build/us_1.0/assets/objects/headers/dome15.bin" -glabel ASSET_OBJHEADER_DOME16 +glabel ASSET_OBJECT_DOME16 .incbin "./build/us_1.0/assets/objects/headers/dome16.bin" -glabel ASSET_OBJHEADER_DOME17 +glabel ASSET_OBJECT_DOME17 .incbin "./build/us_1.0/assets/objects/headers/dome17.bin" -glabel ASSET_OBJHEADER_SELECTIONSHADOW +glabel ASSET_OBJECT_SELECTIONSHADOW .incbin "./build/us_1.0/assets/objects/headers/selectionshadow.bin" -glabel ASSET_OBJHEADER_POSTFORPARTY +glabel ASSET_OBJECT_POSTFORPARTY .incbin "./build/us_1.0/assets/objects/headers/postforparty.bin" -glabel ASSET_OBJHEADER_RARELOGO +glabel ASSET_OBJECT_RARELOGO .incbin "./build/us_1.0/assets/objects/headers/Rarelogo.bin" -glabel ASSET_OBJHEADER_SPARKLYTHING +glabel ASSET_OBJECT_SPARKLYTHING .incbin "./build/us_1.0/assets/objects/headers/sparklything.bin" -glabel ASSET_OBJHEADER_DOOROPENER +glabel ASSET_OBJECT_DOOROPENER .incbin "./build/us_1.0/assets/objects/headers/DoorOpener.bin" -glabel ASSET_OBJHEADER_ANIMDINOSAUR2 +glabel ASSET_OBJECT_ANIMDINOSAUR2 .incbin "./build/us_1.0/assets/objects/headers/AnimDinosaur2.bin" -glabel ASSET_OBJHEADER_TIMERANIMHOVER +glabel ASSET_OBJECT_TIMERANIMHOVER .incbin "./build/us_1.0/assets/objects/headers/Timeranimhover.bin" -glabel ASSET_OBJHEADER_ANIMBADGERPLANE +glabel ASSET_OBJECT_ANIMBADGERPLANE .incbin "./build/us_1.0/assets/objects/headers/AnimBadgerPlane.bin" -glabel ASSET_OBJHEADER_ANIMDINOSAUR1 +glabel ASSET_OBJECT_ANIMDINOSAUR1 .incbin "./build/us_1.0/assets/objects/headers/AnimDinosaur1.bin" -glabel ASSET_OBJHEADER_ANIMMOUSECAR +glabel ASSET_OBJECT_ANIMMOUSECAR .incbin "./build/us_1.0/assets/objects/headers/AnimMouseCar.bin" -glabel ASSET_OBJHEADER_ANIMTORT +glabel ASSET_OBJECT_ANIMTORT .incbin "./build/us_1.0/assets/objects/headers/Animtort.bin" -glabel ASSET_OBJHEADER_CHICKENANIMPLAN +glabel ASSET_OBJECT_CHICKENANIMPLAN .incbin "./build/us_1.0/assets/objects/headers/ChickenAnimPlan.bin" -glabel ASSET_OBJHEADER_EMPTYHOVERANIM +glabel ASSET_OBJECT_EMPTYHOVERANIM .incbin "./build/us_1.0/assets/objects/headers/EmptyHoverAnim.bin" -glabel ASSET_OBJHEADER_KREMANIM +glabel ASSET_OBJECT_KREMANIM .incbin "./build/us_1.0/assets/objects/headers/KremAnim.bin" -glabel ASSET_OBJHEADER_MOUSEHOVERANIM +glabel ASSET_OBJECT_MOUSEHOVERANIM .incbin "./build/us_1.0/assets/objects/headers/MouseHoverAnim.bin" -glabel ASSET_OBJHEADER_TORTRUNNER +glabel ASSET_OBJECT_TORTRUNNER .incbin "./build/us_1.0/assets/objects/headers/TortRunner.bin" -glabel ASSET_OBJHEADER_ANIMBANJOPLANE +glabel ASSET_OBJECT_ANIMBANJOPLANE .incbin "./build/us_1.0/assets/objects/headers/AnimBanjoPlane.bin" -glabel ASSET_OBJHEADER_CONKAANIMCAR +glabel ASSET_OBJECT_CONKAANIMCAR .incbin "./build/us_1.0/assets/objects/headers/Conkaanimcar.bin" -glabel ASSET_OBJHEADER_GBPARKWARDEN +glabel ASSET_OBJECT_GBPARKWARDEN .incbin "./build/us_1.0/assets/objects/headers/GBParkwarden.bin" -glabel ASSET_OBJHEADER_WIZPIG +glabel ASSET_OBJECT_WIZPIG .incbin "./build/us_1.0/assets/objects/headers/Wizpig.bin" -glabel ASSET_OBJHEADER_WIZPIGROCKET +glabel ASSET_OBJECT_WIZPIGROCKET .incbin "./build/us_1.0/assets/objects/headers/WizpigRocket.bin" -glabel ASSET_OBJHEADER_PIGBOSS +glabel ASSET_OBJECT_PIGBOSS .incbin "./build/us_1.0/assets/objects/headers/Pigboss.bin" -glabel ASSET_OBJHEADER_PIGBOSS2 +glabel ASSET_OBJECT_PIGBOSS2 .incbin "./build/us_1.0/assets/objects/headers/Pigboss2.bin" -glabel ASSET_OBJHEADER_PIGROCKETEER +glabel ASSET_OBJECT_PIGROCKETEER .incbin "./build/us_1.0/assets/objects/headers/PigRocketeer.bin" -glabel ASSET_OBJHEADER_PARTICLES2 +glabel ASSET_OBJECT_PARTICLES2 .incbin "./build/us_1.0/assets/objects/headers/Particles2.bin" -glabel ASSET_OBJHEADER_PIGBOULDER +glabel ASSET_OBJECT_PIGBOULDER .incbin "./build/us_1.0/assets/objects/headers/Pigboulder.bin" -glabel ASSET_OBJHEADER_BIGPLANET +glabel ASSET_OBJECT_BIGPLANET .incbin "./build/us_1.0/assets/objects/headers/Bigplanet.bin" -glabel ASSET_OBJHEADER_ROCKETBIT1 +glabel ASSET_OBJECT_ROCKETBIT1 .incbin "./build/us_1.0/assets/objects/headers/rocketbit1.bin" -glabel ASSET_OBJHEADER_ROCKETBIT2 +glabel ASSET_OBJECT_ROCKETBIT2 .incbin "./build/us_1.0/assets/objects/headers/rocketbit2.bin" -glabel ASSET_OBJHEADER_GENIEHEAD +glabel ASSET_OBJECT_GENIEHEAD .incbin "./build/us_1.0/assets/objects/headers/Geniehead.bin" -glabel ASSET_OBJHEADER_PIGBOULDER2 +glabel ASSET_OBJECT_PIGBOULDER2 .incbin "./build/us_1.0/assets/objects/headers/Pigboulder2.bin" -glabel ASSET_OBJHEADER_PIGBOULDER3 +glabel ASSET_OBJECT_PIGBOULDER3 .incbin "./build/us_1.0/assets/objects/headers/Pigboulder3.bin" -glabel ASSET_OBJHEADER_PIGBOULDER4 +glabel ASSET_OBJECT_PIGBOULDER4 .incbin "./build/us_1.0/assets/objects/headers/Pigboulder4.bin" -glabel ASSET_OBJHEADER_PIGBOULDER5 +glabel ASSET_OBJECT_PIGBOULDER5 .incbin "./build/us_1.0/assets/objects/headers/Pigboulder5.bin" -glabel ASSET_OBJHEADER_TRICKYTOPS +glabel ASSET_OBJECT_TRICKYTOPS .incbin "./build/us_1.0/assets/objects/headers/Trickytops.bin" -glabel ASSET_OBJHEADER_TRICKYANIM +glabel ASSET_OBJECT_TRICKYANIM .incbin "./build/us_1.0/assets/objects/headers/Trickyanim.bin" -glabel ASSET_OBJHEADER_TRICKYANIM2 +glabel ASSET_OBJECT_TRICKYANIM2 .incbin "./build/us_1.0/assets/objects/headers/Trickyanim2.bin" -glabel ASSET_OBJHEADER_TRICKYANIM3 +glabel ASSET_OBJECT_TRICKYANIM3 .incbin "./build/us_1.0/assets/objects/headers/Trickyanim3.bin" -glabel ASSET_OBJHEADER_WALRUS_ANIM +glabel ASSET_OBJECT_WALRUS_ANIM .incbin "./build/us_1.0/assets/objects/headers/Walrus_anim.bin" -glabel ASSET_OBJHEADER_TERRYBOSS +glabel ASSET_OBJECT_TERRYBOSS .incbin "./build/us_1.0/assets/objects/headers/Terryboss.bin" -glabel ASSET_OBJHEADER_DRAGONBOSS +glabel ASSET_OBJECT_DRAGONBOSS .incbin "./build/us_1.0/assets/objects/headers/Dragonboss.bin" -glabel ASSET_OBJHEADER_DRAGONANIM +glabel ASSET_OBJECT_DRAGONANIM .incbin "./build/us_1.0/assets/objects/headers/DragonAnim.bin" -glabel ASSET_OBJHEADER_WALRUS +glabel ASSET_OBJECT_WALRUS .incbin "./build/us_1.0/assets/objects/headers/Walrus.bin" -glabel ASSET_OBJHEADER_SNOWBALLBOSS +glabel ASSET_OBJECT_SNOWBALLBOSS .incbin "./build/us_1.0/assets/objects/headers/SnowballBoss.bin" -glabel ASSET_OBJHEADER_ANIMOCTO +glabel ASSET_OBJECT_ANIMOCTO .incbin "./build/us_1.0/assets/objects/headers/animocto.bin" -glabel ASSET_OBJHEADER_OCTOPUS +glabel ASSET_OBJECT_OCTOPUS .incbin "./build/us_1.0/assets/objects/headers/octopus.bin" -glabel ASSET_OBJHEADER_GOLDBALOONSPRIT +glabel ASSET_OBJECT_GOLDBALOONSPRIT .incbin "./build/us_1.0/assets/objects/headers/GoldBaloonSprit.bin" -glabel ASSET_OBJHEADER_SPACECOLUMN1 +glabel ASSET_OBJECT_SPACECOLUMN1 .incbin "./build/us_1.0/assets/objects/headers/SpaceColumn1.bin" -glabel ASSET_OBJHEADER_SPACECOLUMN2 +glabel ASSET_OBJECT_SPACECOLUMN2 .incbin "./build/us_1.0/assets/objects/headers/SpaceColumn2.bin" -glabel ASSET_OBJHEADER_SPACECOLUMN3 +glabel ASSET_OBJECT_SPACECOLUMN3 .incbin "./build/us_1.0/assets/objects/headers/SpaceColumn3.bin" -glabel ASSET_OBJHEADER_HAYSTACK +glabel ASSET_OBJECT_HAYSTACK .incbin "./build/us_1.0/assets/objects/headers/Haystack.bin" -glabel ASSET_OBJHEADER_ANIMGENIE2 +glabel ASSET_OBJECT_ANIMGENIE2 .incbin "./build/us_1.0/assets/objects/headers/AnimGenie2.bin" -glabel ASSET_OBJHEADER_BRIGHTSTAR +glabel ASSET_OBJECT_BRIGHTSTAR .incbin "./build/us_1.0/assets/objects/headers/Brightstar.bin" -glabel ASSET_OBJHEADER_BUTTERFLY +glabel ASSET_OBJECT_BUTTERFLY .incbin "./build/us_1.0/assets/objects/headers/Butterfly.bin" -glabel ASSET_OBJHEADER_FISH +glabel ASSET_OBJECT_FISH .incbin "./build/us_1.0/assets/objects/headers/Fish.bin" -glabel ASSET_OBJHEADER_FROG +glabel ASSET_OBJECT_FROG .incbin "./build/us_1.0/assets/objects/headers/Frog.bin" -glabel ASSET_OBJHEADER_BOOST +glabel ASSET_OBJECT_BOOST .incbin "./build/us_1.0/assets/objects/headers/Boost.bin" -glabel ASSET_OBJHEADER_MAGNETFX +glabel ASSET_OBJECT_MAGNETFX .incbin "./build/us_1.0/assets/objects/headers/MagnetFX.bin" -glabel ASSET_OBJHEADER_STILLFROG +glabel ASSET_OBJECT_STILLFROG .incbin "./build/us_1.0/assets/objects/headers/stillfrog.bin" -glabel ASSET_OBJHEADER_STOPWATCHICON +glabel ASSET_OBJECT_STOPWATCHICON .incbin "./build/us_1.0/assets/objects/headers/stopwatchicon.bin" -glabel ASSET_OBJHEADER_STOPWATCHHAND +glabel ASSET_OBJECT_STOPWATCHHAND .incbin "./build/us_1.0/assets/objects/headers/stopwatchhand.bin" -glabel ASSET_OBJHEADER_BRIDGE +glabel ASSET_OBJECT_BRIDGE .incbin "./build/us_1.0/assets/objects/headers/bridge.bin" -glabel ASSET_OBJHEADER_POSARROW +glabel ASSET_OBJECT_POSARROW .incbin "./build/us_1.0/assets/objects/headers/posarrow.bin" -glabel ASSET_OBJHEADER_HITTESTER +glabel ASSET_OBJECT_HITTESTER .incbin "./build/us_1.0/assets/objects/headers/hittester.bin" -glabel ASSET_OBJHEADER_MIDIFADE +glabel ASSET_OBJECT_MIDIFADE .incbin "./build/us_1.0/assets/objects/headers/midifade.bin" -glabel ASSET_OBJHEADER_WINDSAIL +glabel ASSET_OBJECT_WINDSAIL .incbin "./build/us_1.0/assets/objects/headers/windsail.bin" -glabel ASSET_OBJHEADER_EFFECTBOX +glabel ASSET_OBJECT_EFFECTBOX .incbin "./build/us_1.0/assets/objects/headers/EffectBox.bin" -glabel ASSET_OBJHEADER_TROPHYCAB +glabel ASSET_OBJECT_TROPHYCAB .incbin "./build/us_1.0/assets/objects/headers/trophycab.bin" -glabel ASSET_OBJHEADER_FLYCOIN +glabel ASSET_OBJECT_FLYCOIN .incbin "./build/us_1.0/assets/objects/headers/FlyCoin.bin" -glabel ASSET_OBJHEADER_GOLDENBALLOON +glabel ASSET_OBJECT_GOLDENBALLOON .incbin "./build/us_1.0/assets/objects/headers/GoldenBalloon.bin" -glabel ASSET_OBJHEADER_LASERBOLT +glabel ASSET_OBJECT_LASERBOLT .incbin "./build/us_1.0/assets/objects/headers/laserbolt.bin" -glabel ASSET_OBJHEADER_LASERGUN +glabel ASSET_OBJECT_LASERGUN .incbin "./build/us_1.0/assets/objects/headers/lasergun.bin" -glabel ASSET_OBJHEADER_BOLTGLOW +glabel ASSET_OBJECT_BOLTGLOW .incbin "./build/us_1.0/assets/objects/headers/boltglow.bin" -glabel ASSET_OBJHEADER_GROUNDZIPPER +glabel ASSET_OBJECT_GROUNDZIPPER .incbin "./build/us_1.0/assets/objects/headers/GroundZipper.bin" -glabel ASSET_OBJHEADER_PWSAFETELEPOINT +glabel ASSET_OBJECT_PWSAFETELEPOINT .incbin "./build/us_1.0/assets/objects/headers/PWSafeTelepoint.bin" -glabel ASSET_OBJHEADER_HEADFORPOINT +glabel ASSET_OBJECT_HEADFORPOINT .incbin "./build/us_1.0/assets/objects/headers/HeadForPoint.bin" -glabel ASSET_OBJHEADER_FIREBALLATTRACT +glabel ASSET_OBJECT_FIREBALLATTRACT .incbin "./build/us_1.0/assets/objects/headers/FireballAttract.bin" -glabel ASSET_OBJHEADER_FIREBALL +glabel ASSET_OBJECT_FIREBALL .incbin "./build/us_1.0/assets/objects/headers/Fireball.bin" -glabel ASSET_OBJHEADER_OCTOBUBBLE +glabel ASSET_OBJECT_OCTOBUBBLE .incbin "./build/us_1.0/assets/objects/headers/OctoBubble.bin" -glabel ASSET_OBJHEADER_OCTOBOMB +glabel ASSET_OBJECT_OCTOBOMB .incbin "./build/us_1.0/assets/objects/headers/OctoBomb.bin" -glabel ASSET_OBJHEADER_GOLDTROPHY +glabel ASSET_OBJECT_GOLDTROPHY .incbin "./build/us_1.0/assets/objects/headers/GoldTrophy.bin" -glabel ASSET_OBJHEADER_PARKTROPHY +glabel ASSET_OBJECT_PARKTROPHY .incbin "./build/us_1.0/assets/objects/headers/Parktrophy.bin" -glabel ASSET_OBJHEADER_TICKTROPHY +glabel ASSET_OBJECT_TICKTROPHY .incbin "./build/us_1.0/assets/objects/headers/Ticktrophy.bin" -glabel ASSET_OBJHEADER_TROPHY +glabel ASSET_OBJECT_TROPHY .incbin "./build/us_1.0/assets/objects/headers/Trophy.bin" -glabel ASSET_OBJHEADER_TELEPORT +glabel ASSET_OBJECT_TELEPORT .incbin "./build/us_1.0/assets/objects/headers/Teleport.bin" -glabel ASSET_OBJHEADER_SHIELD +glabel ASSET_OBJECT_SHIELD .incbin "./build/us_1.0/assets/objects/headers/Shield.bin" -glabel ASSET_OBJHEADER_LIGHTNING +glabel ASSET_OBJECT_LIGHTNING .incbin "./build/us_1.0/assets/objects/headers/Lightning.bin" -glabel ASSET_OBJHEADER_MIDIFADEPOINT +glabel ASSET_OBJECT_MIDIFADEPOINT .incbin "./build/us_1.0/assets/objects/headers/midifadepoint.bin" -glabel ASSET_OBJHEADER_LEVELNAME +glabel ASSET_OBJECT_LEVELNAME .incbin "./build/us_1.0/assets/objects/headers/levelname.bin" -glabel ASSET_OBJHEADER_MIDICHSET +glabel ASSET_OBJECT_MIDICHSET .incbin "./build/us_1.0/assets/objects/headers/midichset.bin" -glabel ASSET_OBJECT_HEADERS_END +glabel ASSET_OBJECTS_END /********** ASSET_LEVEL_OBJECT_TRANSLATION_TABLE **********/ @@ -13283,6 +13298,7 @@ glabel ASSET_LEVEL_OBJECT_TRANSLATION_TABLE_END glabel ASSET_EMPTY_37_TABLE .word ASSET_EMPTY_37_END - ASSET_EMPTY_37 .word 0xFFFFFFFF +glabel ASSET_EMPTY_37_TABLE_END /********** ASSET_EMPTY_37 **********/ @@ -13294,6 +13310,7 @@ glabel ASSET_EMPTY_37_END .balign 16 glabel ASSET_AUDIO_TABLE +# For whatever reason, the first table entry in the audio table is not set. .word ASSET_AUDIO_1 - ASSET_AUDIO .word ASSET_AUDIO_2 - ASSET_AUDIO .word ASSET_AUDIO_3 - ASSET_AUDIO @@ -13308,37 +13325,38 @@ glabel ASSET_AUDIO_TABLE .word ASSET_AUDIO_12 - ASSET_AUDIO .word ASSET_AUDIO_END - ASSET_AUDIO .word 0xFFFFFFFF +glabel ASSET_AUDIO_TABLE_END /********** ASSET_AUDIO **********/ .balign 16 glabel ASSET_AUDIO glabel ASSET_AUDIO_0 -.incbin "./build/us_1.0/assets/audio/unknown_39_0.bin" +.incbin "./build/us_1.0/assets/audio/asset_audio_0.bin" glabel ASSET_AUDIO_1 -.incbin "./build/us_1.0/assets/audio/unknown_39_1.bin" +.incbin "./build/us_1.0/assets/audio/asset_audio_1.bin" glabel ASSET_AUDIO_2 -.incbin "./build/us_1.0/assets/audio/unknown_39_2.bin" +.incbin "./build/us_1.0/assets/audio/asset_audio_2.bin" glabel ASSET_AUDIO_3 -.incbin "./build/us_1.0/assets/audio/unknown_39_3.bin" +.incbin "./build/us_1.0/assets/audio/asset_audio_3.bin" glabel ASSET_AUDIO_4 -.incbin "./build/us_1.0/assets/audio/unknown_39_4.bin" +.incbin "./build/us_1.0/assets/audio/asset_audio_4.bin" glabel ASSET_AUDIO_5 -.incbin "./build/us_1.0/assets/audio/unknown_39_5.bin" +.incbin "./build/us_1.0/assets/audio/asset_audio_5.bin" glabel ASSET_AUDIO_6 -.incbin "./build/us_1.0/assets/audio/unknown_39_6.bin" +.incbin "./build/us_1.0/assets/audio/asset_audio_6.bin" glabel ASSET_AUDIO_7 -.incbin "./build/us_1.0/assets/audio/unknown_39_7.bin" +.incbin "./build/us_1.0/assets/audio/asset_audio_7.bin" glabel ASSET_AUDIO_8 -.incbin "./build/us_1.0/assets/audio/unknown_39_8.bin" +.incbin "./build/us_1.0/assets/audio/asset_audio_8.bin" glabel ASSET_AUDIO_9 -.incbin "./build/us_1.0/assets/audio/unknown_39_9.bin" +.incbin "./build/us_1.0/assets/audio/asset_audio_9.bin" glabel ASSET_AUDIO_10 -.incbin "./build/us_1.0/assets/audio/unknown_39_10.bin" +.incbin "./build/us_1.0/assets/audio/asset_audio_10.bin" glabel ASSET_AUDIO_11 -.incbin "./build/us_1.0/assets/audio/unknown_39_11.bin" +.incbin "./build/us_1.0/assets/audio/asset_audio_11.bin" glabel ASSET_AUDIO_12 -.incbin "./build/us_1.0/assets/audio/unknown_39_12.bin" +.incbin "./build/us_1.0/assets/audio/asset_audio_12.bin" glabel ASSET_AUDIO_END /********** ASSET_PARTICLES_TABLE **********/ @@ -13417,151 +13435,152 @@ glabel ASSET_PARTICLES_TABLE .word ASSET_PARTICLES_69 - ASSET_PARTICLES .word ASSET_PARTICLES_END - ASSET_PARTICLES .word 0xFFFFFFFF +glabel ASSET_PARTICLES_TABLE_END /********** ASSET_PARTICLES **********/ .balign 16 glabel ASSET_PARTICLES glabel ASSET_PARTICLES_0 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_0.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_0.bin" glabel ASSET_PARTICLES_1 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_1.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_1.bin" glabel ASSET_PARTICLES_2 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_2.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_2.bin" glabel ASSET_PARTICLES_3 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_3.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_3.bin" glabel ASSET_PARTICLES_4 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_4.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_4.bin" glabel ASSET_PARTICLES_5 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_5.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_5.bin" glabel ASSET_PARTICLES_6 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_6.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_6.bin" glabel ASSET_PARTICLES_7 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_7.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_7.bin" glabel ASSET_PARTICLES_8 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_8.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_8.bin" glabel ASSET_PARTICLES_9 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_9.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_9.bin" glabel ASSET_PARTICLES_10 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_10.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_10.bin" glabel ASSET_PARTICLES_11 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_11.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_11.bin" glabel ASSET_PARTICLES_12 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_12.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_12.bin" glabel ASSET_PARTICLES_13 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_13.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_13.bin" glabel ASSET_PARTICLES_14 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_14.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_14.bin" glabel ASSET_PARTICLES_15 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_15.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_15.bin" glabel ASSET_PARTICLES_16 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_16.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_16.bin" glabel ASSET_PARTICLES_17 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_17.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_17.bin" glabel ASSET_PARTICLES_18 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_18.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_18.bin" glabel ASSET_PARTICLES_19 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_19.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_19.bin" glabel ASSET_PARTICLES_20 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_20.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_20.bin" glabel ASSET_PARTICLES_21 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_21.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_21.bin" glabel ASSET_PARTICLES_22 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_22.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_22.bin" glabel ASSET_PARTICLES_23 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_23.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_23.bin" glabel ASSET_PARTICLES_24 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_24.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_24.bin" glabel ASSET_PARTICLES_25 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_25.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_25.bin" glabel ASSET_PARTICLES_26 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_26.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_26.bin" glabel ASSET_PARTICLES_27 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_27.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_27.bin" glabel ASSET_PARTICLES_28 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_28.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_28.bin" glabel ASSET_PARTICLES_29 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_29.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_29.bin" glabel ASSET_PARTICLES_30 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_30.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_30.bin" glabel ASSET_PARTICLES_31 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_31.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_31.bin" glabel ASSET_PARTICLES_32 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_32.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_32.bin" glabel ASSET_PARTICLES_33 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_33.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_33.bin" glabel ASSET_PARTICLES_34 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_34.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_34.bin" glabel ASSET_PARTICLES_35 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_35.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_35.bin" glabel ASSET_PARTICLES_36 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_36.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_36.bin" glabel ASSET_PARTICLES_37 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_37.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_37.bin" glabel ASSET_PARTICLES_38 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_38.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_38.bin" glabel ASSET_PARTICLES_39 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_39.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_39.bin" glabel ASSET_PARTICLES_40 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_40.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_40.bin" glabel ASSET_PARTICLES_41 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_41.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_41.bin" glabel ASSET_PARTICLES_42 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_42.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_42.bin" glabel ASSET_PARTICLES_43 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_43.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_43.bin" glabel ASSET_PARTICLES_44 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_44.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_44.bin" glabel ASSET_PARTICLES_45 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_45.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_45.bin" glabel ASSET_PARTICLES_46 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_46.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_46.bin" glabel ASSET_PARTICLES_47 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_47.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_47.bin" glabel ASSET_PARTICLES_48 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_48.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_48.bin" glabel ASSET_PARTICLES_49 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_49.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_49.bin" glabel ASSET_PARTICLES_50 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_50.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_50.bin" glabel ASSET_PARTICLES_51 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_51.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_51.bin" glabel ASSET_PARTICLES_52 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_52.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_52.bin" glabel ASSET_PARTICLES_53 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_53.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_53.bin" glabel ASSET_PARTICLES_54 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_54.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_54.bin" glabel ASSET_PARTICLES_55 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_55.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_55.bin" glabel ASSET_PARTICLES_56 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_56.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_56.bin" glabel ASSET_PARTICLES_57 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_57.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_57.bin" glabel ASSET_PARTICLES_58 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_58.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_58.bin" glabel ASSET_PARTICLES_59 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_59.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_59.bin" glabel ASSET_PARTICLES_60 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_60.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_60.bin" glabel ASSET_PARTICLES_61 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_61.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_61.bin" glabel ASSET_PARTICLES_62 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_62.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_62.bin" glabel ASSET_PARTICLES_63 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_63.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_63.bin" glabel ASSET_PARTICLES_64 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_64.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_64.bin" glabel ASSET_PARTICLES_65 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_65.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_65.bin" glabel ASSET_PARTICLES_66 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_66.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_66.bin" glabel ASSET_PARTICLES_67 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_67.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_67.bin" glabel ASSET_PARTICLES_68 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_68.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_68.bin" glabel ASSET_PARTICLES_69 -.incbin "./build/us_1.0/assets/particles/particles/unknown_41_69.bin" +.incbin "./build/us_1.0/assets/particles/particles/asset_particles_69.bin" glabel ASSET_PARTICLES_END /********** ASSET_PARTICLE_BEHAVIORS_TABLE **********/ @@ -13645,161 +13664,162 @@ glabel ASSET_PARTICLE_BEHAVIORS_TABLE .word ASSET_PARTICLE_BEHAVIORS_74 - ASSET_PARTICLE_BEHAVIORS .word ASSET_PARTICLE_BEHAVIORS_END - ASSET_PARTICLE_BEHAVIORS .word 0xFFFFFFFF +glabel ASSET_PARTICLE_BEHAVIORS_TABLE_END /********** ASSET_PARTICLE_BEHAVIORS **********/ .balign 16 glabel ASSET_PARTICLE_BEHAVIORS glabel ASSET_PARTICLE_BEHAVIORS_0 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_0.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_0.bin" glabel ASSET_PARTICLE_BEHAVIORS_1 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_1.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_1.bin" glabel ASSET_PARTICLE_BEHAVIORS_2 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_2.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_2.bin" glabel ASSET_PARTICLE_BEHAVIORS_3 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_3.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_3.bin" glabel ASSET_PARTICLE_BEHAVIORS_4 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_4.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_4.bin" glabel ASSET_PARTICLE_BEHAVIORS_5 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_5.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_5.bin" glabel ASSET_PARTICLE_BEHAVIORS_6 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_6.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_6.bin" glabel ASSET_PARTICLE_BEHAVIORS_7 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_7.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_7.bin" glabel ASSET_PARTICLE_BEHAVIORS_8 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_8.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_8.bin" glabel ASSET_PARTICLE_BEHAVIORS_9 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_9.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_9.bin" glabel ASSET_PARTICLE_BEHAVIORS_10 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_10.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_10.bin" glabel ASSET_PARTICLE_BEHAVIORS_11 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_11.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_11.bin" glabel ASSET_PARTICLE_BEHAVIORS_12 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_12.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_12.bin" glabel ASSET_PARTICLE_BEHAVIORS_13 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_13.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_13.bin" glabel ASSET_PARTICLE_BEHAVIORS_14 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_14.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_14.bin" glabel ASSET_PARTICLE_BEHAVIORS_15 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_15.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_15.bin" glabel ASSET_PARTICLE_BEHAVIORS_16 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_16.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_16.bin" glabel ASSET_PARTICLE_BEHAVIORS_17 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_17.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_17.bin" glabel ASSET_PARTICLE_BEHAVIORS_18 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_18.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_18.bin" glabel ASSET_PARTICLE_BEHAVIORS_19 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_19.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_19.bin" glabel ASSET_PARTICLE_BEHAVIORS_20 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_20.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_20.bin" glabel ASSET_PARTICLE_BEHAVIORS_21 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_21.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_21.bin" glabel ASSET_PARTICLE_BEHAVIORS_22 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_22.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_22.bin" glabel ASSET_PARTICLE_BEHAVIORS_23 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_23.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_23.bin" glabel ASSET_PARTICLE_BEHAVIORS_24 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_24.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_24.bin" glabel ASSET_PARTICLE_BEHAVIORS_25 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_25.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_25.bin" glabel ASSET_PARTICLE_BEHAVIORS_26 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_26.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_26.bin" glabel ASSET_PARTICLE_BEHAVIORS_27 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_27.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_27.bin" glabel ASSET_PARTICLE_BEHAVIORS_28 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_28.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_28.bin" glabel ASSET_PARTICLE_BEHAVIORS_29 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_29.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_29.bin" glabel ASSET_PARTICLE_BEHAVIORS_30 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_30.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_30.bin" glabel ASSET_PARTICLE_BEHAVIORS_31 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_31.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_31.bin" glabel ASSET_PARTICLE_BEHAVIORS_32 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_32.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_32.bin" glabel ASSET_PARTICLE_BEHAVIORS_33 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_33.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_33.bin" glabel ASSET_PARTICLE_BEHAVIORS_34 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_34.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_34.bin" glabel ASSET_PARTICLE_BEHAVIORS_35 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_35.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_35.bin" glabel ASSET_PARTICLE_BEHAVIORS_36 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_36.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_36.bin" glabel ASSET_PARTICLE_BEHAVIORS_37 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_37.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_37.bin" glabel ASSET_PARTICLE_BEHAVIORS_38 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_38.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_38.bin" glabel ASSET_PARTICLE_BEHAVIORS_39 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_39.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_39.bin" glabel ASSET_PARTICLE_BEHAVIORS_40 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_40.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_40.bin" glabel ASSET_PARTICLE_BEHAVIORS_41 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_41.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_41.bin" glabel ASSET_PARTICLE_BEHAVIORS_42 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_42.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_42.bin" glabel ASSET_PARTICLE_BEHAVIORS_43 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_43.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_43.bin" glabel ASSET_PARTICLE_BEHAVIORS_44 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_44.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_44.bin" glabel ASSET_PARTICLE_BEHAVIORS_45 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_45.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_45.bin" glabel ASSET_PARTICLE_BEHAVIORS_46 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_46.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_46.bin" glabel ASSET_PARTICLE_BEHAVIORS_47 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_47.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_47.bin" glabel ASSET_PARTICLE_BEHAVIORS_48 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_48.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_48.bin" glabel ASSET_PARTICLE_BEHAVIORS_49 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_49.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_49.bin" glabel ASSET_PARTICLE_BEHAVIORS_50 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_50.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_50.bin" glabel ASSET_PARTICLE_BEHAVIORS_51 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_51.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_51.bin" glabel ASSET_PARTICLE_BEHAVIORS_52 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_52.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_52.bin" glabel ASSET_PARTICLE_BEHAVIORS_53 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_53.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_53.bin" glabel ASSET_PARTICLE_BEHAVIORS_54 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_54.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_54.bin" glabel ASSET_PARTICLE_BEHAVIORS_55 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_55.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_55.bin" glabel ASSET_PARTICLE_BEHAVIORS_56 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_56.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_56.bin" glabel ASSET_PARTICLE_BEHAVIORS_57 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_57.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_57.bin" glabel ASSET_PARTICLE_BEHAVIORS_58 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_58.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_58.bin" glabel ASSET_PARTICLE_BEHAVIORS_59 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_59.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_59.bin" glabel ASSET_PARTICLE_BEHAVIORS_60 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_60.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_60.bin" glabel ASSET_PARTICLE_BEHAVIORS_61 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_61.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_61.bin" glabel ASSET_PARTICLE_BEHAVIORS_62 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_62.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_62.bin" glabel ASSET_PARTICLE_BEHAVIORS_63 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_63.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_63.bin" glabel ASSET_PARTICLE_BEHAVIORS_64 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_64.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_64.bin" glabel ASSET_PARTICLE_BEHAVIORS_65 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_65.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_65.bin" glabel ASSET_PARTICLE_BEHAVIORS_66 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_66.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_66.bin" glabel ASSET_PARTICLE_BEHAVIORS_67 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_67.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_67.bin" glabel ASSET_PARTICLE_BEHAVIORS_68 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_68.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_68.bin" glabel ASSET_PARTICLE_BEHAVIORS_69 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_69.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_69.bin" glabel ASSET_PARTICLE_BEHAVIORS_70 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_70.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_70.bin" glabel ASSET_PARTICLE_BEHAVIORS_71 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_71.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_71.bin" glabel ASSET_PARTICLE_BEHAVIORS_72 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_72.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_72.bin" glabel ASSET_PARTICLE_BEHAVIORS_73 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_73.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_73.bin" glabel ASSET_PARTICLE_BEHAVIORS_74 -.incbin "./build/us_1.0/assets/particles/behaviors/unknown_43_74.bin" +.incbin "./build/us_1.0/assets/particles/behaviors/asset_particle_behaviors_74.bin" glabel ASSET_PARTICLE_BEHAVIORS_END /********** ASSET_FONTS **********/ @@ -13813,37 +13833,37 @@ glabel ASSET_FONTS_END .balign 16 glabel ASSET_BINARY_45 -.incbin "./build/us_1.0/assets/fonts/unknown_45.bin" +.incbin "./build/us_1.0/assets/fonts/asset_binary_45.bin" glabel ASSET_BINARY_45_END /********** ASSET_BINARY_46 **********/ .balign 16 glabel ASSET_BINARY_46 -.incbin "./build/us_1.0/assets/fonts/unknown_46.bin" +.incbin "./build/us_1.0/assets/fonts/asset_binary_46.bin" glabel ASSET_BINARY_46_END /********** ASSET_BINARY_47 **********/ .balign 16 glabel ASSET_BINARY_47 -.incbin "./build/us_1.0/assets/ids/unknown_47.bin" +.incbin "./build/us_1.0/assets/ids/asset_binary_47.bin" glabel ASSET_BINARY_47_END /********** ASSET_TTGHOSTS_TABLE **********/ .balign 16 glabel ASSET_TTGHOSTS_TABLE -.word 0x3000000, ASSET_TTGHOSTS_FOSSILCANYON - ASSET_TTGHOSTS -.word 0x4010000, ASSET_TTGHOSTS_PIRATELAGOON - ASSET_TTGHOSTS -.word 0x5000000, ASSET_TTGHOSTS_ANCIENTLAKE - ASSET_TTGHOSTS -.word 0x6000000, ASSET_TTGHOSTS_WALRUSCOVE - ASSET_TTGHOSTS -.word 0x7020000, ASSET_TTGHOSTS_HOTTOPVOLCANO - ASSET_TTGHOSTS -.word 0x8010000, ASSET_TTGHOSTS_WHALEBAY - ASSET_TTGHOSTS -.word 0x9000000, ASSET_TTGHOSTS_SNOWBALLVALLEY - ASSET_TTGHOSTS -.word 0xA000000, ASSET_TTGHOSTS_CRESCENTISLAND - ASSET_TTGHOSTS -.word 0xD020000, ASSET_TTGHOSTS_EVERFROSTPEAK - ASSET_TTGHOSTS -.word 0xF020000, ASSET_TTGHOSTS_SPACEPORTALPHA - ASSET_TTGHOSTS +.word 0x03000000, ASSET_TTGHOSTS_FOSSILCANYON - ASSET_TTGHOSTS +.word 0x04010000, ASSET_TTGHOSTS_PIRATELAGOON - ASSET_TTGHOSTS +.word 0x05000000, ASSET_TTGHOSTS_ANCIENTLAKE - ASSET_TTGHOSTS +.word 0x06000000, ASSET_TTGHOSTS_WALRUSCOVE - ASSET_TTGHOSTS +.word 0x07020000, ASSET_TTGHOSTS_HOTTOPVOLCANO - ASSET_TTGHOSTS +.word 0x08010000, ASSET_TTGHOSTS_WHALEBAY - ASSET_TTGHOSTS +.word 0x09000000, ASSET_TTGHOSTS_SNOWBALLVALLEY - ASSET_TTGHOSTS +.word 0x0A000000, ASSET_TTGHOSTS_CRESCENTISLAND - ASSET_TTGHOSTS +.word 0x0D020000, ASSET_TTGHOSTS_EVERFROSTPEAK - ASSET_TTGHOSTS +.word 0x0F020000, ASSET_TTGHOSTS_SPACEPORTALPHA - ASSET_TTGHOSTS .word 0x11020000, ASSET_TTGHOSTS_SPACEDUSTALLEY - ASSET_TTGHOSTS .word 0x12000000, ASSET_TTGHOSTS_GREENWOODVILLAGE - ASSET_TTGHOSTS .word 0x13010000, ASSET_TTGHOSTS_BOULDERCANYON - ASSET_TTGHOSTS @@ -13856,6 +13876,7 @@ glabel ASSET_TTGHOSTS_TABLE .word 0x21000000, ASSET_TTGHOSTS_STARCITY - ASSET_TTGHOSTS .word 0xFFFF0000, ASSET_TTGHOSTS_END - ASSET_TTGHOSTS .word 0xFFFF0000, 0xFFFFFFFF +glabel ASSET_TTGHOSTS_TABLE_END /********** ASSET_TTGHOSTS **********/ diff --git a/asm/assets/ucode_data.s b/asm/assets/ucode_data.s index 0f4da3be..d90cbc84 100644 --- a/asm/assets/ucode_data.s +++ b/asm/assets/ucode_data.s @@ -1,14 +1,14 @@ -# This file was generated by generate_ld.py +# This file is automatically generated. Any changes you make to this file will get overwritten. .include "macros.inc" glabel aspMainDataStart -.incbin "./build/us_1.0/ucode/data_audio.bin" +.incbin "build/us_1.0/ucode/data_audio.bin" glabel rspF3DDKRDataDramStart -.incbin "./build/us_1.0/ucode/data_f3ddkr_dram.bin" +.incbin "build/us_1.0/ucode/data_f3ddkr_dram.bin" glabel rspF3DDKRDataFifoStart -.incbin "./build/us_1.0/ucode/data_f3ddkr_fifo.bin" +.incbin "build/us_1.0/ucode/data_f3ddkr_fifo.bin" glabel rspF3DDKRDataXbusStart -.incbin "./build/us_1.0/ucode/data_f3ddkr_xbus.bin" +.incbin "build/us_1.0/ucode/data_f3ddkr_xbus.bin" glabel rspUnknown2DataStart -.incbin "./build/us_1.0/ucode/data_unknown_2.bin" +.incbin "build/us_1.0/ucode/data_unknown_2.bin" diff --git a/asm/assets/ucode_text.s b/asm/assets/ucode_text.s index d014c215..ba321751 100644 --- a/asm/assets/ucode_text.s +++ b/asm/assets/ucode_text.s @@ -1,16 +1,16 @@ -# This file was generated by generate_ld.py +# This file is automatically generated. Any changes you make to this file will get overwritten. .include "macros.inc" glabel aspMainTextStart -.incbin "./build/us_1.0/ucode/ucode_audio.bin" +.incbin "build/us_1.0/ucode/ucode_audio.bin" glabel rspF3DDKRBootStart -.incbin "./build/us_1.0/ucode/ucode_boot.bin" +.incbin "build/us_1.0/ucode/ucode_boot.bin" glabel rspF3DDKRDramStart -.incbin "./build/us_1.0/ucode/ucode_f3ddkr_dram.bin" +.incbin "build/us_1.0/ucode/ucode_f3ddkr_dram.bin" glabel rspF3DDKRFifoStart -.incbin "./build/us_1.0/ucode/ucode_f3ddkr_fifo.bin" +.incbin "build/us_1.0/ucode/ucode_f3ddkr_fifo.bin" glabel rspF3DDKRXbusStart -.incbin "./build/us_1.0/ucode/ucode_f3ddkr_xbus.bin" +.incbin "build/us_1.0/ucode/ucode_f3ddkr_xbus.bin" glabel rspUnknown2Start -.incbin "./build/us_1.0/ucode/ucode_unknown_2.bin" +.incbin "build/us_1.0/ucode/ucode_unknown_2.bin" diff --git a/asm/boot/boot.bin b/asm/boot/boot.bin new file mode 100644 index 0000000000000000000000000000000000000000..43e6e2f510cd3d2bd049ddfe98af752e33d95e04 GIT binary patch literal 4032 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 = (Object_64 *) ((s32) get_misc_asset(ASSET_MISC_20) + (entry->unk8[0] << 7)); obj->segment.level_entry = NULL; } diff --git a/src/object_functions.h b/src/object_functions.h index 4f2b1cb3..fcdd33a7 100644 --- a/src/object_functions.h +++ b/src/object_functions.h @@ -346,7 +346,7 @@ void obj_init_wavegenerator(Object *obj, LevelObjectEntry_WaveGenerator *entry, void obj_init_midichset(Object *obj, LevelObjectEntry_Midichset *entry); void obj_init_bubbler(Object *obj, LevelObjectEntry_Bubbler *entry); void obj_loop_bubbler(Object *obj, s32 updateRate); -void obj_init_boost(Object *obj, LevelObjectEntry_Boost *entry); +void obj_init_boost(Object *obj, LevelObjectEntry_Boost2 *entry); void obj_init_unknown94(Object *obj, LevelObjectEntry_Unknown94 *entry, s32 arg2); void obj_loop_unknown94(Object *obj, s32 updateRate); void obj_init_rangetrigger(Object *obj, LevelObjectEntry_RangeTrigger *entry); diff --git a/tools/Makefile b/tools/Makefile index 97165c8d..d562bd75 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -1,11 +1,16 @@ + +OPT := -O2 + CC := gcc CXX := g++ -CFLAGS := -I . -Wall -Wextra -Wno-unused-parameter -pedantic -std=c99 -O2 -s -CXXFLAGS := -I . -Wall -Wextra -std=c++17 +CFLAGS := -I . -Wall -Wextra -Wno-unused-parameter -pedantic -std=c99 $(OPT) -s +# List of specific errors to ignore +IGNORE_W_ERRORS := -Wno-unused-parameter -Wno-misleading-indentation -Wno-extra +CXXFLAGS := -I . -I dkr_assets_tool_src/ -Werror -Wall $(IGNORE_W_ERRORS) -std=c++17 $(OPT) -lpcre2-8 LDFLAGS := -lm PROGRAMS := n64crc dkr_assets_tool -BUILD_DIR := dkr_assets_tool_classes/_build +BUILD_DIR := dkr_assets_tool_src/_build ENUMS_HEADER := ../include/enums.h @@ -29,10 +34,9 @@ distclean: clean n64crc: n64crc.c $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) -dkr_assets_tool_CPP_FILES := dkr_assets_tool.cpp \ - $(call rwildcard,dkr_assets_tool_classes,*.cpp) +dkr_assets_tool_CPP_FILES := $(call rwildcard,dkr_assets_tool_src,*.cpp) -dkr_assets_tool_C_FILES := $(call rwildcard,dkr_assets_tool_classes,*.c) +dkr_assets_tool_C_FILES := $(call rwildcard,dkr_assets_tool_src,*.c) dkr_assets_tool_OBJ_FILES := $(foreach file,$(dkr_assets_tool_C_FILES),$(BUILD_DIR)/$(file:.c=.o)) \ $(foreach file,$(dkr_assets_tool_CPP_FILES),$(BUILD_DIR)/$(file:.cpp=.o)) diff --git a/tools/dkr_assets_tool.cpp b/tools/dkr_assets_tool.cpp deleted file mode 100644 index d6aff52c..00000000 --- a/tools/dkr_assets_tool.cpp +++ /dev/null @@ -1,204 +0,0 @@ -/** - * This tool handles everything assets-related including extracting and building. - */ - -#include -#include -#include - -#include "dkr_assets_tool_classes/common/util.h" -#include "dkr_assets_tool_classes/extractor/extractor.h" -#include "dkr_assets_tool_classes/builder/builder.h" -#include "dkr_assets_tool_classes/make_asset_files/asset_enums_header.h" -#include "dkr_assets_tool_classes/make_asset_files/asset_asm_data.h" -#include "dkr_assets_tool_classes/compiler/compiler.h" - -/**************************************************************************/ - -void print_usage() { - std::cout << "---- Usages -------------------------------------------------------------" << std::endl; - std::cout << "Extracting assets: ./dkr_assets_tool -e " << std::endl; - std::cout << "Building an asset: ./dkr_assets_tool -b " << std::endl; - std::cout << "Build enums cache: ./dkr_assets_tool -bc " << std::endl; - std::cout << "Creating includes: ./dkr_assets_tool -i " << std::endl; - std::cout << "Compiling assets: ./dkr_assets_tool -c " << std::endl; - std::cout << "Compress file: ./dkr_assets_tool -fc " << std::endl; - std::cout << "Decompress file: ./dkr_assets_tool -fd " << std::endl; - std::cout << "-------------------------------------------------------------------------" << std::endl; -} - -/**************************************************************************/ - -struct Command { - std::string flag; - int args; - void (*func)(const std::vector&); -}; - -void extract(const std::vector& args); -void build(const std::vector& args); -void asset_includes(const std::vector& args); -void asset_compile(const std::vector& args); -void asset_compress(const std::vector& args); -void asset_decompress(const std::vector& args); -void build_enums_cache(const std::vector& args); - -static const std::vector COMMANDS = { - // Extract - { - .flag = "-e", - .args = 5, - .func = &extract, - }, - // Build - { - .flag = "-b", - .args = 4, - .func = build, - }, - // Build enums cache - { - .flag = "-bc", - .args = 2, - .func = build_enums_cache, - }, - // Asset includes - { - .flag = "-i", - .args = 5, - .func = asset_includes, - }, - // Asset compile - { - .flag = "-c", - .args = 2, - .func = asset_compile, - }, - // Asset compress file - { - .flag = "-fc", - .args = 2, - .func = asset_compress, - }, - // Asset decompress file - { - .flag = "-fd", - .args = 2, - .func = asset_decompress, - }, -}; - -void extract(const std::vector& args) { - std::string version = args[0]; // us_1.0 - std::string assetsDir = args[1]; // /assets - std::string configsPath = args[2]; // /extract-ver - std::string baseromsPath = args[3]; // /baseroms - std::string outputPath = args[4]; // - - set_assets_folder_path(assetsDir + "/vanilla"); - set_version(version); - - Extractor extractor(version, configsPath, baseromsPath, outputPath); -} - -void build(const std::vector& args) { - std::string version = args[0]; // us_1.0 - std::string assetsDir = args[1]; // /assets - std::string sourcePath = args[2]; // Input .json filepath - std::string outputPath = args[3]; // Output .bin filepath - - set_assets_folder_path(assetsDir); - set_version(version); - - Builder builder(sourcePath, outputPath); -} - -void asset_includes(const std::vector& args) { - std::string version = args[0]; // us_1.0 - std::string assetsDir = args[1]; // /assets - std::string includeDir = args[2]; // /include - std::string buildDir = args[3]; // /build - std::string assetsAsmDir = args[4]; // /asm/assets - - set_assets_folder_path(assetsDir); - set_version(version); - - AssetEnumsHeader assetEnumsHeader(includeDir); - AssetAsmIncludes assetAsmIncludes(assetsDir + "/" + version, buildDir + "/" + version + "/assets", assetsAsmDir); -} - -void asset_compile(const std::vector& args) { - std::string version = args[0]; // us_1.0 - std::string assetsDir = args[1]; // /assets - - set_assets_folder_path(assetsDir); - set_version(version); - - AssetCompiler compiler; -} - -void asset_compress(const std::vector& args) { - DKRCompression compression; - std::string inputFilename = args[0]; - std::string outputFilename = args[1]; - std::vector inputBinary, outputBinary; - - if(compression.readBinaryFile(inputBinary, inputFilename)) { - if(inputBinary.size() == 0) { - compression.writeBinaryFile(inputBinary, outputFilename); - } else { - outputBinary = compression.compressBuffer(inputBinary); - compression.writeBinaryFile(outputBinary, outputFilename); - } - } else { - display_error_and_abort("Could not read file: ", inputFilename); - } -} - -void asset_decompress(const std::vector& args) { - DKRCompression compression; - std::string inputFilename = args[0]; - std::string outputFilename = args[1]; - std::vector inputBinary, outputBinary; - - if(compression.readBinaryFile(inputBinary, inputFilename)) { - if(inputBinary.size() == 0) { - compression.writeBinaryFile(inputBinary, outputFilename); - } else { - outputBinary = compression.decompressBuffer(inputBinary); - compression.writeBinaryFile(outputBinary, outputFilename); - } - } else { - display_error_and_abort("Could not read file: ", inputFilename); - } -} - -void build_enums_cache(const std::vector& args) { - std::string version = args[0]; // us_1.0 - std::string enumsHeaderPath = args[1]; // /include/enums.h - - set_version(version); - generate_enums_cache(enumsHeaderPath); -} - -int main(int argc, char *argv[]) { - if (argc == 1) { - print_usage(); - return 1; - } - std::string flag = argv[1]; - auto it = std::find_if(COMMANDS.begin(), COMMANDS.end(), [&flag](const Command& cmd) { - return cmd.flag == flag; - }); - if (it == COMMANDS.end()) { - print_usage(); - return 1; - } - if (argc - 2 != it->args) { - display_error_and_abort("Expected ", it->args, " args but was given ", argc - 2, "."); - return 1; - } - std::vector args(argv + 2, argv + argc); - it->func(args); - return 0; -} diff --git a/tools/dkr_assets_tool_classes/builder/build_files/build_fonts.cpp b/tools/dkr_assets_tool_classes/builder/build_files/build_fonts.cpp deleted file mode 100644 index f043a515..00000000 --- a/tools/dkr_assets_tool_classes/builder/build_files/build_fonts.cpp +++ /dev/null @@ -1,137 +0,0 @@ -#include "build_fonts.h" - -#define SIZEOF_FONTS_HEADER 4 - -// Note that these are just for DKR afaik. Other rare games have different sizes. -#define SIZEOF_FONT 0x400 // Larger in later Rare games -#define MAX_NUMBER_OF_TEXTURES 32 // Extended to 64 in later Rare games -#define CHAR_NODE_START_OFFSET 32 -#define NUMBER_OF_CHAR_NODES 96 // Extended to 224 in later Rare games -#define CHAR_NODE_END_OFFSET CHAR_NODE_START_OFFSET + NUMBER_OF_CHAR_NODES -#define SIZEOF_CHAR_NODE 8 - -BuildFonts::BuildFonts(std::string srcPath, std::string dstPath) { - - std::string fontFolderPath = get_directory_from_full_path(srcPath); - - std::vector fontIds = get_array_from_section("ASSET_FONTS", "fonts-order"); - int numberOfFonts = fontIds.size(); - - std::vector out(align16(SIZEOF_FONT * numberOfFonts + SIZEOF_FONTS_HEADER)); - - // Write header. - write_big_endian_word(out, 0, numberOfFonts); - - // Write fonts. - for(int font = 0; font < numberOfFonts; font++) { - std::string fontPath = fontFolderPath + "/" + get_string_from_json(srcPath, "fonts", fontIds[font]); - - int fontOffset = font * SIZEOF_FONT + SIZEOF_FONTS_HEADER; - - insert_ascii(out, fontOffset, get_string_from_json(fontPath, "name")); - write_big_endian_halfword(out, fontOffset + 0x20, get_int_from_json(fontPath, "fixed-width")); - write_big_endian_halfword(out, fontOffset + 0x22, get_int_from_json(fontPath, "y-offset")); - write_big_endian_halfword(out, fontOffset + 0x24, get_int_from_json(fontPath, "special-character-width")); - write_big_endian_halfword(out, fontOffset + 0x26, get_int_from_json(fontPath, "tab-width")); - insert_ascii(out, fontOffset + 0x28, get_string_from_json(fontPath, "unknown-text")); - - int numberOfTextures = get_array_length_from_json(fontPath, "textures"); - int texOffset = fontOffset + 0x40; - int texIndex = 0; - // Write texture ids. - for(; texIndex < numberOfTextures; texIndex++) { - write_big_endian_halfword(out, texOffset, get_tex_2d_index_from_build_id(get_string_from_json(fontPath, "textures", texIndex))); - texOffset += 2; - } - // Fill rest of the space with -1. - for(; texIndex < MAX_NUMBER_OF_TEXTURES; texIndex++) { - write_big_endian_halfword(out, texOffset, -1); - texOffset += 2; - } - - std::string encoding = get_string_from_json(fontPath, "encoding", "type"); - make_uppercase(encoding); - - bool uppercaseOnly = false; - - if(json_has_key(fontPath, "uppercase-only")) { - uppercaseOnly = get_bool_from_json(fontPath, "uppercase-only"); - } - - // Write character nodes - if(encoding == "ASCII") { - write_ascii_char_nodes(out, fontPath, fontOffset + 0x100, uppercaseOnly); - } else if(encoding == "CUSTOM") { - write_custom_char_nodes(out, fontPath, fontOffset + 0x100, uppercaseOnly); - } else { - display_error_and_abort("Unsupported font encoding type: \"", encoding, "\""); - } - - } - - write_binary_file(out, dstPath); -} - -BuildFonts::~BuildFonts() { - -} - -void write_char_node(std::vector &out, std::string fontPath, int nodeOffset, std::string &chr) { - if(json_has_key(fontPath, "characters", chr)) { - out[nodeOffset] = get_int_from_json(fontPath, "characters", chr, "tex-index"); - out[nodeOffset + 1] = get_int_from_json(fontPath, "characters", chr, "char-width"); - out[nodeOffset + 2] = get_int_from_json(fontPath, "characters", chr, "offset", 0); // X offset - out[nodeOffset + 3] = get_int_from_json(fontPath, "characters", chr, "offset", 1); // Y offset - out[nodeOffset + 4] = get_int_from_json(fontPath, "characters", chr, "uv", 0); // U coordinate - out[nodeOffset + 5] = get_int_from_json(fontPath, "characters", chr, "uv", 1); // V coordinate - out[nodeOffset + 6] = get_int_from_json(fontPath, "characters", chr, "tex-size", 0); // Width - out[nodeOffset + 7] = get_int_from_json(fontPath, "characters", chr, "tex-size", 1); // Height - } else { // Node doesn't exist, so just mark it as empty. - out[nodeOffset] = -1; - out[nodeOffset + 1] = 0; - out[nodeOffset + 2] = 0; - out[nodeOffset + 3] = 0; - out[nodeOffset + 4] = 0; - out[nodeOffset + 5] = 0; - out[nodeOffset + 6] = 0; - out[nodeOffset + 7] = 0; - } -} - -void BuildFonts::write_ascii_char_nodes(std::vector &out, std::string fontPath, int offset, bool uppercaseOnly) { - for(int node = CHAR_NODE_START_OFFSET; node < CHAR_NODE_END_OFFSET; node++) { - std::string chr; - if(node == 127) { - chr = "DEL"; // Special case because the delete character itself is sometimes weird. - } else if (node == 92) { - chr = "\\\\"; - } else if (node == 34) { - chr = "\\\""; - } else { - chr = (char)node; - } - int nodeOffset = offset + (node - CHAR_NODE_START_OFFSET) * SIZEOF_CHAR_NODE; - if(uppercaseOnly && node >= (int)'a' && node <= (int)'z') { - make_uppercase(chr); - } - write_char_node(out, fontPath, nodeOffset, chr); - } -} - -void BuildFonts::write_custom_char_nodes(std::vector &out, std::string fontPath, int offset, bool uppercaseOnly) { - int index = 0; - std::vector order = get_array_from_json(fontPath, "encoding", "order"); - for(std::string &chr : order) { - if(index >= NUMBER_OF_CHAR_NODES) { - std::string fontName = get_string_from_json(fontPath, "name"); - display_error_and_abort("Too many character nodes in ", fontName, ". The limit is ", NUMBER_OF_CHAR_NODES); - } - int nodeOffset = offset + (index++ * SIZEOF_CHAR_NODE); - write_char_node(out, fontPath, nodeOffset, chr); - } - // Set the rest of the nodes to show nothing. - while(index < NUMBER_OF_CHAR_NODES) { - int nodeOffset = offset + (index++ * SIZEOF_CHAR_NODE); - out[nodeOffset] = -1; - } -} diff --git a/tools/dkr_assets_tool_classes/builder/build_files/build_fonts.h b/tools/dkr_assets_tool_classes/builder/build_files/build_fonts.h deleted file mode 100644 index c5a7b243..00000000 --- a/tools/dkr_assets_tool_classes/builder/build_files/build_fonts.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include "../../common/util.h" -//#include "macros.h" - -class BuildFonts { -public: - BuildFonts(std::string srcPath, std::string dstPath); - ~BuildFonts(); -private: - void write_ascii_char_nodes(std::vector &out, std::string srcPath, int offset, bool uppercaseOnly); - void write_custom_char_nodes(std::vector &out, std::string srcPath, int offset, bool uppercaseOnly); -}; diff --git a/tools/dkr_assets_tool_classes/builder/build_files/build_gametext.cpp b/tools/dkr_assets_tool_classes/builder/build_files/build_gametext.cpp deleted file mode 100644 index 9a2c70c0..00000000 --- a/tools/dkr_assets_tool_classes/builder/build_files/build_gametext.cpp +++ /dev/null @@ -1,133 +0,0 @@ -#include "build_gametext.h" - -// Dialog -#define END_OF_LINES 0x00 -#define ACTIVE_LINE 0x01 -#define CONTINUE 0x0C - -// Textbox -#define NEXT_PAGE 0x01 - -BuildGameText::BuildGameText(std::string srcPath, std::string dstPath) { - std::vector out; - - - // TODO: Figure this out! - - std::string textType = get_string_from_json(srcPath, "text-type"); - if(textType == "Dialog") { - // This is temporary until the game text format is figured out - int numRawBytes = get_array_length_from_json(srcPath, "raw"); - - for(int i = 0; i < numRawBytes; i++) { - out.push_back(get_int_from_json(srcPath, "raw", i)); - } - //build_dialog(out, srcPath); - } else { - build_textbox(out, srcPath); - } - - - while(out.size() % 8 != 0) { - out.push_back(0); // Make sure the data is 8-byte aligned. - } - - - write_binary_file(out, dstPath); -} - -BuildGameText::~BuildGameText() { - -} - -/* -void BuildGameText::build_dialog(std::vector &out, std::string &srcPath) { - int numberOfLines = GET_ARRAY_LENGTH("lines"); - for(int i = 0; i < numberOfLines; i++) { - if(inputJSON["lines"][i].JSONType() == json::JSON::Class::String) { - out.push_back(CONTINUE); - continue; - } - if(HAS_KEY("unknown-data", "lines", i)) { // Check if the key "unknown-data" exists. - for(int j = 0; j < GET_ARRAY_LENGTH("lines", i, "unknown-data"); j++) { - out.push_back(get_int_from_json(srcPath, "lines", i, "unknown-data", j)); - } - break; - } - out.push_back(ACTIVE_LINE); - out.push_back(get_int_from_json(srcPath, "lines", i, "color", "red")); - out.push_back(get_int_from_json(srcPath, "lines", i, "color", "green")); - out.push_back(get_int_from_json(srcPath, "lines", i, "color", "blue")); - out.push_back(get_int_from_json(srcPath, "lines", i, "color", "alpha")); - out.push_back(get_int_from_json(srcPath, "lines", i, "font")); - out.push_back(get_int_from_json(srcPath, "lines", i, "alignment")); - out.push_back((uint8_t)(GET_FLOAT("lines", i, "time") * 5)); - write_ascii(out, get_string_from_json(srcPath, "lines", i, "text")); - //if(i < numberOfLines - 1 && !HAS_KEY("unknown-data", "lines", i + 1)) { - // out.push_back(CONTINUE); - //} - } -} -*/ - -void write_basic_command(std::vector &out, uint8_t cmdId, uint8_t value) { - out.push_back(cmdId); - out.push_back(value); -} - -void write_basic_command_4_args(std::vector &out, uint8_t cmdId, uint8_t a, uint8_t b, uint8_t c, uint8_t d) { - out.push_back(cmdId); - out.push_back(a); - out.push_back(b); - out.push_back(c); - out.push_back(d); -} - -void BuildGameText::build_textbox(std::vector &out, std::string &srcPath) { - int numberOfPages = get_array_length_from_json(srcPath, "pages"); - for(int page = 0; page < numberOfPages; page++) { - int numberOfCommandsInPage = get_array_length_from_json(srcPath, "pages", page); - for(int cmd = 0; cmd < numberOfCommandsInPage; cmd++) { - std::string cmdType = get_string_from_json(srcPath, "pages", page, cmd, "command"); - if(cmdType == "Text") { - write_ascii(out, get_string_from_json(srcPath, "pages", page, cmd, "value")); - } else if(cmdType == "SetFont") { - std::string fontId = get_string_from_json(srcPath, "pages", page, cmd, "value"); - int fontIndex = get_index_of_string_array_value_from_section("ASSET_FONTS", fontId, "fonts-order"); - if(fontIndex == -1) { - display_error_and_abort("Could not find the font \"", fontId, "\" in the \"fonts-order\" array in asset_fonts.json."); - } - write_basic_command(out, 3, fontIndex); - } else if(cmdType == "SetBorder") { - write_basic_command_4_args(out, 4, - get_int_from_json(srcPath, "pages", page, cmd, "value", "left"), - get_int_from_json(srcPath, "pages", page, cmd, "value", "top"), - get_int_from_json(srcPath, "pages", page, cmd, "value", "right"), - get_int_from_json(srcPath, "pages", page, cmd, "value", "bottom") - ); - } else if(cmdType == "SetColour") { - write_basic_command_4_args(out, 5, - get_int_from_json(srcPath, "pages", page, cmd, "value", "red"), - get_int_from_json(srcPath, "pages", page, cmd, "value", "green"), - get_int_from_json(srcPath, "pages", page, cmd, "value", "blue"), - get_int_from_json(srcPath, "pages", page, cmd, "value", "alpha") - ); - } else if(cmdType == "SetAlignment") { - write_basic_command(out, 6, get_string_from_json(srcPath, "pages", page, cmd, "value") == "center" ? 0 : 4); - } else if(cmdType == "Unknown") { - write_basic_command(out, 7, get_int_from_json(srcPath, "pages", page, cmd, "value")); - } else if(cmdType == "AddVerticalSpacing") { - write_basic_command(out, 8, get_int_from_json(srcPath, "pages", page, cmd, "value")); - } else if(cmdType == "SetLineHeight") { - write_basic_command(out, 9, get_int_from_json(srcPath, "pages", page, cmd, "value")); - } else if(cmdType == "SetTimer") { - write_basic_command(out, 10, get_int_from_json(srcPath, "pages", page, cmd, "value")); - } else if(cmdType == "AllowUserInput") { - write_basic_command(out, 11, get_bool_from_json(srcPath, "pages", page, cmd, "value") ? 1 : 0); - } - } - if(page < numberOfPages - 1) { - out.push_back(NEXT_PAGE); - } - } -} diff --git a/tools/dkr_assets_tool_classes/builder/build_files/build_gametext.h b/tools/dkr_assets_tool_classes/builder/build_files/build_gametext.h deleted file mode 100644 index d8a3cbbb..00000000 --- a/tools/dkr_assets_tool_classes/builder/build_files/build_gametext.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include "../../common/util.h" - -class BuildGameText { -public: - BuildGameText(std::string srcPath, std::string dstPath); - ~BuildGameText(); -private: - /* - void build_dialog(std::vector &out, std::string &srcPath); - */ - void build_textbox(std::vector &out, std::string &srcPath); -}; diff --git a/tools/dkr_assets_tool_classes/builder/build_files/build_levelheader.cpp b/tools/dkr_assets_tool_classes/builder/build_files/build_levelheader.cpp deleted file mode 100644 index 0f741f83..00000000 --- a/tools/dkr_assets_tool_classes/builder/build_files/build_levelheader.cpp +++ /dev/null @@ -1,116 +0,0 @@ -#include "build_levelheader.h" - -#define GET_UNKNOWN_VALUE(name, index) get_int_from_json(srcPath, "unknown-data", name, index) -#define GET_UNKNOWN_VALUES(out, start, end, name) \ - for(int i = start; i < end; i++) { \ - out[i] = GET_UNKNOWN_VALUE(name, i - start); \ - } - -int get_bitfield_from_enum_values(std::string &srcPath, std::string propertyName, std::string enumName) { - int numEntries = get_array_length_from_json(srcPath, propertyName); - int out = 0; - for(int i = 0; i < numEntries; i++) { - out |= 1 << get_enum_value_from_string(enumName, get_string_from_json(srcPath, propertyName, i)); - } - return out; -} - -BuildLevelHeader::BuildLevelHeader(std::string srcPath, std::string dstPath) { - std::vector out(SIZEOF_LEVEL_HEADER); - - // World ID - out[0] = get_enum_value_from_string("World", get_string_from_json(srcPath, "world")); - - out[1] = get_int_from_json(srcPath, "unknown-data", "unk1"); - out[2] = get_int_from_json(srcPath, "unknown-data", "unk2"); - out[3] = get_int_from_json(srcPath, "unknown-data", "unk3"); - GET_UNKNOWN_VALUES(out, 4, 8, "unk4"); - - // Ceiling height for planes - write_big_endian_float(out, 8, get_float_from_json(srcPath, "ceiling-height")); - - GET_UNKNOWN_VALUES(out, 0xC, 0x34, "unkC"); - - // Track ID to use - write_big_endian_halfword(out, 0x34, get_index_from_build_id("ASSET_LEVEL_MODELS", get_string_from_json(srcPath, "model"))); - - // Collectables bitflags (bananas, balloons, etc) - write_big_endian_halfword(out, 0x36, get_int_from_json(srcPath, "collectables")); - - // Skydome object model ID - write_big_endian_halfword(out, 0x38, get_int_from_json(srcPath, "skybox")); - - // Fog - write_big_endian_halfword(out, 0x3A, get_int_from_json(srcPath, "fog", "range", "min")); - write_big_endian_halfword(out, 0x3C, get_int_from_json(srcPath, "fog", "range", "max")); - write_big_endian_halfword(out, 0x3E, get_int_from_json(srcPath, "fog", "colour", "red")); - write_big_endian_halfword(out, 0x40, get_int_from_json(srcPath, "fog", "colour", "green")); - write_big_endian_halfword(out, 0x42, get_int_from_json(srcPath, "fog", "colour", "blue")); - - GET_UNKNOWN_VALUES(out, 0x44, 0x4B, "unk44"); - - // Number of laps to complete the race. - out[0x4B] = get_int_from_json(srcPath, "number-laps"); - - // Type of race (standard, boss race, hub world, etc. - out[0x4C] = get_enum_value_from_string("RaceType", get_string_from_json(srcPath, "race-type")); - - // Default vehicle used for this track. (Either Car, Hovercraft, or Plane) - out[0x4D] = get_enum_value_from_string("Vehicle", get_string_from_json(srcPath, "default-vehicle")); - - // Which vehicles can be used in this track (Either Car, Hovercraft, or Plane) - out[0x4E] = get_bitfield_from_enum_values(srcPath, "available-vehicles", "Vehicle"); - GET_UNKNOWN_VALUES(out, 0x4F, 0x52, "unk4F"); - - // Music ID to use for this track - out[0x52] = get_int_from_json(srcPath, "music"); - - // Unknown, but *probably* related to audio. - out[0x53] = get_int_from_json(srcPath, "unknown-data", "unk53"); - - // Instruments bitflags. Most levels have 0xFFFF, except for the central hub which is 0xB - write_big_endian_halfword(out, 0x54, get_int_from_json(srcPath, "instruments")); - - GET_UNKNOWN_VALUES(out, 0x56, 0x74, "unk56"); - for(int i = 0; i < 7; i++) { - write_big_endian_word(out, 0x74 + (i * 4), get_int_from_json(srcPath, "unknown-data", "unk74", i)); - } - - // Weather values currently unknown. - write_big_endian_halfword(out, 0x90, get_int_from_json(srcPath, "unknown-data", "weather", "particle-density")); - write_big_endian_halfword(out, 0x92, get_int_from_json(srcPath, "unknown-data", "weather", "type")); - out[0x94] = get_int_from_json(srcPath, "unknown-data", "weather", "intensity"); - out[0x95] = get_int_from_json(srcPath, "unknown-data", "weather", "opacity"); - write_big_endian_halfword(out, 0x96, get_int_from_json(srcPath, "unknown-data", "weather", "x-velocity")); - write_big_endian_halfword(out, 0x98, get_int_from_json(srcPath, "unknown-data", "weather", "y-velocity")); - write_big_endian_halfword(out, 0x9A, get_int_from_json(srcPath, "unknown-data", "weather", "z-velocity")); - - // Field of view - out[0x9C] = get_int_from_json(srcPath, "fov"); - - // Background clear color - out[0x9D] = get_int_from_json(srcPath, "background-colour", "red"); - out[0x9E] = get_int_from_json(srcPath, "background-colour", "green"); - out[0x9F] = get_int_from_json(srcPath, "background-colour", "blue"); - - GET_UNKNOWN_VALUES(out, 0xA0, 0xA4, "unkA0"); - write_big_endian_word(out, 0xA4, get_int_from_json(srcPath, "unknown-data", "unkA4")); - write_big_endian_halfword(out, 0xA8, get_int_from_json(srcPath, "unknown-data", "unkA8")); - write_big_endian_halfword(out, 0xAA, get_int_from_json(srcPath, "unknown-data", "unkAA")); - - // Pulsating lights are only used in spaceport alpha - int pulsatingLights = -1; - if(json_has_key(srcPath, "pulsating-lights")) { - pulsatingLights = get_index_from_build_id("ASSET_MISC", get_string_from_json(srcPath, "pulsating-lights")); - } - write_big_endian_word(out, 0xAC, pulsatingLights); - - GET_UNKNOWN_VALUES(out, 0xB0, 0xC4, "unkB0"); - write_big_endian_word(out, 0xC4, get_int_from_json(srcPath, "unknown-data", "unkC4")); - - write_binary_file(out, dstPath); -} - -BuildLevelHeader::~BuildLevelHeader() { - -} diff --git a/tools/dkr_assets_tool_classes/builder/build_files/build_levelheader.h b/tools/dkr_assets_tool_classes/builder/build_files/build_levelheader.h deleted file mode 100644 index 5e7a35e3..00000000 --- a/tools/dkr_assets_tool_classes/builder/build_files/build_levelheader.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include "../../common/util.h" - -#define SIZEOF_LEVEL_HEADER 0xC8 - -class BuildLevelHeader { -public: - BuildLevelHeader(std::string srcPath, std::string dstPath); - ~BuildLevelHeader(); -}; diff --git a/tools/dkr_assets_tool_classes/builder/build_files/build_levelname.cpp b/tools/dkr_assets_tool_classes/builder/build_files/build_levelname.cpp deleted file mode 100644 index b4c30263..00000000 --- a/tools/dkr_assets_tool_classes/builder/build_files/build_levelname.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "build_levelname.h" - -BuildLevelName::BuildLevelName(std::string srcPath, std::string dstPath) { - std::vector out; - - std::vector languages = get_enum_keys("Language"); - - int numLangWritten = 0; - - // Search through and add all the avaliable languages. - // Note: If a language is not defined in the enum, then it won't be added to the output! - for(auto &langName : languages) { - if(json_has_key(srcPath, "languages", langName)) { // Check if the level name json has the language. - write_ascii(out, get_string_from_json(srcPath, "languages", langName)); - numLangWritten++; - } else { - // Language not found. For now, this means the text will be empty. - // TODO: Maybe have an option to default to english? - out.push_back('\0'); // Push back a null terminator - } - } - - if(numLangWritten == 0) { - std::cout << "Warning: No languages were found." << std::endl; - } - - write_binary_file(out, dstPath); -} - -BuildLevelName::~BuildLevelName() { - -} diff --git a/tools/dkr_assets_tool_classes/builder/build_files/build_levelname.h b/tools/dkr_assets_tool_classes/builder/build_files/build_levelname.h deleted file mode 100644 index 0bb9497f..00000000 --- a/tools/dkr_assets_tool_classes/builder/build_files/build_levelname.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include "../../common/util.h" - -class BuildLevelName { -public: - BuildLevelName(std::string srcPath, std::string dstPath); - ~BuildLevelName(); -}; diff --git a/tools/dkr_assets_tool_classes/builder/build_files/build_menutext.cpp b/tools/dkr_assets_tool_classes/builder/build_files/build_menutext.cpp deleted file mode 100644 index a2d75d29..00000000 --- a/tools/dkr_assets_tool_classes/builder/build_files/build_menutext.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include "build_menutext.h" - -BuildMenuText::BuildMenuText(std::string srcPath, std::string dstPath) { - //int numberOfEntries = get_array_length_from_json(srcPath, "order"); - - std::vector ids = get_array_from_section("ASSET_MENU_TEXT", "menu-text-build-ids"); - int numberOfEntries = ids.size(); - - std::vector table(numberOfEntries * 4); - std::vector text; - - int textOffset = numberOfEntries * 4; - - for(int i = 0; i < numberOfEntries; i++) { - // Get the build id for this index. - std::string buildId = ids[i]; - - // If the build ID is not in the sections, then just write -1 to the table. - if(!json_has_key(srcPath, "sections", buildId)) { - write_big_endian_word(table, i * 4, -1); - continue; - } - // Get the text string from the inputJSON. - std::string entryText = get_string_from_json(srcPath, "sections", buildId); - // Write ascii text to vector - write_ascii(text, entryText); - // Write the offset to the text - write_big_endian_word(table, i * 4, textOffset); - // Increment the current offset by the length of the string (+1 for null terminator) - textOffset += entryText.length() + 1; - } - - // Append the text data to the table data. - table.insert(table.end(), text.begin(), text.end()); - - while(table.size() % 8 != 0) { - table.push_back(0); // Make sure the data is 8-byte aligned. - } - - write_binary_file(table, dstPath); -} - -BuildMenuText::~BuildMenuText(){ - -} - diff --git a/tools/dkr_assets_tool_classes/builder/build_files/build_menutext.h b/tools/dkr_assets_tool_classes/builder/build_files/build_menutext.h deleted file mode 100644 index ef71d6bb..00000000 --- a/tools/dkr_assets_tool_classes/builder/build_files/build_menutext.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include "../../common/util.h" - -class BuildMenuText { -public: - BuildMenuText(std::string srcPath, std::string dstPath); - ~BuildMenuText(); -}; diff --git a/tools/dkr_assets_tool_classes/builder/build_files/build_sprite.cpp b/tools/dkr_assets_tool_classes/builder/build_files/build_sprite.cpp deleted file mode 100644 index b157a76e..00000000 --- a/tools/dkr_assets_tool_classes/builder/build_files/build_sprite.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "build_sprite.h" - -#define SIZEOF_SPRITE_HEADER 12 - -BuildSprite::BuildSprite(std::string srcPath, std::string dstPath) { - int numberOfFrames = get_array_length_from_json(srcPath, "frame-tex-count"); - - std::vector out(align16(SIZEOF_SPRITE_HEADER + numberOfFrames + 1)); - - // Write header - write_big_endian_halfword(out, 0, get_tex_2d_index_from_build_id(get_string_from_json(srcPath, "start-texture"))); - write_big_endian_halfword(out, 2, numberOfFrames); - write_big_endian_halfword(out, 4, get_int_from_json(srcPath, "unk4")); - write_big_endian_halfword(out, 6, get_int_from_json(srcPath, "unk6")); - // The word at offset 8 is always zero in the rom. - - int texOffset = 0; - - for(int i = 0; i < numberOfFrames + 1; i++) { - out[SIZEOF_SPRITE_HEADER + i] = texOffset; - texOffset += get_int_from_json(srcPath, "frame-tex-count", i); - } - - write_binary_file(out, dstPath); -} - -BuildSprite::~BuildSprite() { - -} diff --git a/tools/dkr_assets_tool_classes/builder/build_files/build_sprite.h b/tools/dkr_assets_tool_classes/builder/build_files/build_sprite.h deleted file mode 100644 index dc8ad2c4..00000000 --- a/tools/dkr_assets_tool_classes/builder/build_files/build_sprite.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include "../../common/util.h" - -class BuildSprite { -public: - BuildSprite(std::string srcPath, std::string dstPath); - ~BuildSprite(); -}; diff --git a/tools/dkr_assets_tool_classes/builder/build_files/build_texture.cpp b/tools/dkr_assets_tool_classes/builder/build_files/build_texture.cpp deleted file mode 100644 index d266a878..00000000 --- a/tools/dkr_assets_tool_classes/builder/build_files/build_texture.cpp +++ /dev/null @@ -1,221 +0,0 @@ -#include "build_texture.h" - -#define SET_BOOL_FLAG(flagName, flagVal) \ - flags |= get_bool_from_json(srcPath, "flags", flagName) ? flagVal : 0 -#define SET_STRING_FLAG(flagName, strVal, flagVal) \ - flags |= get_string_from_json(srcPath, "flags", flagName) == strVal ? flagVal : 0 - -int get_png_data_size(int width, int height, int format) { - switch(format) { - case TEX_FORMAT_I8: - case TEX_FORMAT_I4: - case TEX_FORMAT_IA16: - case TEX_FORMAT_IA8: - case TEX_FORMAT_IA4: - return (width * height * 2); - default: - return (width * height * 4); - } -} - -int get_png_offset(int i, int width, int height, int format) { - return get_png_data_size(width, height, format) * i; -} - -BuildTexture::BuildTexture(std::string srcPath, std::string dstPath) { - std::string directory = get_directory_from_full_path(srcPath); - std::string imgPath = directory + "/" + get_string_from_json(srcPath, "img"); - - bool isCompressed = get_bool_from_json(srcPath, "compressed"); - bool flipTexture = get_bool_from_json(srcPath, "flipped-image"); - bool interlaced = get_bool_from_json(srcPath, "flags", "interlaced"); - - int width = get_int_from_json(srcPath, "width"); - int height = get_int_from_json(srcPath, "height"); - std::string formatString = get_string_from_json(srcPath, "format"); - int format = get_texture_format_from_string(formatString); - int texType = get_int_from_json(srcPath, "tex-type"); - - int spriteX = json_has_key(srcPath, "sprite-x") ? get_int_from_json(srcPath, "sprite-x") : 0; - int spriteY = json_has_key(srcPath, "sprite-y") ? get_int_from_json(srcPath, "sprite-y") : 0; - - bool writeSize = get_bool_from_json(srcPath, "write-size"); - - // TODO: Figure out all the flags - int flags = 0; - SET_BOOL_FLAG("flag-01", 0x0001); - SET_BOOL_FLAG("flag-04", 0x0004); - SET_BOOL_FLAG("flag-10", 0x0010); - SET_STRING_FLAG("wrap-s", "Clamp", 0x0040); - SET_STRING_FLAG("wrap-t", "Clamp", 0x0080); - SET_BOOL_FLAG("interlaced", 0x0400); - - int textureSize = get_texture_size(width, height, format); - - int numberOfTextures = get_int_from_json(srcPath, "frame-count"); - - int frameAdvance = json_has_key(srcPath, "frame-advance-delay") ? get_int_from_json(srcPath, "frame-advance-delay") : 0; - - std::vector uncompressed(textureSize * numberOfTextures); - - int pngWidth, pngHeight; - std::vector pngData = load_texture_from_png(imgPath, format, &pngWidth, &pngHeight); - - for(int i = 0; i < numberOfTextures; i++) { - int off = i * textureSize; - int pngOff = get_png_offset(i, width, height, format); - - // Texture Header - uncompressed[off] = width; - uncompressed[off + 0x01] = height; - uncompressed[off + 0x02] = (texType << 4) | format; - uncompressed[off + 0x03] = spriteX; - uncompressed[off + 0x04] = spriteY; - uncompressed[off + 0x05] = 1; // Number of instances. Always 1 in the ROM. - write_big_endian_halfword(uncompressed, off + 0x06, flags); - uncompressed[off + 0x12] = numberOfTextures; - write_big_endian_halfword(uncompressed, off + 0x14, frameAdvance); - if(writeSize) { - write_big_endian_halfword(uncompressed, off + 0x16, align16(textureSize)); - } else { - uncompressed[off + 0x1D] = 0x01; - } - - // Subsection of pngData - std::vector rgbaData(pngData.begin() + pngOff, pngData.begin() + pngOff + get_png_data_size(width, height, format)); - - write_texture_data(uncompressed, off + TEX_HEADER_SIZE, rgbaData, width, height, format, interlaced, flipTexture); - } - - if(!writeSize) { - while(uncompressed.size() % 16 != 0) { - uncompressed.push_back(0); - } - } - - // isCompressed = false; // Uncomment to help with debugging. - - if(isCompressed) { - std::vector compressedHeader; - compressedHeader.insert(compressedHeader.end(), uncompressed.begin(), uncompressed.begin() + TEX_HEADER_SIZE); - - compressedHeader[0x1D] = 0x01; - - DKRCompression compression; - std::vector compressed = compression.compressBuffer(uncompressed); - - // Note: uncompressed is garbled at this point. - - compressed.insert(compressed.begin(), compressedHeader.begin(), compressedHeader.end()); - - write_binary_file(compressed, dstPath); - } else { - write_binary_file(uncompressed, dstPath); - } - - //write_binary_file(out, dstPath); -} - -BuildTexture::~BuildTexture() { - -} - -void BuildTexture::write_texture_data(std::vector &out, int outOffset, std::vector &rgbaData, - int width, int height, int format, bool interlace, bool flipTexture) { - if(flipTexture) { - switch(format) { - case TEX_FORMAT_I8: - case TEX_FORMAT_I4: - case TEX_FORMAT_IA16: - case TEX_FORMAT_IA8: - case TEX_FORMAT_IA4: - flip_texture_vertically(rgbaData, 0, width, height, TEX_FORMAT_IA16); - break; - default: - flip_texture_vertically(rgbaData, 0, width, height, TEX_FORMAT_RGBA32); - break; - } - } - switch(format) { - case TEX_FORMAT_RGBA32: - { - if (interlace) { - deinterlace(rgbaData, 0, width, height, 32, 8); - } - std::copy(rgbaData.begin(), rgbaData.end(), out.begin() + outOffset); - break; - } - case TEX_FORMAT_RGBA16: - { - uint8_t* rgba16Data = (uint8_t*)malloc(width * height * 2); - rgba2raw(rgba16Data, (const rgba*)&rgbaData[0], width, height, 16); - std::vector rgba16(rgba16Data, rgba16Data + (width * height * 2)); - if (interlace) { - deinterlace(rgba16, 0, width, height, 16, 4); - } - std::copy(rgba16.begin(), rgba16.end(), out.begin() + outOffset); - break; - } - case TEX_FORMAT_I8: - { - uint8_t* i8Data = (uint8_t*)malloc(width * height); - i2raw(i8Data, (const ia*)&rgbaData[0], width, height, 8); - std::vector i8(i8Data, i8Data + (width * height)); - if (interlace) { - deinterlace(i8, 0, width, height, 8, 4); - } - std::copy(i8.begin(), i8.end(), out.begin() + outOffset); - break; - } - case TEX_FORMAT_I4: - { - uint8_t* i4Data = (uint8_t*)malloc(width * height / 2); - i2raw(i4Data, (const ia*)&rgbaData[0], width, height, 4); - std::vector i4(i4Data, i4Data + (width * height / 2)); - if (interlace) { - deinterlace(i4, 0, width, height, 4, 4); - } - std::copy(i4.begin(), i4.end(), out.begin() + outOffset); - break; - } - case TEX_FORMAT_IA16: - { - uint8_t* ia16Data = (uint8_t*)malloc(width * height * 2); - ia2raw(ia16Data, (const ia*)&rgbaData[0], width, height, 16); - std::vector ia16(ia16Data, ia16Data + (width * height * 2)); - if (interlace) { - deinterlace(ia16, 0, width, height, 16, 4); - } - std::copy(ia16.begin(), ia16.end(), out.begin() + outOffset); - break; - } - case TEX_FORMAT_IA8: - { - uint8_t* ia8Data = (uint8_t*)malloc(width * height); - ia2raw(ia8Data, (const ia*)&rgbaData[0], width, height, 8); - std::vector ia8(ia8Data, ia8Data + (width * height)); - if (interlace) { - deinterlace(ia8, 0, width, height, 8, 4); - } - std::copy(ia8.begin(), ia8.end(), out.begin() + outOffset); - break; - } - case TEX_FORMAT_IA4: - { - uint8_t* ia4Data = (uint8_t*)malloc(width * height / 2); - ia2raw(ia4Data, (const ia*)&rgbaData[0], width, height, 4); - std::vector ia4(ia4Data, ia4Data + (width * height / 2)); - if (interlace) { - deinterlace(ia4, 0, width, height, 4, 4); - } - std::copy(ia4.begin(), ia4.end(), out.begin() + outOffset); - break; - } - case TEX_FORMAT_CI4: - case TEX_FORMAT_CI8: - { - display_error_and_abort("CI4/CI8 texture formats are not currently supported."); - } - } -} - diff --git a/tools/dkr_assets_tool_classes/builder/build_files/build_texture.h b/tools/dkr_assets_tool_classes/builder/build_files/build_texture.h deleted file mode 100644 index e653f1da..00000000 --- a/tools/dkr_assets_tool_classes/builder/build_files/build_texture.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include "../../common/util.h" -#include "../../common/textures.h" - -class BuildTexture { -public: - BuildTexture(std::string srcPath, std::string dstPath); - ~BuildTexture(); -private: - void write_texture_data(std::vector &out, int outOffset, std::vector &rgbaData, - int width, int height, int format, bool interlace, bool flipTexture); -}; diff --git a/tools/dkr_assets_tool_classes/builder/build_files/build_ttghost.cpp b/tools/dkr_assets_tool_classes/builder/build_files/build_ttghost.cpp deleted file mode 100644 index 995bec87..00000000 --- a/tools/dkr_assets_tool_classes/builder/build_files/build_ttghost.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "build_ttghost.h" - -#include - -BuildTTGhost::BuildTTGhost(std::string srcPath, std::string dstPath) { - int numberOfNodes = get_array_length_from_json(srcPath, "nodes"); - - std::vector out(align16(SIZEOF_TTGHOST_HEADER + numberOfNodes * SIZEOF_TTGHOST_NODE)); - - // Write header - out[0] = get_index_from_build_id("ASSET_LEVEL_HEADERS", get_string_from_json(srcPath, "header", "level")); // get_int_from_json(srcPath, "header", "level"); - out[1] = get_enum_value_from_string("Vehicle", get_string_from_json(srcPath, "header", "vehicle")); - out[2] = 9; // Always 9? - write_big_endian_halfword(out, 4, get_int_from_json(srcPath, "header", "time")); - write_big_endian_halfword(out, 6, numberOfNodes); - - // Write the nodes - for(int i = 0; i < numberOfNodes; i++) { - int offset = (i * SIZEOF_TTGHOST_NODE) + SIZEOF_TTGHOST_HEADER; - write_big_endian_halfword(out, offset, get_int_from_json(srcPath, "nodes", i, "x")); - write_big_endian_halfword(out, offset + 2, get_int_from_json(srcPath, "nodes", i, "y")); - write_big_endian_halfword(out, offset + 4, get_int_from_json(srcPath, "nodes", i, "z")); - // Yes, this order is correct. - write_big_endian_halfword(out, offset + 6, get_int_from_json(srcPath, "nodes", i, "rz")); - write_big_endian_halfword(out, offset + 8, get_int_from_json(srcPath, "nodes", i, "rx")); - write_big_endian_halfword(out, offset + 10, get_int_from_json(srcPath, "nodes", i, "ry")); - } - - write_binary_file(out, dstPath); -} - -BuildTTGhost::~BuildTTGhost() { -} diff --git a/tools/dkr_assets_tool_classes/builder/build_files/build_ttghost.h b/tools/dkr_assets_tool_classes/builder/build_files/build_ttghost.h deleted file mode 100644 index e6e935ac..00000000 --- a/tools/dkr_assets_tool_classes/builder/build_files/build_ttghost.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include "../../common/util.h" - -#define SIZEOF_TTGHOST_HEADER 8 -#define SIZEOF_TTGHOST_NODE 12 - -class BuildTTGhost { -public: - BuildTTGhost(std::string srcPath, std::string dstPath); - ~BuildTTGhost(); -}; diff --git a/tools/dkr_assets_tool_classes/builder/builder.cpp b/tools/dkr_assets_tool_classes/builder/builder.cpp deleted file mode 100644 index 221432be..00000000 --- a/tools/dkr_assets_tool_classes/builder/builder.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "builder.h" - -Builder::Builder(std::string srcPath, std::string dstPath) { - if(!path_exists(srcPath)) { - display_error_and_abort("Invalid path \"", srcPath, "\""); - } - - if(ends_with(srcPath, ".json")) { - std::string type = get_string_from_json(srcPath, "type"); - if(type == "Textures") { - BuildTexture(srcPath, dstPath); - } else if (type == "TTGhosts") { - BuildTTGhost(srcPath, dstPath); - } else if (type == "Sprites") { - BuildSprite(srcPath, dstPath); - } else if (type == "LevelNames") { - BuildLevelName(srcPath, dstPath); - } else if (type == "LevelHeaders") { - BuildLevelHeader(srcPath, dstPath); - } else if (type == "GameText") { - BuildGameText(srcPath, dstPath); - } else if (type == "MenuText") { - BuildMenuText(srcPath, dstPath); - } else if (type == "Fonts") { - BuildFonts(srcPath, dstPath); - } else if (type == "") { - display_error_and_abort("No type found for \"", srcPath, "\".\nMake sure the \"type\" property is defined in the json file!"); - } else { - display_error_and_abort("Unknown type \"", type, "\" in \"", srcPath, "\""); - } - } -} - -Builder::~Builder() { - -} diff --git a/tools/dkr_assets_tool_classes/builder/builder.h b/tools/dkr_assets_tool_classes/builder/builder.h deleted file mode 100644 index c90285e6..00000000 --- a/tools/dkr_assets_tool_classes/builder/builder.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -#include "../common/util.h" -#include "../common/types.h" - -#include "build_files/build_fonts.h" -#include "build_files/build_gametext.h" -#include "build_files/build_levelname.h" -#include "build_files/build_levelheader.h" -#include "build_files/build_menutext.h" -#include "build_files/build_sprite.h" -#include "build_files/build_texture.h" -#include "build_files/build_ttghost.h" - -class Builder { -public: - Builder(std::string srcPath, std::string dstPath); - ~Builder(); -private: -}; diff --git a/tools/dkr_assets_tool_classes/common/revision_number.h b/tools/dkr_assets_tool_classes/common/revision_number.h deleted file mode 100644 index 98fa5d17..00000000 --- a/tools/dkr_assets_tool_classes/common/revision_number.h +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -#define REVISION_NUMBER 2 -#define REVISION_MINOR_NUMBER 0 - diff --git a/tools/dkr_assets_tool_classes/common/textures.cpp b/tools/dkr_assets_tool_classes/common/textures.cpp deleted file mode 100644 index ea2a51ea..00000000 --- a/tools/dkr_assets_tool_classes/common/textures.cpp +++ /dev/null @@ -1,138 +0,0 @@ -#include "textures.h" - -std::string get_texture_format_string(int format) { - switch(format) { - case TEX_FORMAT_RGBA32: return "RGBA32"; - case TEX_FORMAT_RGBA16: return "RGBA16"; - case TEX_FORMAT_I8: return "I8"; - case TEX_FORMAT_I4: return "I4"; - case TEX_FORMAT_IA16: return "IA16"; - case TEX_FORMAT_IA8: return "IA8"; - case TEX_FORMAT_IA4: return "IA4"; - case TEX_FORMAT_CI4: return "CI4"; - case TEX_FORMAT_CI8: return "CI8"; - } - display_error_and_abort("Invalid texture format ", format); -} - -int get_texture_format_from_string(std::string format) { - if(format == "RGBA32") return TEX_FORMAT_RGBA32; - if(format == "RGBA16") return TEX_FORMAT_RGBA16; - if(format == "I8") return TEX_FORMAT_I8; - if(format == "I4") return TEX_FORMAT_I4; - if(format == "IA16") return TEX_FORMAT_IA16; - if(format == "IA8") return TEX_FORMAT_IA8; - if(format == "IA4") return TEX_FORMAT_IA4; - if(format == "CI4") return TEX_FORMAT_CI4; - if(format == "CI8") return TEX_FORMAT_CI8; - display_error_and_abort("Invalid texture format ", format); -} - -void deinterlace(std::vector& texData, int texDataOffset, int width, int height, int bitDepth, int bufferSize) { - uint8_t* temp = new uint8_t[bufferSize]; - - int numPixels; - if(bitDepth == 4) { - numPixels = ((width * height) / 2); - } else { - numPixels = (width * height * (bitDepth / 8)); - } - - int stride = bufferSize * 2; - - int size = numPixels / stride; - - for(int i = 0; i < size; i++) { - int row; - if(bitDepth == 4) { - row = (i * stride) / width * 2; - } else { - row = (i * stride) / width / (bitDepth / 8); - } - if(row % 2 == 0) continue; - for(int j = 0; j < bufferSize; j++) { - temp[j] = texData[texDataOffset + (i * stride + j)]; - texData[texDataOffset + (i * stride + j)] = texData[texDataOffset + (i * stride + j + bufferSize)]; - texData[texDataOffset + (i * stride + j + bufferSize)] = temp[j]; - } - } - - delete[] temp; -} - -void flip_texture_vertically(std::vector &data, int dataOffset, int width, int height, int format) { - // Convert width into number of bytes per line. - switch(format) { - case TEX_FORMAT_I4: - case TEX_FORMAT_IA4: - case TEX_FORMAT_CI4: - width /= 2; // 2 pixels per byte - break; - case TEX_FORMAT_RGBA16: - case TEX_FORMAT_IA16: - width *= 2; // 2 bytes per pixel - break; - case TEX_FORMAT_RGBA32: - width *= 4; // 4 bytes per pixel - break; - // Don't need to do anything for the 8-bit formats. - } - - for(int y = 0; y < height / 2; y++) { - for(int x = 0; x < width; x++) { - uint8_t temp = data[dataOffset + (y * width + x)]; - data[dataOffset + (y * width + x)] = data[dataOffset + ((height - y - 1) * width + x)]; - data[dataOffset + ((height - y - 1) * width + x)] = temp; - } - } -} - -int get_texture_size(int width, int height, int format) { - switch(format) { - case TEX_FORMAT_RGBA32: - return (width * height * 4) + TEX_HEADER_SIZE; - case TEX_FORMAT_RGBA16: - case TEX_FORMAT_IA16: - return (width * height * 2) + TEX_HEADER_SIZE; - case TEX_FORMAT_I8: - case TEX_FORMAT_IA8: - return (width * height) + TEX_HEADER_SIZE; - case TEX_FORMAT_I4: - case TEX_FORMAT_IA4: - return (width * height / 2) + TEX_HEADER_SIZE; - case TEX_FORMAT_CI4: - case TEX_FORMAT_CI8: - display_error_and_abort("CI texture formats are not currently supported."); - } - - display_error_and_abort("Invalid texture format ", format); -} - -std::vector load_texture_from_png(std::string filepath, int textureFormat, int *width, int *height) { - switch(textureFormat) { - case TEX_FORMAT_RGBA32: - case TEX_FORMAT_RGBA16: - { - uint8_t* data = (uint8_t*)png2rgba(filepath.c_str(), width, height); - std::vector vec(data, data + ((*width) * (*height) * 4)); - free(data); - return vec; - } - case TEX_FORMAT_I8: - case TEX_FORMAT_I4: - case TEX_FORMAT_IA16: - case TEX_FORMAT_IA8: - case TEX_FORMAT_IA4: - { - uint8_t* data = (uint8_t*)png2ia(filepath.c_str(), width, height); - std::vector vec(data, data + ((*width) * (*height) * 2)); - free(data); - return vec; - } - case TEX_FORMAT_CI4: - case TEX_FORMAT_CI8: - display_error_and_abort("CI4/CI8 texture formats are not currently supported."); - default: - display_error_and_abort("Invalid texture format: ", textureFormat); - } -} diff --git a/tools/dkr_assets_tool_classes/common/textures.h b/tools/dkr_assets_tool_classes/common/textures.h deleted file mode 100644 index e960dd8d..00000000 --- a/tools/dkr_assets_tool_classes/common/textures.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include -#include -#include -#include "../libs/n64graphics.h" -#include "util/errorHelper.h" - -#define TEX_HEADER_SIZE 0x20 - -#define TEX_FORMAT_RGBA32 0 -#define TEX_FORMAT_RGBA16 1 -#define TEX_FORMAT_I8 2 -#define TEX_FORMAT_I4 3 -#define TEX_FORMAT_IA16 4 -#define TEX_FORMAT_IA8 5 -#define TEX_FORMAT_IA4 6 -#define TEX_FORMAT_CI4 7 -#define TEX_FORMAT_CI8 8 - -std::string get_texture_format_string(int format); -int get_texture_format_from_string(std::string format); -void deinterlace(std::vector& texData, int texDataOffset, int width, int height, int bitDepth, int bufferSize); -void flip_texture_vertically(std::vector &data, int dataOffset, int width, int height, int format); -int get_texture_size(int width, int height, int format); -std::vector load_texture_from_png(std::string filepath, int textureFormat, int* width, int* height); diff --git a/tools/dkr_assets_tool_classes/common/types.cpp b/tools/dkr_assets_tool_classes/common/types.cpp deleted file mode 100644 index 5f9dd37b..00000000 --- a/tools/dkr_assets_tool_classes/common/types.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "types.h" - -bool is_binary_type(std::string type) { - return type == "Binary" || type == "Miscellaneous" - || type == "ObjectHeaders" || type == "Audio" - || type == "Particles" || type == "ParticleBehaviors"; -} - -bool is_compressed_type(std::string type) { - return type == "Compressed" || type == "LevelObjectMap" || type == "LevelModels" - || type == "ObjectModels" || type == "ObjectAnimations"; -} - -bool is_json_type(std::string type){ - return type == "MenuText" || type == "GameText" || type == "TTGhosts" || type == "LevelNames" || - type == "LevelHeaders" || type == "Textures" || type == "Sprites" || type == "Fonts"; -} diff --git a/tools/dkr_assets_tool_classes/common/types.h b/tools/dkr_assets_tool_classes/common/types.h deleted file mode 100644 index 4a41002e..00000000 --- a/tools/dkr_assets_tool_classes/common/types.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -#include - -bool is_binary_type(std::string type); -bool is_compressed_type(std::string type); -bool is_json_type(std::string type); diff --git a/tools/dkr_assets_tool_classes/common/util.cpp b/tools/dkr_assets_tool_classes/common/util.cpp deleted file mode 100644 index 1f14eb9e..00000000 --- a/tools/dkr_assets_tool_classes/common/util.cpp +++ /dev/null @@ -1,162 +0,0 @@ -#include "util.h" - -uint32_t get_big_endian_word(std::vector &data, int offset) { - return (data[offset] << 24) | (data[offset + 1] << 16) | (data[offset + 2] << 8) | data[offset + 3]; -} - -void write_big_endian_word(std::vector &data, int offset, uint32_t value) { - data[offset] = (value >> 24) & 0xFF; - data[offset + 1] = (value >> 16) & 0xFF; - data[offset + 2] = (value >> 8) & 0xFF; - data[offset + 3] = value & 0xFF; -} - -uint16_t get_big_endian_halfword(std::vector &data, int offset) { - return (data[offset] << 8) | data[offset + 1]; -} - -void write_big_endian_halfword(std::vector &data, int offset, uint16_t value) { - data[offset] = (value >> 8) & 0xFF; - data[offset + 1] = value & 0xFF; -} - -float get_big_endian_float(std::vector &data, int offset) { - uint32_t word = get_big_endian_word(data, offset); - return *((float*)&word); -} - -void write_big_endian_float(std::vector &data, int offset, float value){ - write_big_endian_word(data, offset, *((uint32_t*)&value)); -} - -std::string get_ascii(std::vector &data, int offset) { - std::stringstream ss; - - while(data[offset] != '\0'){ - ss << (char)data[offset++]; - } - - return ss.str(); -} - -void write_ascii(std::vector &data, std::string value) { - for(size_t i = 0; i < value.length(); i++) { - if(value[i] == '\\') { - char nextChar = value[i+1]; - if(nextChar == 't') { - data.push_back((uint8_t)'\t'); - } else if(nextChar == 'n') { - data.push_back((uint8_t)'\n'); - } else if(nextChar == 'r') { - data.push_back((uint8_t)'\r'); - } else if(nextChar == 'v') { - data.push_back((uint8_t)'\v'); - } else if(nextChar == '0') { - data.push_back((uint8_t)'\0'); - } - i++; - } else { - data.push_back(value[i]); - } - } - data.push_back('\0'); // Write null terminator. -} - -int insert_ascii(std::vector &data, int offset, std::string value) { - for(size_t i = 0; i < value.length(); i++) { - if(value[i] == '\\') { - char nextChar = value[i+1]; - if(nextChar == 't') { - data[offset++] = (uint8_t)'\t'; - } else if(nextChar == 'n') { - data[offset++] = (uint8_t)'\n'; - } else if(nextChar == 'r') { - data[offset++] = (uint8_t)'\r'; - } else if(nextChar == 'v') { - data[offset++] = (uint8_t)'\v'; - } else if(nextChar == '0') { - data[offset++] = (uint8_t)'\0'; - } - i++; - } else { - data[offset++] = value[i]; - } - } - data[offset++] = '\0'; // Write null terminator. - return offset; -} - -std::vector get_multiple_ascii(std::vector &data, int offset, int count) { - std::vector out(count); - for(int i = 0; i < count; i++) { - std::stringstream ss; - while(data[offset] != '\0') { - ss << (char)data[offset++]; - } - out[i] = ss.str(); - offset++; // Move past the null terminator - } - return out; -} - -std::vector decompress_dkr_gzip(std::vector &compressedData) { - // Needed padding to prevent errors with decompressing. - if(compressedData[compressedData.size() - 1] != 0) { - compressedData.push_back(0); - compressedData.push_back(0); - compressedData.push_back(0); - compressedData.push_back(0); - } - DKRCompression compression; - return compression.decompressBuffer(compressedData); -} - -std::vector compress_dkr_gzip(std::vector &uncompressedData) { - DKRCompression compression; - return compression.compressBuffer(uncompressedData); -} - -int align16(int val) { - return (val + 15) & 0xFFFFFFF0; -} - -std::string to_hex(uint32_t value) { - std::stringstream sstream; - sstream << std::hex << value; - std::string out = sstream.str(); - make_uppercase(out); - return "0x" + out; -} - -// Converts `FOO_BAR` to `FooBar`. -std::string upper_snake_case_to_pascal_case(std::string input) { - std::stringstream out; - bool isFirst = true; - for(int i = 0; i < input.length(); i++) { - if(input[i] == '_') { - isFirst = true; - } else { - if(isFirst) { - out << input[i]; - isFirst = false; - } else { - out << (char)tolower(input[i]); - } - } - } - - return out.str(); -} - -void print_data(std::vector &data, int offset, int length) { - int start = offset; - int end = start + length; - - std::cout << std::hex; - for(int i = start; i < end; i++) { - std::cout << (int)data[i] << ' '; - } - std::cout << std::dec << std::endl; -} - - diff --git a/tools/dkr_assets_tool_classes/common/util.h b/tools/dkr_assets_tool_classes/common/util.h deleted file mode 100644 index f0b19de1..00000000 --- a/tools/dkr_assets_tool_classes/common/util.h +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -#include "../libs/json.hpp" -#include "../libs/n64graphics.h" -#include "../libs/DKRCompression.h" - -#include "util/fileHelper.h" -#include "util/jsonHelper.h" -#include "util/enumHelper.h" -#include "util/errorHelper.h" - -uint32_t get_big_endian_word(std::vector &data, int offset); -void write_big_endian_word(std::vector &data, int offset, uint32_t value); -uint16_t get_big_endian_halfword(std::vector &data, int offset); -void write_big_endian_halfword(std::vector &data, int offset, uint16_t value); -int16_t get_big_endian_halfword_signed(std::vector &data, int offset); -float get_big_endian_float(std::vector &data, int offset); -void write_big_endian_float(std::vector &data, int offset, float value); -std::string get_ascii(std::vector &data, int offset); -void write_ascii(std::vector &data, std::string value); -int insert_ascii(std::vector &data, int offset, std::string value); -std::vector get_multiple_ascii(std::vector &data, int offset, int count); - -std::vector decompress_dkr_gzip(std::vector &compressedData); -std::vector compress_dkr_gzip(std::vector &uncompressedData); - -int align16(int val); -std::string to_hex(uint32_t value); - -std::string upper_snake_case_to_pascal_case(std::string input); - -void print_data(std::vector &data, int offset, int length); diff --git a/tools/dkr_assets_tool_classes/common/util/enumHelper.cpp b/tools/dkr_assets_tool_classes/common/util/enumHelper.cpp deleted file mode 100644 index 486cd4f6..00000000 --- a/tools/dkr_assets_tool_classes/common/util/enumHelper.cpp +++ /dev/null @@ -1,182 +0,0 @@ -#include "enumHelper.h" - -bool is_string_integer(const std::string &s){ - return std::regex_match(s, std::regex("[(-|+)]?[0-9]+")); -} - -bool hasLoadedEnums = false; -std::map enums; -std::map> enumKeys; - -std::string ENUMS_CACHE_PATH = ""; - -void set_enums_cache_path() { - ENUMS_CACHE_PATH = "./build/" + get_version() + "/enumsCache.bin"; -} - -int evalulate_enum(std::string &enumValue) { - int attempts = 0; - std::regex enumNameRegex("([^0-9|^&~+\\-\\/*\\s]+)"); - std::smatch sm; - - // Replaces all enum strings with their defined values. E.g. "VEHICLE_PLANE" should get replaced with "2". - while (regex_search(enumValue, sm, enumNameRegex) && attempts++ < 100) { - std::string foundEnum = sm[1]; - if(enums.find(foundEnum) == enums.end()) { - std::cout << "Error: Could not find enum value \"" << foundEnum << "\". Make sure it is defined!" << std::endl; - throw 1; - } - std::string newValue = std::to_string(enums[foundEnum]); - int pos = sm.position(1); - enumValue.replace(pos, pos + foundEnum.length(), newValue); - } - - try { - return calculator::eval(enumValue); - } catch (calculator::error& e) { - std::cerr << e.what() << std::endl; - throw 1; - } -} - -void get_enum_values(std::string enumName, std::string enumValuesText) { - std::vector names; - - std::regex enumValueRegex("\\s*([_A-Za-z][_A-Za-z0-9]*)(?:\\s*=\\s*([^,]*)[,]?.*)?"); - std::smatch sm; - std::string text = enumValuesText; - int currentValue = 0; // Enums start off at 0. - while (regex_search(text, sm, enumValueRegex)) { - std::string enumValueName = sm[1]; - std::string enumValue = sm[2]; - names.push_back(enumValueName); - if(!enumValue.empty()) { - currentValue = evalulate_enum(enumValue); - } - enums[enumValueName] = currentValue++; - - //std::cout << enumValueName << " = " << enums[enumValueName] << std::endl; - text = sm.suffix(); - } - enumKeys[enumName] = names; -} - -void write_ascii_to_cache(std::vector &cache, std::string &text) { - int textLength = text.length(); - if(textLength > 255) { // Assumption: All labels are under 256 characters. - textLength = 255; - } - cache.push_back(textLength); - for(int i = 0; i < text.length(); i++) { - cache.push_back((uint8_t)text.at(i)); - } - cache.push_back(0); // Push back null terminator -} -void write_int_to_cache(std::vector &cache, int value) { - int pos = cache.size(); - for(int i = 0; i < 4; i++) cache.push_back(0); - *((int*)(&cache[pos])) = value; -} -std::string read_ascii_from_cache(std::vector &cache, int &offset) { - int pos = offset; - int strLength = cache[pos]; - offset += cache[pos] + 2; - return std::string((char*)&cache[pos + 1]); -} -int read_int_from_cache(std::vector &cache, int &offset) { - int value = *((int*)(&cache[offset])); - offset += 4; - return value; -} - -void save_enums_cache() { - std::vector cache; - - for(auto& keyValuePair : enumKeys) { - std::string enumName = keyValuePair.first; - int numberOfValues = keyValuePair.second.size(); - //std::cout << enumName << " has " << numberOfValues << " values" << std::endl; - write_ascii_to_cache(cache, enumName); - write_int_to_cache(cache, numberOfValues); - for(std::string enumValueName : keyValuePair.second) { - write_ascii_to_cache(cache, enumValueName); - write_int_to_cache(cache, enums[enumValueName]); - } - } - - write_binary_file(cache, ENUMS_CACHE_PATH); -} - -#define READ_STRING() read_ascii_from_cache(cache, offset) -#define READ_INT() read_int_from_cache(cache, offset) - -void load_enums_cache() { - std::vector cache = read_binary_file(ENUMS_CACHE_PATH); - int offset = 0; - int len = cache.size(); - - while(offset != len) { - std::string enumName = READ_STRING(); - int numberOfValues = READ_INT(); - std::vector names; - for(int i = 0; i < numberOfValues; i++) { - std::string enumValueName = READ_STRING(); - int enumValue = READ_INT(); - names.push_back(enumValueName); - enums[enumValueName] = enumValue; - } - enumKeys[enumName] = names; - } -} - -void generate_enums_cache(std::string enumsHeaderPath) { - set_enums_cache_path(); - ensure_that_path_exists("build/" + get_version() + "/"); - // Generate enums map - path_must_exist(enumsHeaderPath); - std::string enumsIncludeText = read_text_file(enumsHeaderPath); - std::regex enumRegex("enum ([^\\s{]+)\\s*[{]((?:.*\\n)*?)[}]"); - std::smatch sm; - std::string text = enumsIncludeText; - while (regex_search(text, sm, enumRegex)) { - std::string enumName = sm[1]; - std::string enumValuesText = sm[2]; - get_enum_values(enumName, enumValuesText); - text = sm.suffix(); - } - save_enums_cache(); -} - -std::mutex enumsMutex; - -void make_sure_enums_are_loaded() { - enumsMutex.lock(); - if(!hasLoadedEnums) { - if(ENUMS_CACHE_PATH.empty()) { - set_enums_cache_path(); - } - load_enums_cache(); - hasLoadedEnums = true; - } - enumsMutex.unlock(); -} - -std::string get_enum_string_from_value(std::string enumName, int value) { - make_sure_enums_are_loaded(); - for (std::string &key : enumKeys[enumName]) { - if(enums[key] == value) { - return key; - } - } - return "null"; -} - -int get_enum_value_from_string(std::string enumName, std::string value) { - make_sure_enums_are_loaded(); - return enums[value]; -} - -std::vector get_enum_keys(std::string enumName) { - make_sure_enums_are_loaded(); - return enumKeys[enumName]; -} diff --git a/tools/dkr_assets_tool_classes/common/util/enumHelper.h b/tools/dkr_assets_tool_classes/common/util/enumHelper.h deleted file mode 100644 index 431eb5f6..00000000 --- a/tools/dkr_assets_tool_classes/common/util/enumHelper.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../../libs/calculator.hpp" - -#include "fileHelper.h" - -void generate_enums_cache(std::string enumsHeaderPath); - -std::string get_enum_string_from_value(std::string enumName, int value); -int get_enum_value_from_string(std::string enumName, std::string value); -std::vector get_enum_keys(std::string enumName); - - diff --git a/tools/dkr_assets_tool_classes/common/util/errorHelper.cpp b/tools/dkr_assets_tool_classes/common/util/errorHelper.cpp deleted file mode 100644 index d00ba0ef..00000000 --- a/tools/dkr_assets_tool_classes/common/util/errorHelper.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "errorHelper.h" - - diff --git a/tools/dkr_assets_tool_classes/common/util/errorHelper.h b/tools/dkr_assets_tool_classes/common/util/errorHelper.h deleted file mode 100644 index 7c0c746d..00000000 --- a/tools/dkr_assets_tool_classes/common/util/errorHelper.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -#include -#include - -// Terminal colors -#define RED_TEXT "\033[1;31m" -#define GREEN_TEXT "\033[1;32m" -#define YELLOW_TEXT "\033[1;33m" -#define BLUE_TEXT "\033[1;34m" -#define MAGENTA_TEXT "\033[1;35m" -#define CYAN_TEXT "\033[1;36m" - -#define RESET_TEXT "\033[0m" - -// Requires C++17 -template -inline void display_error(Args... args) { - std::cout << RED_TEXT << "Error: "; - (std::cout << ... << args); - std::cout << RESET_TEXT << std::endl; -} - -// Requires C++17 -template -inline void display_error_and_abort(Args... args) { - display_error(args...); - std::cout << RED_TEXT << "Aborting!" << RESET_TEXT << std::endl; - throw 1; -} - diff --git a/tools/dkr_assets_tool_classes/common/util/fileHelper.cpp b/tools/dkr_assets_tool_classes/common/util/fileHelper.cpp deleted file mode 100644 index dce18bde..00000000 --- a/tools/dkr_assets_tool_classes/common/util/fileHelper.cpp +++ /dev/null @@ -1,238 +0,0 @@ -#include "fileHelper.h" -#include "md5.h" - -std::string assetsFolderPath = ""; -std::string version = ""; - -bool is_asset_folder_path_defined() { - return assetsFolderPath != ""; -} - -void set_assets_folder_path(std::string path) { - assetsFolderPath = path; -} - -std::string get_asset_folder_path() { - return assetsFolderPath; -} - -void set_version(std::string ver) { - version = ver; -} - -std::string get_version() { - return version; -} - -std::vector read_binary_file(std::string filename) { - std::ifstream is; - is.open(filename.c_str(), std::ios::binary); - is.seekg(0, std::ios::end); - size_t filesize = is.tellg(); - is.seekg(0, std::ios::beg); - std::vector bytes(filesize); - is.read((char *)bytes.data(), filesize); - is.close(); - return bytes; -} - -void write_binary_file(std::vector &data, std::string filepath) { - std::ofstream wf(filepath.c_str(), std::ios::out | std::ios::binary); - wf.write((char *)&data[0], data.size()); - wf.close(); -} - -std::string read_text_file(std::string filename) { - std::ifstream t(filename); - t.seekg(0, std::ios::end); - size_t size = t.tellg(); - std::string buffer(size, ' '); - t.seekg(0); - t.read(&buffer[0], size); - return buffer; -} - -void write_text_file(std::string text, std::string filepath) { - std::ofstream myfile; - myfile.open(filepath); - myfile << text; - myfile.close(); -} - -bool path_exists(std::string path) { - return fs::exists(path); -} - -void path_must_exist(std::string path) { - if(!fs::exists(path)) { - display_error_and_abort("Error: Path \"", path, "\" does not exist!"); - } -} - -bool path_is_directory(std::string strPath) { - fs::path path(strPath); - std::error_code ec; - return fs::is_directory(path, ec); -} - -std::vector get_filenames_from_directory(std::string dirPath) { - std::vector out; - for (const auto &file : fs::recursive_directory_iterator(dirPath)) { - out.push_back(file.path()); - } - return out; -} - -std::vector get_filenames_from_directory_only(std::string dirPath) { - std::vector out; - for (const auto &file : fs::directory_iterator(dirPath)) { - out.push_back(file.path()); - } - return out; -} - -std::vector get_filenames_from_directory_only_with_extension(std::string dirPath, std::string extension) { - std::vector out; - for (const auto &file : fs::directory_iterator(dirPath)) { - fs::path path = file.path(); - if(ends_with(path, extension)) { - out.push_back(path); - } - } - return out; -} - - -std::vector get_folders_from_directory_only(std::string dirPath) { - std::vector out; - for (const auto &file : fs::directory_iterator(dirPath)) { - if(file.is_directory()) { - out.push_back(file.path()); - } - } - return out; -} - -std::vector get_filenames_from_directory_with_extension(std::string dirPath, std::string extension) { - std::vector out; - for (const auto &file : fs::recursive_directory_iterator(dirPath)) { - std::string path = file.path(); - if(ends_with(path, extension)) { - out.push_back(path); - } - } - return out; -} - -std::vector get_filenames_from_directory_without_extension(std::string dirPath, std::string extension) { - std::vector out; - for (const auto &file : fs::recursive_directory_iterator(dirPath)) { - std::string path = file.path(); - if(!ends_with(path, extension)) { - out.push_back(path); - } - } - return out; -} - -void create_directory(std::string directory) { - if(!fs::is_directory(directory)) { - fs::create_directories(directory); - } -} - -std::string get_filename_from_full_path(std::string path, bool excludeExtension) { - size_t lastSlash = path.rfind("/"); - if (lastSlash != std::string::npos) { - path = path.substr(lastSlash + 1); - } - if(excludeExtension) { - size_t dot = path.find("."); - if (dot != std::string::npos) { - path = path.substr(0, dot); - } - } - return path; -} - -std::string get_directory_from_full_path(std::string path) { - return path.substr(0, path.rfind("/")); -} - -void ensure_that_path_exists(std::string path) { - if(path_exists(path)) { - return; - } - create_directory(get_directory_from_full_path(path)); -} - - -void copy_file(std::string srcPath, std::string dstPath) { - fs::copy(srcPath, dstPath, fs::copy_options::overwrite_existing); -} - -void recursively_copy_directory(std::string srcPath, std::string dstPath) { - fs::copy(srcPath, dstPath, fs::copy_options::recursive | fs::copy_options::overwrite_existing); -} - -void delete_directory(std::string dirPath) { - if(path_exists(dirPath)) { - fs::remove_all(dirPath); - } -} - -void delete_path(std::string path) { - if(path_exists(path)) { - if(path_is_directory(path)) { - fs::remove_all(path); - } else { - fs::remove(path); - } - } -} - -std::string replace_extension(std::string path, std::string newExtension) { - return path.substr(0, path.rfind(".")) + newExtension; -} - -bool starts_with(const std::string &a, const std::string &b) { - return a.rfind(b, 0) == 0; -} - -bool ends_with(const std::string &a, const std::string &b) { - if (b.size() > a.size()) return false; - return std::equal(a.begin() + a.size() - b.size(), a.end(), b.begin()); -} - -void make_lowercase(std::string& input) { - for(char& character : input) { - character = std::tolower(character); - } -} - -void make_uppercase(std::string& input) { - for(char& character : input) { - character = std::toupper(character); - } -} - -std::string calculate_md5(std::vector &bytes) { - md5::Digest digest = md5::compute(bytes); - std::stringstream ss; - - // set up stringstream format - ss << std::hex << std::setfill('0'); - - for(uint8_t uc: digest) { - ss << std::setw(2) << (int)uc; - } - - return ss.str(); -} - -std::string calculate_file_md5(std::string filepath) { - std::vector bytes = read_binary_file(filepath); - return calculate_md5(bytes); -} - - diff --git a/tools/dkr_assets_tool_classes/common/util/fileHelper.h b/tools/dkr_assets_tool_classes/common/util/fileHelper.h deleted file mode 100644 index fd69d741..00000000 --- a/tools/dkr_assets_tool_classes/common/util/fileHelper.h +++ /dev/null @@ -1,53 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include - -// C++17 -#include -namespace fs = std::filesystem; - -#include "errorHelper.h" - -bool is_asset_folder_path_defined(); -void set_assets_folder_path(std::string path); -std::string get_asset_folder_path(); -void set_version(std::string ver); -std::string get_version(); - -std::vector read_binary_file(std::string filename); -void write_binary_file(std::vector &data, std::string filepath); -std::string read_text_file(std::string filename); -void write_text_file(std::string text, std::string filepath); -bool path_exists(std::string path); -void path_must_exist(std::string path); -bool path_is_directory(std::string strPath); -std::vector get_filenames_from_directory(std::string dirPath); -std::vector get_filenames_from_directory_only(std::string dirPath); -std::vector get_filenames_from_directory_only_with_extension(std::string dirPath, std::string extension); -std::vector get_folders_from_directory_only(std::string dirPath); -std::vector get_filenames_from_directory_with_extension(std::string dirPath, std::string extension); -std::vector get_filenames_from_directory_without_extension(std::string dirPath, std::string extension); -void create_directory(std::string directory); -std::string get_filename_from_full_path(std::string path, bool excludeExtension); -std::string get_directory_from_full_path(std::string path); -void ensure_that_path_exists(std::string path); -void copy_file(std::string srcPath, std::string dstPath); -void recursively_copy_directory(std::string srcPath, std::string dstPath); -void delete_directory(std::string dirPath); -void delete_path(std::string dirPath); -std::string replace_extension(std::string path, std::string newExtension); -bool starts_with(const std::string &a, const std::string &b); -bool ends_with(const std::string &a, const std::string &b); -void make_lowercase(std::string &input); -void make_uppercase(std::string &input); - -std::string calculate_md5(std::vector &bytes); -std::string calculate_file_md5(std::string filepath); - diff --git a/tools/dkr_assets_tool_classes/common/util/jsonHelper.cpp b/tools/dkr_assets_tool_classes/common/util/jsonHelper.cpp deleted file mode 100644 index 1e24343f..00000000 --- a/tools/dkr_assets_tool_classes/common/util/jsonHelper.cpp +++ /dev/null @@ -1,201 +0,0 @@ -#include "jsonHelper.h" - -bool hasLoadedAssetsJson = false; -json::JSON assetsJson; - -std::string lastSectionName = ""; -json::JSON *lastSection; -std::unordered_map sectionCache; - -std::string lastJsonFileName = ""; -json::JSON *lastJsonFile; -std::unordered_map jsonFileCache; - -#define ASSETS_FILENAME "assets.meta.json" - -json::JSON load_assets_json(std::string assetsFolder, std::string jsonName) { - std::string jsonFilepath = assetsFolder + "/" + jsonName; - path_must_exist(jsonFilepath); - return json::JSON::Load(read_text_file(jsonFilepath)); -} - -void write_json(json::JSON &jsonData, std::string filename) { - std::ofstream myfile; - myfile.open(filename); - myfile << jsonData; - myfile.close(); -} - -std::mutex assetsJsonMutex; - -void make_sure_assets_json_is_loaded() { - assetsJsonMutex.lock(); - if(!hasLoadedAssetsJson) { - if(!is_asset_folder_path_defined()) { - display_error_and_abort("assetsFolderPath not defined! Make sure set_assets_folder_path() is called somewhere!"); - } - std::string assetsJsonPath = get_asset_folder_path() + "/" + get_version() + "/" + ASSETS_FILENAME; - path_must_exist(assetsJsonPath); - std::string assetsJsonText = read_text_file(assetsJsonPath); - assetsJson = json::JSON::Load(assetsJsonText); - hasLoadedAssetsJson = true; - } - assetsJsonMutex.unlock(); -} - - -std::mutex sectionJsonMutex; - -json::JSON *get_section_json(std::string sectionName) { - make_sure_assets_json_is_loaded(); - sectionJsonMutex.lock(); - std::string assetsFolderPath = get_asset_folder_path() + "/" + get_version(); - if(sectionName == lastSectionName) { - sectionJsonMutex.unlock(); - return lastSection; - } else if(sectionCache.find(sectionName) == sectionCache.end()) { - // section not found in cache, so it needs to be loaded/defined! - json::JSON assetSection = assetsJson["assets"]["sections"][sectionName]; - if(assetSection.JSONType() == json::JSON::Class::String) { - std::string sectionJsonLocalPath = assetsJson["assets"]["sections"][sectionName].ToString(); - make_lowercase(sectionJsonLocalPath); - std::string jsonPath = assetsFolderPath + "/" + sectionJsonLocalPath; - path_must_exist(jsonPath); - sectionCache[sectionName] = json::JSON::Load(read_text_file(jsonPath)); - } else { - sectionCache[sectionName] = assetSection; - } - } - lastSectionName = sectionName; - lastSection = §ionCache[sectionName]; - sectionJsonMutex.unlock(); - return lastSection; -} - -std::string get_build_id_from_section(std::string sectionName, int index) { - json::JSON *sectionJson = get_section_json(sectionName); - if(sectionJson->IsNull()) { - return "null"; - } - return (*sectionJson)["files"]["order"][index].ToString(); -} - -int get_index_of_string_from_json_array(json::JSON &jsonArray, std::string value) { - for(int i = 0; i < jsonArray.length(); i++) { - if(jsonArray[i].ToString() == value) { - return i; - } - } - return -1; -} - -int get_index_from_build_id(std::string sectionName, std::string buildId) { - json::JSON *sectionJson = get_section_json(sectionName); - return get_index_of_string_from_json_array((*sectionJson)["files"]["order"], buildId); -} - -int get_tex_2d_index_from_build_id(std::string texBuildId) { - return get_index_from_build_id("ASSET_TEXTURES_2D", texBuildId); -} - -std::vector get_order(json::JSON orderJson) { - std::vector out; - for(auto &entry : orderJson.ArrayRange()) { - out.push_back(entry.ToString()); - } - return out; -} - -std::vector get_section_order(std::string sectionName) { - json::JSON *sectionJson = get_section_json(sectionName); - return get_order((*sectionJson)["files"]["order"]); -} -std::vector get_assets_order() { - make_sure_assets_json_is_loaded(); - return get_order(assetsJson["assets"]["order"]); -} - -std::string get_filename_from_section_entry(std::string sectionName, std::string entryName) { - json::JSON *sectionJson = get_section_json(sectionName); - return (*sectionJson)["files"]["sections"][entryName]["filename"].ToString(); -} - - -int get_asset_count() { - make_sure_assets_json_is_loaded(); - return assetsJson["assets"]["order"].length(); -} - -#define JSON_IS_TYPE(jsonObj, type) jsonObj.JSONType() == json::JSON::Class::type -#define JSON_IS_OBJECT(jsonObj) JSON_IS_TYPE(jsonObj, Object) -#define JSON_IS_ARRAY(jsonObj) JSON_IS_TYPE(jsonObj, Array) -#define JSON_IS_STRING(jsonObj) JSON_IS_TYPE(jsonObj, String) - -bool does_json_array_contain_string(json::JSON &arrayJson, std::string value) { - for(json::JSON &childJson : arrayJson.ArrayRange()) { - if(JSON_IS_STRING(childJson)) { - if(childJson.ToString() == value) return true; - } - } - return false; -} - -void recursively_combine_json(json::JSON &mainJson, json::JSON &addJson) { - if(JSON_IS_OBJECT(mainJson) && JSON_IS_OBJECT(addJson)) { - for(auto &keyValuePair : addJson.ObjectRange()) { - std::string key = keyValuePair.first; - json::JSON newJson = keyValuePair.second; - if(!mainJson.hasKey(key)) { - mainJson[key] = newJson; - continue; - } - if(JSON_IS_OBJECT(newJson)) { - recursively_combine_json(mainJson[key], newJson); - continue; - } - if(JSON_IS_ARRAY(newJson)) { - for(json::JSON &orderEntry : newJson.ArrayRange()) { - // "order" is a special case, where the array should be a set. - if(key == "order" && does_json_array_contain_string(mainJson[key], orderEntry.ToString())) { - // Order already has the value in its array, so just ignore it. - continue; - } - mainJson[key].append(orderEntry.ToString()); - } - continue; - } - // Not an object or array, so just overwrite the value. - mainJson[key] = newJson; - } - } -} - -void combine_json_files(std::string src1Path, std::string src2Path, std::string outputPath) { - path_must_exist(src1Path); - path_must_exist(src2Path); - json::JSON mainJson = json::JSON::Load(read_text_file(src1Path)); - json::JSON addJson = json::JSON::Load(read_text_file(src2Path)); - recursively_combine_json(mainJson, addJson); - write_json(mainJson, outputPath); -} - -json::JSON *load_json_file(std::string filename) { - if(filename == lastJsonFileName) { - return lastJsonFile; - } else if(jsonFileCache.find(filename) == jsonFileCache.end()) { - // file not found in cache, so it needs to be loaded! - path_must_exist(filename); - jsonFileCache[filename] = json::JSON::Load(read_text_file(filename)); - } - lastJsonFileName = filename; - lastJsonFile = &jsonFileCache[filename]; - return lastJsonFile; -} - -std::string get_source_section_for_table(std::string tableSectionName) { - json::JSON *tableSection = get_section_json(tableSectionName); - return (*tableSection)["for"].ToString(); -} - - - diff --git a/tools/dkr_assets_tool_classes/common/util/jsonHelper.h b/tools/dkr_assets_tool_classes/common/util/jsonHelper.h deleted file mode 100644 index 1ca9b3b2..00000000 --- a/tools/dkr_assets_tool_classes/common/util/jsonHelper.h +++ /dev/null @@ -1,152 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../../libs/json.hpp" - -#include "fileHelper.h" -#include "errorHelper.h" - -void write_json(json::JSON &assetsJSON, std::string filename); -json::JSON load_assets_json(std::string assetsFolder, std::string jsonName); -std::string get_build_id_from_section(std::string sectionName, int index); -int get_index_of_string_from_json_array(json::JSON &jsonArray, std::string value); -int get_index_from_build_id(std::string sectionName, std::string buildId); -int get_tex_2d_index_from_build_id(std::string texBuildId); -std::vector get_section_order(std::string sectionName); -std::vector get_assets_order(); -std::string get_filename_from_section_entry(std::string sectionName, std::string entryName); -std::string get_source_section_for_table(std::string tableSectionName); -int get_asset_count(); -void combine_json_files(std::string src1Path, std::string src2Path, std::string outputPath); - -// The variadic templates require C++17. They also need to be defined in the header, not in the cpp file. - -// Do not use these outside of this file! They are exposed in the header only for the variadic template functions. -std::vector get_order(json::JSON orderJson); -json::JSON *get_section_json(std::string sectionName); -json::JSON *load_json_file(std::string filename); - -template -inline json::JSON json_get(json::JSON &json, FirstKey const& key, RestKeys const&... rest_keys) { - if constexpr(sizeof...(RestKeys) == 0) { - return json[key]; - } else { - return json_get(json[key], rest_keys...); - } -} - -template -inline bool _json_has_key(json::JSON &json, FirstKey const& key, RestKeys const&... rest_keys) { - if constexpr(sizeof...(RestKeys) == 0) - return json.hasKey(key); - else - return _json_has_key(json[key], rest_keys...); -} - -template -inline int get_int_from_json(std::string filename, FirstKey const& key, RestKeys const&... rest_keys) { - json::JSON *json = load_json_file(filename); - return json_get(*json, key, rest_keys...).ToInt(); -} - -template -inline bool get_bool_from_json(std::string filename, FirstKey const& key, RestKeys const&... rest_keys) { - json::JSON *json = load_json_file(filename); - return json_get(*json, key, rest_keys...).ToBool(); -} - -template -inline float get_float_from_json(std::string filename, FirstKey const& key, RestKeys const&... rest_keys) { - json::JSON *json = load_json_file(filename); - return json_get(*json, key, rest_keys...).ToFloat(); -} - -template -inline std::string get_string_from_json(std::string filename, FirstKey const& key, RestKeys const&... rest_keys) { - json::JSON *json = load_json_file(filename); - return json_get(*json, key, rest_keys...).ToString(); -} - -template -inline std::vector get_array_from_json(std::string filename, FirstKey const& key, RestKeys const&... rest_keys) { - json::JSON *json = load_json_file(filename); - json::JSON arrayJson = json_get(*json, key, rest_keys...); - return get_order(arrayJson); -} - -inline std::vector get_array_from_json(std::string filename) { - return get_order(*load_json_file(filename)); -} - -template -inline int get_array_length_from_json(std::string filename, FirstKey const& key, RestKeys const&... rest_keys) { - json::JSON *json = load_json_file(filename); - return json_get(*json, key, rest_keys...).length(); -} - -template -inline bool json_has_key(std::string filename, FirstKey const& key, RestKeys const&... rest_keys) { - json::JSON *json = load_json_file(filename); - if constexpr(sizeof...(RestKeys) == 0) { - return json->hasKey(key); - } else { - return _json_has_key(*json, key, rest_keys...); - } -} - -template -inline int get_int_from_section(std::string sectionName, FirstKey const& key, RestKeys const&... rest_keys) { - json::JSON *json = get_section_json(sectionName); - return json_get(*json, key, rest_keys...).ToInt(); -} - -template -inline std::string get_string_from_section(std::string sectionName, FirstKey const& key, RestKeys const&... rest_keys) { - json::JSON *json = get_section_json(sectionName); - return json_get(*json, key, rest_keys...).ToString(); -} - -template -inline std::vector get_array_from_section(std::string sectionName, FirstKey const& key, RestKeys const&... rest_keys) { - json::JSON *json = get_section_json(sectionName); - json::JSON arrayJson = json_get(*json, key, rest_keys...); - return get_order(arrayJson); -} - -template -inline int get_array_length_from_section(std::string sectionName, FirstKey const& key, RestKeys const&... rest_keys) { - json::JSON *json = get_section_json(sectionName); - return json_get(*json, key, rest_keys...).length(); -} - -template -inline int get_index_of_string_array_value_from_section(std::string sectionName, std::string value, FirstKey const& key, RestKeys const&... rest_keys) { - json::JSON *json = get_section_json(sectionName); - - std::vector arr = get_array_from_section(sectionName, key, rest_keys...); - for(int i = 0; i < arr.size(); i++) { - if(arr[i] == value) { - return i; - } - } - return -1; // Value not found in array. -} - -template -inline bool section_has_key(std::string sectionName, FirstKey const& key, RestKeys const&... rest_keys) { - json::JSON *json = get_section_json(sectionName); - if constexpr(sizeof...(RestKeys) == 0) - return json->hasKey(key); - else - return _json_has_key(*json, key, rest_keys...); -} - - diff --git a/tools/dkr_assets_tool_classes/compiler/compiler.cpp b/tools/dkr_assets_tool_classes/compiler/compiler.cpp deleted file mode 100644 index fd06349b..00000000 --- a/tools/dkr_assets_tool_classes/compiler/compiler.cpp +++ /dev/null @@ -1,253 +0,0 @@ -#include "compiler.h" - -// Needs to be defined here. -#include "../libs/zip_file.hpp" - - -const std::string JSON_WRITE_MODE_REPLACE = "replace"; -const std::string JSON_WRITE_MODE_MERGE = "merge"; -const std::string DEFAULT_JSON_WRITE_MODE = JSON_WRITE_MODE_REPLACE; - -const std::string BASE_DIR_NAME = "vanilla"; -const std::string EXT_DIR_NAME = "packages"; - -void print_text(std::string text) { - std::cout << text << std::endl; -} - -void print_coloured_text(std::string color, std::string text) { - std::cout << color << text << RESET_TEXT << std::endl; -} - -AssetCompiler::AssetCompiler() { - print_text("Compiling assets..."); - - std::string assetsDirectory = get_asset_folder_path(); - std::string version = get_version(); - - std::string vanillaDirPath = assetsDirectory + "/" + BASE_DIR_NAME; - std::string outDirPath = assetsDirectory + "/" + version; - std::string packagesDirPath = assetsDirectory + "/" + EXT_DIR_NAME + "/" + version; - std::string tempDirPath = assetsDirectory + "/_temp"; - - try { - // 1.) Create temporary directory for working files. - create_directory(tempDirPath); - - // 2.) Create "compiled" directory for output files - std::string compiledDir = tempDirPath + "/__compiled__"; - - // Copy vanilla folder to the compiled directory as the baseline. - print_text("Copying vanilla files..."); - recursively_copy_directory(vanillaDirPath + "/" + version, compiledDir); - - print_text("Reading package order..."); - std::string packageOrderFilepath = packagesDirPath + "/order.meta.json"; - - bool isVanilla = true; - - if(path_exists(packageOrderFilepath)) { - std::vector packageOrder = get_array_from_json(packageOrderFilepath); - for(std::string &packageName : packageOrder) { - print_text("Applying package \"" + packageName + "\"..."); - if(packageName.length() == 0) { - display_error_and_abort("The package \"\" does not exist!"); - } - apply_package(packagesDirPath, packageName, tempDirPath, compiledDir); - isVanilla = false; - } - } - - if(isVanilla) { - print_coloured_text(CYAN_TEXT, "Assets are vanilla."); - } else { - print_coloured_text(CYAN_TEXT, "Assets are modified."); - } - - print_text("Merging modified files..."); - merge_output(compiledDir, outDirPath); - - // Remove the temp directory - print_text("Cleaning up..."); - delete_directory(tempDirPath); - } catch (int e) { - delete_directory(tempDirPath); - throw e; - } - - print_text("Done!"); -} - -AssetCompiler::~AssetCompiler() { - -} - -void ensure_meta_json_has_key(std::string &packageName, std::string &metaJsonFilepath, std::string key) { - if(!json_has_key(metaJsonFilepath, key)) { - display_error_and_abort("\"", key, "\" not defined in ", packageName, "'s meta.json file!"); - } -} - -void AssetCompiler::check_meta_json(std::string &packageName, std::string metaJsonFilepath) { - if(!path_exists(metaJsonFilepath)) { - display_error_and_abort("The package \"", packageName, "\" is missing a meta.json file!"); - } - - ensure_meta_json_has_key(packageName, metaJsonFilepath, "name"); - ensure_meta_json_has_key(packageName, metaJsonFilepath, "pkg-version"); - ensure_meta_json_has_key(packageName, metaJsonFilepath, "authors"); - ensure_meta_json_has_key(packageName, metaJsonFilepath, "revision"); - ensure_meta_json_has_key(packageName, metaJsonFilepath, "revision-minor"); - - int revision = get_int_from_json(metaJsonFilepath, "revision"); - int revisionMinor = get_int_from_json(metaJsonFilepath, "revision-minor"); - - if(revision != REVISION_NUMBER || revisionMinor != REVISION_MINOR_NUMBER) { - display_error_and_abort("The package \"", packageName, "\" is not supported. It's revision number is ", revision, ".", revisionMinor, ", when it should be ", REVISION_NUMBER, ".", REVISION_MINOR_NUMBER, "!"); - } -} - -void AssetCompiler::apply_package(std::string &packagesDirPath, std::string &packageName, std::string &tempDirPath, std::string &outDirPath) { - std::string packageDir = packagesDirPath + "/" + packageName; - - bool isZip = false; - - if(ends_with(packageName, ".zip")) { - packageName = packageName.substr(0, packageName.length() - 4); - isZip = true; - } else if(!path_exists(packageDir) && path_exists(packageDir + ".zip")) { - packageDir += ".zip"; - isZip = true; - } else if(!path_exists(packageDir)) { - display_error_and_abort("The package \"", packageName, "\" does not exist!"); - } - - if(isZip) { - miniz_cpp::zip_file file(packageDir); - packageDir = tempDirPath + "/" + packageName; - // Make sure a subdirectory with the name of the package exists in the temp directory. - if(file.has_file("meta.json")) { - create_directory(packageDir); - file.extractall(packageDir); - } else { - file.extractall(tempDirPath); - } - } - - check_meta_json(packageName, packageDir + "/meta.json"); - - std::vector jsonFiles = get_filenames_from_directory_with_extension(packageDir, ".json"); - std::vector otherFiles = get_filenames_from_directory_without_extension(packageDir, ".json"); - for(int i = 0; i < jsonFiles.size(); i++) { - std::string localPath = jsonFiles[i].substr(packageDir.length() + 1); - - if(localPath == "meta.json") { - continue; // Skip meta.json file. - } - - std::string outPath = outDirPath + "/" + localPath; - - std::string write_mode = get_string_from_json(jsonFiles[i], "pkg-write"); - make_lowercase(write_mode); - if(write_mode == "") { - write_mode = DEFAULT_JSON_WRITE_MODE; - } - - if(write_mode == JSON_WRITE_MODE_REPLACE) { - copy_file(jsonFiles[i], outPath); - } else if(write_mode == JSON_WRITE_MODE_MERGE) { - combine_json_files(outPath, jsonFiles[i], outPath); - } else { - display_error_and_abort("Unknown json write mode: \"", write_mode, "\""); - } - } - - for(int i = 0; i < otherFiles.size(); i++) { - if(path_is_directory(otherFiles[i])) { - std::string localPath = otherFiles[i].substr(packageDir.length() + 1); - if(localPath == "meta") { - continue; // Skip meta folder if it exists. - } - std::string outPath = outDirPath + "/" + localPath; - create_directory(outPath); - } else { - std::string localPath = otherFiles[i].substr(packageDir.length() + 1); - if(starts_with(localPath, "meta/")) { - continue; // Skip files within the meta folder. - } - std::string outPath = outDirPath + "/" + localPath; - copy_file(otherFiles[i], outPath); - } - } -} - -void AssetCompiler::merge_output(std::string &tempDir, std::string &outDir) { - std::vector tempFiles = get_filenames_from_directory(tempDir); - std::vector curFiles = get_filenames_from_directory(outDir); - std::vector sameFiles, filesToAdd, filesToRemove; - - for(int i = 0; i < tempFiles.size(); i++) { - std::string tempFilepath = tempFiles[i]; - std::string localPath = tempFilepath.substr(tempDir.length() + 1); - if(path_exists(outDir + "/" + localPath)) { - sameFiles.push_back(localPath); - } else { - filesToAdd.push_back(tempFilepath); - } - } - - for(int i = 0; i < curFiles.size(); i++) { - std::string curOutFilepath = curFiles[i]; - std::string localPath = curOutFilepath.substr(outDir.length() + 1); - if(!path_exists(tempDir + "/" + localPath)) { - filesToRemove.push_back(curOutFilepath); - } - } - - for(std::string &pathToRemove : filesToRemove) { - delete_path(pathToRemove); - } - - for(std::string &pathToAdd : filesToAdd) { - std::string localPath = pathToAdd.substr(tempDir.length() + 1); - std::string outAddPath = outDir + "/" + localPath; - if(path_is_directory(pathToAdd)) { - create_directory(outAddPath); - } else { - copy_file(pathToAdd, outAddPath); - } - } - - for(std::string &sameFileLocalPath : sameFiles) { - std::string tempFilePath = tempDir + "/" + sameFileLocalPath; - std::string curFilePath = outDir + "/" + sameFileLocalPath; - if(!path_is_directory(tempFilePath)) { - bool doHashCheck = true; - if(ends_with(tempFilePath, ".json")) { - std::string pkgRebuild = "onchange"; - if(json_has_key(tempFilePath, "pkg-rebuild")) { - pkgRebuild = get_string_from_json(tempFilePath, "pkg-rebuild"); - make_lowercase(pkgRebuild); - } - if(pkgRebuild == "always") { - doHashCheck = false; - } else if(pkgRebuild == "onchange") { - doHashCheck = true; - } else { - display_error_and_abort("Unknown pkg-rebuild value \"", pkgRebuild, "\"."); - } - } - if(doHashCheck) { - std::string tempFileHash = calculate_file_md5(tempFilePath); - std::string curFileHash = calculate_file_md5(curFilePath); - if(tempFileHash != curFileHash) { - copy_file(tempFilePath, curFilePath); - } - } else { - copy_file(tempFilePath, curFilePath); - } - } - } -} - - diff --git a/tools/dkr_assets_tool_classes/compiler/compiler.h b/tools/dkr_assets_tool_classes/compiler/compiler.h deleted file mode 100644 index f50005e7..00000000 --- a/tools/dkr_assets_tool_classes/compiler/compiler.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -#include "../common/util.h" -#include "../common/types.h" -#include "../common/revision_number.h" - -class AssetCompiler { -public: - AssetCompiler(); - ~AssetCompiler(); -private: - void apply_package(std::string &packagesDirPath, std::string &packageName, std::string &tempDirPath, std::string &outDirPath); - void check_meta_json(std::string &packageName, std::string metaJsonFilepath); - void merge_output(std::string &tempDir, std::string &outDir); -}; diff --git a/tools/dkr_assets_tool_classes/extractor/config.cpp b/tools/dkr_assets_tool_classes/extractor/config.cpp deleted file mode 100644 index 3d4893dd..00000000 --- a/tools/dkr_assets_tool_classes/extractor/config.cpp +++ /dev/null @@ -1,467 +0,0 @@ -#include "config.h" - -const std::string BASE_DIR_NAME = "vanilla"; -const std::string EXT_DIR_NAME = "packages"; - -#define VANILLA_WARNING_FILENAME "PLEASE_DONT_MODIFY_ANYTHING.txt" - -ExtractConfig::ExtractConfig(std::string configFilepath, std::string outDirectory) { - std::cout << "Reading config \"" << configFilepath << "\"" << std::endl; - configJSON = json::JSON::Load(read_text_file(configFilepath)); - - this->outBaseDirectory = outDirectory + "/assets/" + BASE_DIR_NAME + "/" + configJSON["subfolder"].ToString(); - this->outDirectory = outDirectory + "/assets/" + configJSON["subfolder"].ToString(); - this->name = configJSON["config-name"].ToString(); - this->subfolder = configJSON["subfolder"].ToString(); - this->md5 = configJSON["checksum-md5"].ToString(); - this->notSupported = configJSON["not-supported"].ToString() == "true"; - - assetsJson["@version"] = this->subfolder; - assetsJson["@revision"] = REVISION_NUMBER; - assetsJson["@revision-minor"] = REVISION_MINOR_NUMBER; - - // Create package extensions folder if it doesn't exist. - if(this->subfolder == "us_1.0"){ - std::string packagesDir = outDirectory + "/assets/" + EXT_DIR_NAME + "/" + configJSON["subfolder"].ToString(); - create_directory(packagesDir); - json::JSON orderJson = json::Array(); - write_json(orderJson, packagesDir + "/order.meta.json"); - } -} - -ExtractConfig::~ExtractConfig() { -} - -void ExtractConfig::find_rom_for_this_config_and_extract(std::vector &roms) { - if(this->subfolder != "us_1.0"){ - std::cout << "Sorry, extracting only works for us_1.0 at the moment." << std::endl; - return; - } - for (ROM* rom : roms) { - if(rom->get_md5() == this->md5) { - this->rom = rom; - std::cout << "Extracting using config: \"" << this->name << "\"" << std::endl; - extract(); - return; - } - } - std::cout << "No valid ROMs were found for the config \"" << this->name << "\"" << std::endl; -} - -bool ExtractConfig::is_correct_version(std::string version) { - return this->subfolder == version; -} - -void ExtractConfig::extract_code_sections(int &romOffset) { - json::JSON codeSections = configJSON["code"]["sections"]; - int numCodeSections = codeSections.length(); - for(int i = 0; i < numCodeSections; i++) { - json::JSON section = codeSections[i]; - std::string type = section["type"].ToString(); - - json::JSON files = section["files"]; - std::string folder = this->outBaseDirectory + "/" + section["folder"].ToString(); - - if(type != "NoExtract") { - create_directory(folder); - } - - std::string key = "CODE_" + std::to_string(i); - - int numFiles = files.length(); - for(int j = 0; j < numFiles; j++) { - json::JSON file = files[j]; - int length = std::stoul(file["length"].ToString(), nullptr, 16); - extractions.push_back(ExtractInfo(key, type, folder, file["filename"].ToString(), - rom->get_bytes_from_range(romOffset, length))); - romOffset += length; - } - - } -} - -std::string get_extension_from_type(std::string type) { - if(is_json_type(type)) { - return ".json"; - } else if(is_compressed_type(type)) { - return ".cbin"; - } else { - return ".bin"; - } -} - -std::vector> get_section_files(std::vector& section, std::vector& table, std::string tableType, json::JSON& outputAsset) { - std::vector> out; - - int currentTableIndex = 0; - int scale = 1; // Each table entry is 4-bytes long. - int offset = 0; - - if(tableType == "MenuText") { - outputAsset["_text-entry-count"] = std::to_string(get_big_endian_word(table, currentTableIndex*4)); - currentTableIndex = 1; // The first entry is the number of text entries for each language. - } else if(tableType == "TTGhosts") { - scale = 2; // Each table entry is 8-bytes long. - offset = 1; // offset by 4 bytes. - //outputAsset["meta"] = json::Array(); - } else if (tableType == "GameText") { - // Temporary - outputAsset["_textTypes"] = json::Array(); - } - - uint32_t currentTableValue = get_big_endian_word(table, (currentTableIndex * scale + offset)*4); - uint32_t nextTableValue = get_big_endian_word(table, ((currentTableIndex + 1) * scale + offset)*4); - - if (tableType == "Audio") { - // The audio table doesn't start at offset 0, so this check will extract - // the first actual part of the audio section. - std::vector file(section.begin(), section.begin() + currentTableValue); - out.push_back(file); - } - - while(nextTableValue != 0xFFFFFFFF) { - - if(tableType == "GameText") { - bool isDialog = (currentTableValue & 0x80000000) == 0x80000000; - outputAsset["_textTypes"].append(isDialog ? 1 : 0); - currentTableValue &= 0x7FFFFFFF; - nextTableValue &= 0x7FFFFFFF; - } else if(tableType == "Miscellaneous") { - currentTableValue *= 4; - nextTableValue *= 4; - } - - int length = nextTableValue - currentTableValue; - if(length < 0) { - display_error_and_abort("Invalid table length: ", length, "\ncurrentTableValue: ", currentTableValue, "\nnextTableValue: ", nextTableValue); - } - - std::vector file(section.begin() + currentTableValue, section.begin() + nextTableValue); - out.push_back(file); - - currentTableIndex++; - currentTableValue = get_big_endian_word(table, (currentTableIndex * scale + offset)*4); - nextTableValue = get_big_endian_word(table, ((currentTableIndex + 1) * scale + offset)*4); - } - - return out; -} - -int ExtractConfig::get_file_index(json::JSON &files, int searchIndex) { - int numFiles = files.length(); - - for (int i = 0; i < numFiles; i++) { - if (files[i]["index"].ToInt() == searchIndex) { - return i; - } - } - - return -1; -} - -void ExtractConfig::extract_asset_section(json::JSON §ion, std::vector> §ionsData, int i) { - std::string folder = this->outBaseDirectory + "/" + section["folder"].ToString(); - std::string type = section["type"].ToString(); - std::string build_id = section["build-id"].ToString(); - - if (type != "NoExtract") { - create_directory(folder); - } - - json::JSON sectionOut = json::Object(); - - sectionOut["type"] = type; - - std::string defaultSubdirectory = ""; - - if (section.hasKey("files-default-folder")) { - defaultSubdirectory = section["files-default-folder"].ToString(); - } - - if (section.hasKey("folder") && !section["folder"].IsNull()) { - sectionOut["folder"] = section["folder"]; - } - - if (section.hasKey("table")) { - int tableIndex = section["table"].ToInt(); - sectionOut["table"] = assetsJson["assets"]["order"][tableIndex]; - - std::vector> sectionFiles - = get_section_files(sectionsData[i], sectionsData[tableIndex], type, sectionOut); - int numberOfSectionFiles = sectionFiles.size(); - - if (numberOfSectionFiles > 0) { - sectionOut["files"] = json::Object(); - sectionOut["files"]["order"] = json::Array(); - sectionOut["files"]["sections"] = json::Object(); - } - - bool sectionHasFilesSubsection = section.hasKey("files"); - bool flipTextureDefault = false; - bool hasDefaultBuildIdPrefix = section.hasKey("default-build-id-prefix"); - std::string buildIdPrefix = ""; - - if (hasDefaultBuildIdPrefix) { - buildIdPrefix = section["default-build-id-prefix"].ToString(); - } - - if (type == "Textures") { - if (section.hasKey("flip-textures-by-default")) { - flipTextureDefault = section["flip-textures-by-default"].ToBool(); - } - } - - for (int j = 0; j < numberOfSectionFiles; j++) { - std::unordered_map* tags = nullptr; - std::string filename = ""; - std::string key = ""; - std::string subfolder = ""; - json::JSON filesInfo; - int localFileIndex = -1; - bool flipTexture = flipTextureDefault; - if (sectionHasFilesSubsection) { - localFileIndex = get_file_index(section["files"], j); - if (localFileIndex >= 0) { - filesInfo = section["files"][localFileIndex]; - if (filesInfo.hasKey("filename")) { - filename = filesInfo["filename"].ToString(); - } - if (filesInfo.hasKey("build-id")) { - key = filesInfo["build-id"].ToString(); - } - if (filesInfo.hasKey("flip-tex")) { - flipTexture = filesInfo["flip-tex"].ToBool(); - } - if (filesInfo.hasKey("folder")) { - subfolder = filesInfo["folder"].ToString(); - } else if (defaultSubdirectory.length() > 0) { - subfolder = defaultSubdirectory; - } - } - else { - if (defaultSubdirectory.length() > 0) { - subfolder = defaultSubdirectory; - } - } - } - if (filename == "") { - std::stringstream filenameStream; - filenameStream << "unknown_" << i << "_" << j; - filename = filenameStream.str(); - } - if (key == "") { - std::stringstream keyStream; - if (hasDefaultBuildIdPrefix) { - keyStream << buildIdPrefix << j; - } else { - keyStream << build_id << "_" << j; - } - key = keyStream.str(); - } - make_uppercase(key); - sectionOut["files"]["order"].append(key); - sectionOut["files"]["sections"][key] = json::Object(); - sectionOut["files"]["sections"][key]["filename"] = filename + get_extension_from_type(type); - if (subfolder.length() > 0) { - sectionOut["files"]["sections"][key]["filename"] = subfolder + "/" + sectionOut["files"]["sections"][key]["filename"].ToString(); - } - - if (type == "GameText") { - if (tags == nullptr) { - tags = new std::unordered_map(); - } - (*tags)["text-type"] = (sectionOut["_textTypes"][j].ToInt() == 1) ? "Dialog" : "Textbox"; - } - else if (type == "MenuText") { - if (tags == nullptr) { - tags = new std::unordered_map(); - } - (*tags)["text-entry-count"] = sectionOut["_text-entry-count"].ToString(); - int numberOfEntries = stoi((*tags)["text-entry-count"]); - for (int k = 0; k < numberOfEntries; k++) { - if (!section["menu-text-build-ids"][k].IsNull()) { - (*tags)["text-entry-build-id_" + std::to_string(k)] = section["menu-text-build-ids"][k].ToString(); - } - } - if (!sectionOut.hasKey("menu-text-build-ids")) { - sectionOut["menu-text-build-ids"] = section["menu-text-build-ids"]; - } - sectionOut["files"]["sections"][key]["language"] = section["language-order"][j]; - } - else if (type == "Textures") { - if (tags == nullptr) { - tags = new std::unordered_map(); - } - (*tags)["flip-texture_" + key] = flipTexture ? "true" : "false"; - } - if (subfolder.length() > 0) { - subfolder = folder + "/" + subfolder; - } else { - subfolder = folder; - } - extractions.push_back(ExtractInfo(key, type, subfolder, filename, sectionFiles[j], tags)); - } - - if (type == "GameText") { - sectionOut.erase("_textTypes"); - } else if (type == "MenuText") { - sectionOut.erase("_text-entry-count"); - } - } else { - if (type != "Table" && type != "NoExtract" && type != "Empty") { - // No lookup table associated, so the section is assumed to be 1 file. - std::string filename = ""; - if (section.hasKey("files")) { - filename = section["files"][0]["filename"].ToString(); - } - if (filename == "") { - std::stringstream filenameStream; - filenameStream << "unknown_" << i; - filename = filenameStream.str(); - } - sectionOut["filename"] = filename + get_extension_from_type(type); - extractions.push_back(ExtractInfo(build_id, type, folder, filename, sectionsData[i])); - - if (type == "Fonts") { - //sectionOut["fonts"] = json::Object(); - sectionOut["fonts-order"] = json::Array(); - for (auto& fontName : section["font-names"].ArrayRange()) { - std::string fontid = "ASSET_FONTS_" + fontName.ToString(); - make_uppercase(fontid); - //sectionOut["fonts"][fontid] = fontName.ToString() + ".json"; - sectionOut["fonts-order"].append(fontid); - } - } - } else if (type == "Table") { - sectionOut["for"] = section["for"]; - } - } - - if (type != "Table" && type != "NoExtract" && type != "Empty") { - std::string sectionFilename = build_id + ".meta.json"; - make_lowercase(sectionFilename); - write_json(sectionOut, this->outBaseDirectory + "/" + sectionFilename); - assetsJson["assets"]["sections"][build_id] = sectionFilename; - } - else { - assetsJson["assets"]["sections"][build_id] = sectionOut; - } -} - -void ExtractConfig::extract_asset_sections(int &romOffset) { - /* Make sure the assets section has the correct number of entries. */ - json::JSON assetSections = configJSON["assets"]["sections"]; - int numAssetSections = assetSections.length(); - int numAssetSectionsFromTable = rom->get_uint(romOffset); - - if(numAssetSections != numAssetSectionsFromTable) { - display_error_and_abort("Number of asset sections in config does not match ROM.\nNumber of asset sections in Config: ", - numAssetSections, "\nNumber of asset sections in ROM: ", numAssetSectionsFromTable); - } - - romOffset += 4; - int tableOffset = romOffset; - romOffset += (numAssetSections + 1) * 4; - int assetsStart = romOffset; - - std::vector> sectionsData; - - /* Read the main assets look-up table for section lengths */ - for(int i = 0; i < numAssetSections; i++) { - int assetSectionLength = rom->get_uint(tableOffset + ((i + 1) * 4)) - rom->get_uint(tableOffset + (i * 4)); - sectionsData.push_back(rom->get_bytes_from_range(romOffset, assetSectionLength)); - romOffset += assetSectionLength; - } - - romOffset = assetsStart; - - assetsJson["assets"] = json::Object(); - assetsJson["assets"]["order"] = json::Array(); - assetsJson["assets"]["sections"] = json::Object(); - - /* Extract the assets sections */ - - // First loop to get the order array in place. - for(int i = 0; i < numAssetSections; i++) { - json::JSON section = assetSections[i]; - std::string build_id = section["build-id"].ToString(); - assetsJson["assets"]["order"].append(build_id); - } - // Second loop for everything else - for(int i = 0; i < numAssetSections; i++) { - extract_asset_section(assetSections[i], sectionsData, i); - } -} - -void write_vanilla_warning_file(std::string baseDirectory) { - std::string warningText = ""; - warningText += "This directory contains all the non-modified assets for DKR.\n"; - warningText += "It is VERY important that you do not modify any of the assets in this directory.\n"; - warningText += "If you do, then you might create headaches for yourself later when trying to revert back to a matching build.\n"; - write_text_file(warningText, baseDirectory + "/../" + VANILLA_WARNING_FILENAME); -} - -void ExtractConfig::execute_extraction() { - // These braces are important, because I want the ThreadPool to call its destructor by going out of scope. - { - //ThreadPool pool(std::thread::hardware_concurrency()); // TODO: Solve race condition issues. - ThreadPool pool(1); - - for(int i = 0; i < extractions.size(); i++) { - std::string key = extractions[i].key; - std::string type = extractions[i].type; - std::string folder = extractions[i].folder; - std::string filename = extractions[i].filename; - std::vector data = extractions[i].data; - std::unordered_map *tags = extractions[i].tags; - pool.enqueue([this, key, type, folder, filename, data, tags] { - std::string outFilepath = folder + "/" + filename; - - if(type == "MenuText") { - ExtractMenuText(key, data, outFilepath + ".json", tags); - } else if(type == "GameText") { - ExtractGameText(key, data, outFilepath + ".json", tags); - } else if(type == "TTGhosts") { - ExtractTTGhost(key, data, outFilepath + ".json", configJSON); - } else if(type == "LevelNames") { - ExtractLevelName(key, data, outFilepath + ".json"); - } else if(type == "LevelHeaders") { - ExtractLevelHeader(key, data, outFilepath + ".json"); - } else if(type == "Textures") { - ExtractTextures(key, data, outFilepath + ".json", tags); - } else if(type == "Sprites") { - ExtractSprite(key, data, outFilepath + ".json", assetsJson); - } else if(type == "Fonts") { - ExtractFonts(key, data, outFilepath + ".json", folder, configJSON); - } else if(is_binary_type(type)) { - ExtractBinary(key, data, outFilepath + ".bin"); - } else if(is_compressed_type(type)) { - ExtractCompressed(key, data, outFilepath + ".cbin"); - } else if(type == "Empty") { - } else if(type != "NoExtract") { - display_error_and_abort("Unknown extraction type: ", type); - } - }); - } - } -} - -void ExtractConfig::extract() { - int romOffset = 0; - extract_code_sections(romOffset); - extract_asset_sections(romOffset); - - std::string jsonFilename = outBaseDirectory + "/assets.meta.json"; - write_json(assetsJson, jsonFilename); - - execute_extraction(); - - while(!path_exists(jsonFilename)){ - std::cout << "Not created yet!" << std::endl; - } // Wait for assets.json to be created. - - // All extractions are done at this point. - std::cout << "Finished extracting! Copying from vanilla folder..." << std::endl; - recursively_copy_directory(this->outBaseDirectory, this->outDirectory); - write_vanilla_warning_file(this->outBaseDirectory); -} diff --git a/tools/dkr_assets_tool_classes/extractor/config.h b/tools/dkr_assets_tool_classes/extractor/config.h deleted file mode 100644 index eb29abf5..00000000 --- a/tools/dkr_assets_tool_classes/extractor/config.h +++ /dev/null @@ -1,79 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// C++17 -#include -#include -namespace fs = std::filesystem; - -#include "../common/util.h" -#include "../common/types.h" -#include "../common/revision_number.h" -#include "../libs/json.hpp" -#include "../libs/ThreadPool.h" - -#include "rom.h" - -#include "extract/extract_binary.h" -#include "extract/extract_compressed.h" -#include "extract/extract_gametext.h" -#include "extract/extract_fonts.h" -#include "extract/extract_menutext.h" -#include "extract/extract_levelname.h" -#include "extract/extract_levelheader.h" -#include "extract/extract_sprite.h" -#include "extract/extract_textures.h" -#include "extract/extract_ttghost.h" - -struct ExtractInfo { - std::string key; - std::string type; - std::string folder; - std::string filename; - std::vector data; - std::unordered_map *tags; - - ExtractInfo(std::string key, std::string type, std::string folder, std::string filename, - std::vector data, std::unordered_map *tags = nullptr) - : key(key), type(type), folder(folder), filename(filename), data(data), tags(tags) - {} -}; - -class ExtractConfig { -public: - ExtractConfig(std::string configFilepath, std::string outDirectory); - ~ExtractConfig(); - void find_rom_for_this_config_and_extract(std::vector &roms); - bool is_correct_version(std::string version); -private: - - int get_file_index(json::JSON& files, int searchIndex); - void extract_code_sections(int &romOffset); - void extract_asset_section(json::JSON §ion, std::vector>& sectionsData, int i); - void extract_asset_sections(int &romOffset); - void execute_extraction(); - void extract(); - - json::JSON configJSON; // Loaded from a config file. - json::JSON assetsJson; // Output assets.json - - bool notSupported; - std::string outBaseDirectory; - std::string outDirectory; - std::string name; - std::string md5; - std::string subfolder; - - ROM *rom; - std::vector extractions; -}; diff --git a/tools/dkr_assets_tool_classes/extractor/extract/extract.cpp b/tools/dkr_assets_tool_classes/extractor/extract/extract.cpp deleted file mode 100644 index 20d2ab16..00000000 --- a/tools/dkr_assets_tool_classes/extractor/extract/extract.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "extract.h" - -Extract::Extract(std::string key, std::vector data, std::string outFilepath){ - this->key = key; - this->data = data; - this->outFilepath = outFilepath; - ensure_that_path_exists(outFilepath); -} - -Extract::~Extract(){ -} - -void Extract::print_extracted() { - std::stringstream out; - out << "Extracted " << outFilepath << std::endl; - std::cout << out.str(); -} \ No newline at end of file diff --git a/tools/dkr_assets_tool_classes/extractor/extract/extract.h b/tools/dkr_assets_tool_classes/extractor/extract/extract.h deleted file mode 100644 index cc381207..00000000 --- a/tools/dkr_assets_tool_classes/extractor/extract/extract.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include "../../common/util.h" -#include - -class Extract { -public: - Extract(std::string key, std::vector data, std::string outFilepath); - ~Extract(); -protected: - std::string key; - std::vector data; - std::string outFilepath; - - void print_extracted(); -}; diff --git a/tools/dkr_assets_tool_classes/extractor/extract/extract_binary.cpp b/tools/dkr_assets_tool_classes/extractor/extract/extract_binary.cpp deleted file mode 100644 index 9eb58612..00000000 --- a/tools/dkr_assets_tool_classes/extractor/extract/extract_binary.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "extract_binary.h" - -ExtractBinary::ExtractBinary(std::string key, std::vector data, std::string outFilepath) -: Extract(key, data, outFilepath) { - write_binary_file(data, outFilepath); - print_extracted(); -} - -ExtractBinary::~ExtractBinary(){ -} diff --git a/tools/dkr_assets_tool_classes/extractor/extract/extract_binary.h b/tools/dkr_assets_tool_classes/extractor/extract/extract_binary.h deleted file mode 100644 index 5c780cb0..00000000 --- a/tools/dkr_assets_tool_classes/extractor/extract/extract_binary.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include "extract.h" - -class ExtractBinary : Extract { -public: - ExtractBinary(std::string key, std::vector data, std::string outFilepath); - ~ExtractBinary(); -}; diff --git a/tools/dkr_assets_tool_classes/extractor/extract/extract_compressed.cpp b/tools/dkr_assets_tool_classes/extractor/extract/extract_compressed.cpp deleted file mode 100644 index 09b86c35..00000000 --- a/tools/dkr_assets_tool_classes/extractor/extract/extract_compressed.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "extract_compressed.h" - -ExtractCompressed::ExtractCompressed(std::string key, std::vector data, std::string outFilepath) -: Extract(key, data, outFilepath) { - - if(data.size() == 0) { - std::cout << "Warning: \"" << outFilepath << "\" is empty." << std::endl; - write_binary_file(data, outFilepath); - print_extracted(); - return; - } - - data = decompress_dkr_gzip(data); - write_binary_file(data, outFilepath); - print_extracted(); -} - -ExtractCompressed::~ExtractCompressed(){ -} diff --git a/tools/dkr_assets_tool_classes/extractor/extract/extract_compressed.h b/tools/dkr_assets_tool_classes/extractor/extract/extract_compressed.h deleted file mode 100644 index 27b95961..00000000 --- a/tools/dkr_assets_tool_classes/extractor/extract/extract_compressed.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include "extract.h" - -class ExtractCompressed : Extract { -public: - ExtractCompressed(std::string key, std::vector data, std::string outFilepath); - ~ExtractCompressed(); -}; diff --git a/tools/dkr_assets_tool_classes/extractor/extract/extract_fonts.cpp b/tools/dkr_assets_tool_classes/extractor/extract/extract_fonts.cpp deleted file mode 100644 index 3373faed..00000000 --- a/tools/dkr_assets_tool_classes/extractor/extract/extract_fonts.cpp +++ /dev/null @@ -1,89 +0,0 @@ -#include "extract_fonts.h" - -#define SECTION_TEXTURE_2D_INDEX 4 -#define SECTION_FONTS_INDEX 44 - -#define GAME_FONTS_FOLDERNAME "game_fonts" - -ExtractFonts::ExtractFonts(std::string key, std::vector data, std::string outFilepath, std::string folder, json::JSON &configJSON) -: Extract(key, data, outFilepath) { - json::JSON out = json::Object(); - - //out["fonts-folder"] = GAME_FONTS_FOLDERNAME; - create_directory(folder + "/" + GAME_FONTS_FOLDERNAME); - out["fonts"] = json::Object(); - - int numberOfFonts = get_big_endian_word(data, 0); - for(int i = 0; i < numberOfFonts; i++) { - int offset = (i * 0x400) + 4; // Offset in file for this font. - - std::string fontName = get_ascii(data, offset); - std::string fontId = "ASSET_FONTS_" + fontName; - make_uppercase(fontId); - - json::JSON font = json::Object(); - - font["name"] = fontName; - font["unknown-text"] = get_ascii(data, offset + 0x28); - font["fixed-width"] = get_big_endian_halfword(data, offset + 0x20); - font["y-offset"] = get_big_endian_halfword(data, offset + 0x22); - font["special-character-width"] = get_big_endian_halfword(data, offset + 0x24); - font["tab-width"] = get_big_endian_halfword(data, offset + 0x26); - - font["textures"] = json::Array(); - - int texOffset = offset + 0x40; - int16_t texIndex = get_big_endian_halfword(data, texOffset); - while(texIndex != -1) { - json::JSON textureId = get_build_id_from_section("ASSET_TEXTURES_2D", texIndex); - font["textures"].append(textureId); - texOffset += 2; - texIndex = get_big_endian_halfword(data, texOffset); - } - - font["characters"] = json::Object(); - - for(int j = 32; j < 128; j++) { - int nodeOffset = offset + 0x100 + ((j - 32) * 8); - json::JSON node = json::Object(); - - node["tex-index"] = (int8_t)data[nodeOffset]; - node["char-width"] = data[nodeOffset + 1]; - node["offset"] = json::Array(); - node["offset"].append(data[nodeOffset + 2]); // X offset - node["offset"].append(data[nodeOffset + 3]); // Y offset - node["uv"] = json::Array(); - node["uv"].append(data[nodeOffset + 4]); // U coordinate - node["uv"].append(data[nodeOffset + 5]); // V coordinate - node["tex-size"] = json::Array(); - node["tex-size"].append(data[nodeOffset + 6]); // Width - node["tex-size"].append(data[nodeOffset + 7]); // Height - - if(j == '\"') { - font["characters"]["\\\""] = node; - } else if(j == '\\') { - font["characters"]["\\\\"] = node; - } else if(j == 127) { - font["characters"]["DEL"] = node; - } else { - font["characters"][std::string(1, (char)j)] = node; - } - } - - font["encoding"] = json::Object(); - font["encoding"]["type"] = "ASCII"; - - std::string fontJsonFilename = GAME_FONTS_FOLDERNAME; - fontJsonFilename += "/" + fontName + ".meta.json"; - - out["fonts"][fontId] = fontJsonFilename; - - write_json(font, folder + "/" + fontJsonFilename); - } - out["type"] = "Fonts"; - write_json(out, outFilepath); - print_extracted(); -} - -ExtractFonts::~ExtractFonts(){ -} diff --git a/tools/dkr_assets_tool_classes/extractor/extract/extract_fonts.h b/tools/dkr_assets_tool_classes/extractor/extract/extract_fonts.h deleted file mode 100644 index f05b4e1d..00000000 --- a/tools/dkr_assets_tool_classes/extractor/extract/extract_fonts.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include "extract.h" - -class ExtractFonts : Extract { -public: - ExtractFonts(std::string key, std::vector data, std::string outFilepath, std::string folder, json::JSON &configJSON); - ~ExtractFonts(); -}; diff --git a/tools/dkr_assets_tool_classes/extractor/extract/extract_gametext.cpp b/tools/dkr_assets_tool_classes/extractor/extract/extract_gametext.cpp deleted file mode 100644 index bda3a64a..00000000 --- a/tools/dkr_assets_tool_classes/extractor/extract/extract_gametext.cpp +++ /dev/null @@ -1,164 +0,0 @@ -#include "extract_gametext.h" - -ExtractGameText::ExtractGameText(std::string key, std::vector data, std::string outFilepath, - std::unordered_map *tags) : Extract(key, data, outFilepath) { - json::JSON out = json::Object(); - bool isDialog = false; - - out["type"] = "GameText"; - - if(tags != nullptr) { - out["text-type"] = (*tags)["text-type"]; - isDialog = (out["text-type"].ToString() == "Dialog"); - } - - if(isDialog) { - // Uncomment this when the formats have been fully figured out. - //extract_dialog(out, data); - // Remove this raw part when dialog has been figured out. - out["raw"] = json::Array(); - size_t dataLength = data.size(); - for(int i = 0; i < dataLength; i++) { - out["raw"].append(data[i]); - } - } else { // Textbox - extract_textbox(out, data); - } - - write_json(out, outFilepath); - print_extracted(); -} - -ExtractGameText::~ExtractGameText() { -} - -void ExtractGameText::extract_dialog(json::JSON &out, std::vector &data) { - out["lines"] = json::Array(); - - size_t offset = 0; - size_t dataLength = data.size(); - - while(offset < dataLength) { - if(data[offset++] == 1) { - json::JSON line = json::Object(); - line["color"] = json::Object(); - line["color"]["red"] = data[offset++]; - line["color"]["green"] = data[offset++]; - line["color"]["blue"] = data[offset++]; - line["color"]["alpha"] = data[offset++]; - line["font"] = data[offset++]; - line["alignment"] = data[offset++]; - line["time"] = (data[offset++] * 6.0f) / 30.0f; - uint8_t c = data[offset++]; - std::stringstream rawTextStream; - while(c != 0) { - rawTextStream << (char)c; - c = data[offset++]; - } - line["text"] = rawTextStream.str(); - out["lines"].append(line); - } - if(data[offset++] != 0xC) { - break; - } else { - out["lines"].append("CONTINUE"); - } - } - if(offset < dataLength) { - offset--; - json::JSON junk = json::Object(); - json::JSON junkData = json::Array(); - while(offset < dataLength) { - junkData.append(data[offset++]); - } - junk["unknown-data"] = junkData; - out["lines"].append(junk); - } -} - -void ExtractGameText::extract_textbox(json::JSON &out, std::vector &data) { - size_t offset = 0; - size_t dataLength = data.size(); - - out["pages"] = json::Array(); - int currentPage = 0; - out["pages"].append(json::Array()); // Each page is an array of commands/text. - - bool end = false; - while((offset < dataLength) && !end) { - json::JSON cmd = json::Object(); - switch(data[offset++]){ - case 0: // End of textbox commands. - end = true; - break; - case 1: // Go to next page. - currentPage++; - out["pages"].append(json::Array()); - continue; // Move onto the next command, since there is nothing to add anyway. - case 2: - // Not used? - break; - case 3: - cmd["command"] = "SetFont"; - cmd["value"] = get_string_from_section("ASSET_FONTS", "fonts-order", data[offset++]); - break; - case 4: - cmd["command"] = "SetBorder"; - cmd["value"] = json::Object(); // 0 = Farthest left/top, 0xFF = Farthest right/bottom - cmd["value"]["left"] = data[offset++]; - cmd["value"]["top"] = data[offset++]; - cmd["value"]["right"] = data[offset++]; - cmd["value"]["bottom"] = data[offset++]; - break; - case 5: - cmd["command"] = "SetColour"; - cmd["value"] = json::Object(); - cmd["value"]["red"] = data[offset++]; - cmd["value"]["green"] = data[offset++]; - cmd["value"]["blue"] = data[offset++]; - cmd["value"]["alpha"] = data[offset++]; - break; - case 6: - cmd["command"] = "SetAlignment"; - cmd["value"] = (data[offset++] == 0) ? "center" : "left"; - break; - case 7: - cmd["command"] = "Unknown"; // Doesn't seem to do anything as far as I can tell. - cmd["value"] = data[offset++]; - break; - case 8: - cmd["command"] = "AddVerticalSpacing"; - cmd["value"] = data[offset++]; - break; - case 9: - cmd["command"] = "SetLineHeight"; - cmd["value"] = data[offset++]; - break; - case 10: - cmd["command"] = "SetTimer"; - cmd["value"] = data[offset++]; // time in seconds. - break; - case 11: - cmd["command"] = "AllowUserInput"; - cmd["value"] = data[offset++] ? true : false; - break; - default: // Just regular text. - uint8_t c = data[--offset]; - std::stringstream rawTextStream; - while(c != 0) { - rawTextStream << (char)c; - c = data[++offset]; - } - offset++; - cmd["command"] = "Text"; - cmd["value"] = rawTextStream.str(); - break; - } - if(!end) { - out["pages"][currentPage].append(cmd); - } - } -} - - - diff --git a/tools/dkr_assets_tool_classes/extractor/extract/extract_gametext.h b/tools/dkr_assets_tool_classes/extractor/extract/extract_gametext.h deleted file mode 100644 index 74bc1db5..00000000 --- a/tools/dkr_assets_tool_classes/extractor/extract/extract_gametext.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include "extract.h" - -class ExtractGameText : Extract { -public: - ExtractGameText(std::string key, std::vector data, std::string outFilepath, - std::unordered_map *tags); - ~ExtractGameText(); -private: - void extract_dialog(json::JSON &out, std::vector &data); - void extract_textbox(json::JSON &out, std::vector &data); -}; diff --git a/tools/dkr_assets_tool_classes/extractor/extract/extract_levelheader.cpp b/tools/dkr_assets_tool_classes/extractor/extract/extract_levelheader.cpp deleted file mode 100644 index 53271eba..00000000 --- a/tools/dkr_assets_tool_classes/extractor/extract/extract_levelheader.cpp +++ /dev/null @@ -1,132 +0,0 @@ -#include "extract_levelheader.h" - -// Extracts a bitfield as an array of enum value strings. -json::JSON extract_enum_values(std::vector &data, int offset, int numBytes, std::string enumName) { - json::JSON values = json::Array(); - int bitflags = 0; - for(int i = 0; i < numBytes; i++) { - bitflags |= data[offset + i] << (8 * i); - } - for(int i = 0; bitflags != 0; i++) { - if(bitflags & 1) { - values.append(get_enum_string_from_value(enumName, i)); - } - bitflags >>= 1; - } - return values; -} - -ExtractLevelHeader::ExtractLevelHeader(std::string key, std::vector data, std::string outFilepath) -: Extract(key, data, outFilepath) { - json::JSON out = json::Object(); - - out["type"] = "LevelHeaders"; - out["unknown-data"] = json::Object(); - - // World ID - out["world"] = get_enum_string_from_value("World", (int8_t)data[0]); - - out["unknown-data"]["unk1"] = data[1]; - out["unknown-data"]["unk2"] = data[2]; - out["unknown-data"]["unk3"] = data[3]; - out["unknown-data"]["unk4"] = json::Array(); - for(int i = 4; i < 8; i++) { - out["unknown-data"]["unk4"].append(data[i]); - } - - // Ceiling height for planes - out["ceiling-height"] = get_big_endian_float(data, 8); - - out["unknown-data"]["unkC"] = json::Array(); - for(int i = 0xC; i < 0x34; i++) { - out["unknown-data"]["unkC"].append(data[i]); - } - - // Track Model ID to use - int modelId = get_big_endian_halfword(data, 0x34); - out["model"] = get_build_id_from_section("ASSET_LEVEL_MODELS", modelId); - - // Collectables bitflags (bananas, balloons, etc) - out["collectables"] = get_big_endian_halfword(data, 0x36); - - // Skydome object model ID - out["skybox"] = get_big_endian_halfword(data, 0x38); - - // Fog - out["fog"] = json::Object(); - out["fog"]["range"] = json::Object(); - out["fog"]["range"]["min"] = get_big_endian_halfword(data, 0x3A); - out["fog"]["range"]["max"] = get_big_endian_halfword(data, 0x3C); - out["fog"]["colour"] = json::Object(); - out["fog"]["colour"]["red"] = get_big_endian_halfword(data, 0x3E); - out["fog"]["colour"]["green"] = get_big_endian_halfword(data, 0x40); - out["fog"]["colour"]["blue"] = get_big_endian_halfword(data, 0x42); - - for(int i = 0x44; i < 0x4B; i++) { - out["unknown-data"]["unk44"].append(data[i]); - } - - // Number of laps to complete the race - out["number-laps"] = data[0x4B]; - - // Type of race (standard, boss race, hub world, etc. - out["race-type"] = get_enum_string_from_value("RaceType", data[0x4C]); - - // Default vehicle used for this track. (Either Car, Hovercraft, or Plane) - out["default-vehicle"] = get_enum_string_from_value("Vehicle", data[0x4D]); - - // Which vehicles can be used in this track (Either Car, Hovercraft, or Plane) - out["available-vehicles"] = extract_enum_values(data, 0x4E, 1, "Vehicle"); - - out["unknown-data"]["unk4F"] = json::Array(); - for(int i = 0x4F; i < 0x52; i++) { - out["unknown-data"]["unk4F"].append(data[i]); - } - out["music"] = data[0x52]; - out["unknown-data"]["unk53"] = data[0x53]; - out["instruments"] = get_big_endian_halfword(data, 0x54); - out["unknown-data"]["unk56"] = json::Array(); - for(int i = 0x56; i < 0x74; i++) { - out["unknown-data"]["unk56"].append(data[i]); - } - out["unknown-data"]["unk74"] = json::Array(); - for(int i = 0; i < 7; i++) { - int ptr = get_big_endian_word(data, 0x74 + (i*4)); - out["unknown-data"]["unk74"].append(ptr); - } - out["unknown-data"]["weather"] = json::Object(); - out["unknown-data"]["weather"]["particle-density"] = (int)get_big_endian_halfword(data, 0x90); - out["unknown-data"]["weather"]["type"] = (int)get_big_endian_halfword(data, 0x92); - out["unknown-data"]["weather"]["intensity"] = data[0x94]; - out["unknown-data"]["weather"]["opacity"] = data[0x95]; - out["unknown-data"]["weather"]["x-velocity"] = (int)get_big_endian_halfword(data, 0x96); - out["unknown-data"]["weather"]["y-velocity"] = (int)get_big_endian_halfword(data, 0x98); - out["unknown-data"]["weather"]["z-velocity"] = (int)get_big_endian_halfword(data, 0x9A); - out["fov"] = data[0x9C]; - out["background-colour"] = json::Object(); - out["background-colour"]["red"] = data[0x9D]; - out["background-colour"]["green"] = data[0x9E]; - out["background-colour"]["blue"] = data[0x9F]; - out["unknown-data"]["unkA0"] = json::Array(); - for(int i = 0xA0; i < 0xA4; i++) { - out["unknown-data"]["unkA0"].append(data[i]); - } - out["unknown-data"]["unkA4"] = (int)get_big_endian_word(data, 0xA4); - out["unknown-data"]["unkA8"] = (int)get_big_endian_halfword(data, 0xA8); - out["unknown-data"]["unkAA"] = (int)get_big_endian_halfword(data, 0xAA); - int pulsatingLightsOffset = (int)get_big_endian_word(data, 0xAC); - if(pulsatingLightsOffset != -1) { - out["pulsating-lights"] = get_build_id_from_section("ASSET_MISC", pulsatingLightsOffset); - } - out["unknown-data"]["unkB0"] = json::Array(); - for(int i = 0xB0; i < 0xC4; i++) { - out["unknown-data"]["unkB0"].append(data[i]); - } - out["unknown-data"]["unkC4"] = (int)get_big_endian_word(data, 0xC4); - - write_json(out, outFilepath); - print_extracted(); -} - -ExtractLevelHeader::~ExtractLevelHeader(){ -} diff --git a/tools/dkr_assets_tool_classes/extractor/extract/extract_levelheader.h b/tools/dkr_assets_tool_classes/extractor/extract/extract_levelheader.h deleted file mode 100644 index 0d35909e..00000000 --- a/tools/dkr_assets_tool_classes/extractor/extract/extract_levelheader.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include "extract.h" - -class ExtractLevelHeader : Extract { -public: - ExtractLevelHeader(std::string key, std::vector data, std::string outFilepath); - ~ExtractLevelHeader(); -}; diff --git a/tools/dkr_assets_tool_classes/extractor/extract/extract_levelname.cpp b/tools/dkr_assets_tool_classes/extractor/extract/extract_levelname.cpp deleted file mode 100644 index c80fd36c..00000000 --- a/tools/dkr_assets_tool_classes/extractor/extract/extract_levelname.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include "extract_levelname.h" - -ExtractLevelName::ExtractLevelName(std::string key, std::vector data, std::string outFilepath) -: Extract(key, data, outFilepath) { - json::JSON out = json::Object(); - - out["type"] = "LevelNames"; - out["languages"] = json::Object(); - - // Assumption: All of the values in the "Language" enum are continuous and start at 0. - std::vector languages = get_enum_keys("Language"); - - int numLanguages = languages.size(); - std::vector names = get_multiple_ascii(data, 0, numLanguages); - - for(int i = 0; i < numLanguages; i++) { - out["languages"][languages[i]] = names[i]; - } - - write_json(out, outFilepath); - print_extracted(); -} - -ExtractLevelName::~ExtractLevelName(){ -} diff --git a/tools/dkr_assets_tool_classes/extractor/extract/extract_levelname.h b/tools/dkr_assets_tool_classes/extractor/extract/extract_levelname.h deleted file mode 100644 index 5e922a54..00000000 --- a/tools/dkr_assets_tool_classes/extractor/extract/extract_levelname.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include "extract.h" - -class ExtractLevelName : Extract { -public: - ExtractLevelName(std::string key, std::vector data, std::string outFilepath); - ~ExtractLevelName(); -}; diff --git a/tools/dkr_assets_tool_classes/extractor/extract/extract_menutext.cpp b/tools/dkr_assets_tool_classes/extractor/extract/extract_menutext.cpp deleted file mode 100644 index 7332a97c..00000000 --- a/tools/dkr_assets_tool_classes/extractor/extract/extract_menutext.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "extract_menutext.h" - -ExtractMenuText::ExtractMenuText(std::string key, std::vector data, std::string outFilepath, - std::unordered_map *tags) : Extract(key, data, outFilepath) { - json::JSON out = json::Object(); - - out["type"] = "MenuText"; - - std::cout << key << std::endl; - - uint32_t tableSize = stoi((*tags)["text-entry-count"]); - - //out["order"] = json::Array(); - out["sections"] = json::Object(); - - for(size_t i = 0; i < tableSize; i++) { - uint32_t offset = get_big_endian_word(data, i*4); - - if(offset == 0xFFFFFFFF) { - //out["order"].append(nullptr); - } else { - std::string entry_key = (*tags)["text-entry-build-id_" + std::to_string(i)]; - if(out["sections"].hasKey(entry_key)) { - std::stringstream err; - err << "The key \"" << entry_key << "\" is already defined! Aborting!" << std::endl; - std::cout << err.str(); - throw 1; - } - //out["order"].append(entry_key); - out["sections"][entry_key] = get_ascii(data, offset); - } - - } - - write_json(out, outFilepath); - print_extracted(); -} - -ExtractMenuText::~ExtractMenuText(){ -} diff --git a/tools/dkr_assets_tool_classes/extractor/extract/extract_menutext.h b/tools/dkr_assets_tool_classes/extractor/extract/extract_menutext.h deleted file mode 100644 index 635f452a..00000000 --- a/tools/dkr_assets_tool_classes/extractor/extract/extract_menutext.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include "extract.h" - -class ExtractMenuText : Extract { -public: - ExtractMenuText(std::string key, std::vector data, std::string outFilepath, - std::unordered_map *tags); - ~ExtractMenuText(); -}; diff --git a/tools/dkr_assets_tool_classes/extractor/extract/extract_sprite.cpp b/tools/dkr_assets_tool_classes/extractor/extract/extract_sprite.cpp deleted file mode 100644 index faf0aefe..00000000 --- a/tools/dkr_assets_tool_classes/extractor/extract/extract_sprite.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "extract_sprite.h" - -ExtractSprite::ExtractSprite(std::string key, std::vector data, std::string outFilepath, -json::JSON &configJSON) -: Extract(key, data, outFilepath) { - json::JSON out = json::Object(); - - out["type"] = "Sprites"; - out["start-texture"] = get_build_id_from_section("ASSET_TEXTURES_2D", get_big_endian_halfword(data, 0)); - //out["number-of-frames"] = get_big_endian_halfword(data, 2); - out["unk4"] = get_big_endian_halfword(data, 4); - out["unk6"] = get_big_endian_halfword(data, 6); - out["frame-tex-count"] = json::Array(); - - int count = get_big_endian_halfword(data, 2); - int curOffset = 0x0D; - - for(int i = 0; i < count; i++) { - out["frame-tex-count"].append(data[curOffset] - data[curOffset - 1]); - curOffset++; - } - - write_json(out, outFilepath); - print_extracted(); -} - -ExtractSprite::~ExtractSprite(){ -} diff --git a/tools/dkr_assets_tool_classes/extractor/extract/extract_sprite.h b/tools/dkr_assets_tool_classes/extractor/extract/extract_sprite.h deleted file mode 100644 index f65400fd..00000000 --- a/tools/dkr_assets_tool_classes/extractor/extract/extract_sprite.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include "extract.h" - -class ExtractSprite : Extract { -public: - ExtractSprite(std::string key, std::vector data, std::string outFilepath, json::JSON &configJSON); - ~ExtractSprite(); -}; diff --git a/tools/dkr_assets_tool_classes/extractor/extract/extract_textures.cpp b/tools/dkr_assets_tool_classes/extractor/extract/extract_textures.cpp deleted file mode 100644 index 235bf523..00000000 --- a/tools/dkr_assets_tool_classes/extractor/extract/extract_textures.cpp +++ /dev/null @@ -1,204 +0,0 @@ -#include "extract_textures.h" - -ExtractTextures::ExtractTextures(std::string key, std::vector data, std::string outFilepath, - std::unordered_map *tags) -: Extract(key, data, outFilepath) { - std::string directory = get_directory_from_full_path(outFilepath); - std::string filename = get_filename_from_full_path(outFilepath, true); - ensure_that_path_exists(directory); - - json::JSON out = json::Object(); - int format = data[2] & 0xF; - int numberOfTextures = data[0x12]; - - out["type"] = "Textures"; - out["width"] = data[0]; - out["height"] = data[1]; - out["format"] = get_texture_format_string(format); - out["tex-type"] = (data[2] >> 4) & 0xF; - - if(tags != nullptr) { - out["flipped-image"] = (*tags)["flip-texture_" + key] == "true"; - } - - if(data[3] != 0 || data[4] != 0) { - out["sprite-x"] = data[3]; - out["sprite-y"] = data[4]; - } - - int flags = get_big_endian_halfword(data, 6); - - out["flags"] = json::Object(); - - // TODO: Figure out all the flags - out["flags"]["flag-01"] = flags & 0x0001 ? true : false; - out["flags"]["flag-04"] = flags & 0x0004 ? true : false; - out["flags"]["flag-10"] = flags & 0x0010 ? true : false; - out["flags"]["wrap-s"] = flags & 0x0040 ? "Clamp" : "Wrap"; - out["flags"]["wrap-t"] = flags & 0x0080 ? "Clamp" : "Wrap"; - out["flags"]["interlaced"] = flags & 0x0400 ? true : false; - - if(format == TEX_FORMAT_CI4 || format == TEX_FORMAT_CI8) { - // TODO: Replace integer offset with label. - out["palette-offset"] = get_big_endian_halfword(data, 8); - } - - out["frame-count"] = numberOfTextures; - - if(numberOfTextures > 1) { - out["frame-advance-delay"] = get_big_endian_halfword(data, 0x14); - } - - out["compressed"] = data[0x1D] != 0; - - out["img"] = filename + ".png"; - - out["write-size"] = (get_big_endian_halfword(data, 0x16) != 0); - - write_images(directory + "/" + out["img"].ToString(), data, out); - - write_json(out, outFilepath); - print_extracted(); -} - -ExtractTextures::~ExtractTextures(){ -} - -void deinterlace_texture(std::vector& texData, int width, int height, int format) { - switch(format) { - case TEX_FORMAT_RGBA32: - { - deinterlace(texData, 0, width, height, 32, 8); - return; - } - case TEX_FORMAT_RGBA16: - case TEX_FORMAT_IA16: - { - deinterlace(texData, 0, width, height, 16, 4); - return; - } - case TEX_FORMAT_I8: - case TEX_FORMAT_IA8: - { - deinterlace(texData, 0, width, height, 8, 4); - return; - } - case TEX_FORMAT_I4: - case TEX_FORMAT_IA4: - { - deinterlace(texData, 0, width, height, 4, 4); - return; - } - } -} - -void ExtractTextures::write_images(std::string outImagePath, std::vector &data, json::JSON &out) { - std::vector texData; - - if(out["compressed"].ToBool()) { - std::vector compressedData(data.begin() + TEX_HEADER_SIZE, data.end()); - texData = decompress_dkr_gzip(compressedData); - } else { - texData = data; - } - - int numberOfTextures = out["frame-count"].ToInt(); - int width = out["width"].ToInt(); - int height = out["height"].ToInt(); - int format = get_texture_format_from_string(out["format"].ToString()); - bool isInterlaced = out["flags"]["interlaced"].ToBool(); - bool shouldFlip = out["flipped-image"].ToBool(); - - std::vector combinedTexturesData; - int dataOffset = 0; - - if(numberOfTextures > 1) { - for(int i = 0; i < numberOfTextures; i++){ - int textureSize = get_texture_size(width, height, format); - - std::vector texDataPart(texData.begin() + dataOffset + TEX_HEADER_SIZE, texData.begin() + dataOffset + textureSize); - - // Deinterlacing must come before flipping the texture. - if(isInterlaced) { - deinterlace_texture(texDataPart, width, height, format); - } - if(shouldFlip) { - flip_texture_vertically(texDataPart, 0, width, height, format); - } - - combinedTexturesData.insert(combinedTexturesData.end(), texDataPart.begin(), texDataPart.end()); - - dataOffset += textureSize; - } - } else { - combinedTexturesData = std::vector(texData.begin() + TEX_HEADER_SIZE, texData.end()); - - // Deinterlacing must come before flipping the texture. - if(isInterlaced) { - deinterlace_texture(combinedTexturesData, width, height, format); - } - if(shouldFlip) { - flip_texture_vertically(combinedTexturesData, 0, width, height, format); - } - } - - int totalHeight = height * numberOfTextures; - - switch(format) { - case TEX_FORMAT_RGBA32: - { - rgba2png(outImagePath.c_str(), (const rgba*)&combinedTexturesData[0], width, totalHeight); - break; - } - case TEX_FORMAT_RGBA16: - { - rgba *outTex = raw2rgba(&combinedTexturesData[0], width, totalHeight, 16); - rgba2png(outImagePath.c_str(), outTex, width, totalHeight); - break; - } - case TEX_FORMAT_I8: - { - ia *outTex = raw2i(&combinedTexturesData[0], width, totalHeight, 8); - ia2png(outImagePath.c_str(), outTex, width, totalHeight); - break; - } - case TEX_FORMAT_I4: - { - ia *outTex = raw2i(&combinedTexturesData[0], width, totalHeight, 4); - ia2png(outImagePath.c_str(), outTex, width, totalHeight); - break; - } - case TEX_FORMAT_IA16: - { - ia *outTex = raw2ia(&combinedTexturesData[0], width, totalHeight, 16); - ia2png(outImagePath.c_str(), outTex, width, totalHeight); - break; - } - case TEX_FORMAT_IA8: - { - ia *outTex = raw2ia(&combinedTexturesData[0], width, totalHeight, 8); - ia2png(outImagePath.c_str(), outTex, width, totalHeight); - break; - } - case TEX_FORMAT_IA4: - { - ia *outTex = raw2ia(&combinedTexturesData[0], width, totalHeight, 4); - ia2png(outImagePath.c_str(), outTex, width, totalHeight); - break; - } - case TEX_FORMAT_CI4: - case TEX_FORMAT_CI8: - { - display_error_and_abort("CI texture formats are not currently supported."); - } - default: // Invalid texture format - { - display_error_and_abort("Unknown texture format ", format); - } - } -} - - - - - diff --git a/tools/dkr_assets_tool_classes/extractor/extract/extract_textures.h b/tools/dkr_assets_tool_classes/extractor/extract/extract_textures.h deleted file mode 100644 index 1655f94f..00000000 --- a/tools/dkr_assets_tool_classes/extractor/extract/extract_textures.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include "extract.h" -#include "../../common/textures.h" - -class ExtractTextures : Extract { -public: - ExtractTextures(std::string key, std::vector data, std::string outFilepath, - std::unordered_map *tags); - ~ExtractTextures(); -private: - void write_images(std::string outImagePath, std::vector &data, json::JSON &out); -}; diff --git a/tools/dkr_assets_tool_classes/extractor/extract/extract_ttghost.cpp b/tools/dkr_assets_tool_classes/extractor/extract/extract_ttghost.cpp deleted file mode 100644 index 597033e2..00000000 --- a/tools/dkr_assets_tool_classes/extractor/extract/extract_ttghost.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include "extract_ttghost.h" - -ExtractTTGhost::ExtractTTGhost(std::string key, std::vector data, std::string outFilepath, -json::JSON &configJSON) -: Extract(key, data, outFilepath) { - json::JSON out = json::Object(); - - out["type"] = "TTGhosts"; - out["header"] = json::Object(); - out["nodes"] = json::Array(); - - out["header"]["level"] = get_build_id_from_section("ASSET_LEVEL_HEADERS", data[0]); // data[0]; - - out["header"]["vehicle"] = get_enum_string_from_value("Vehicle", data[1]); - - //out["header"]["unk02"] = data[2]; // Always 0x09? - out["header"]["time"] = get_big_endian_halfword(data, 4); - - int nodeCount = get_big_endian_halfword(data, 6); - - for(int i = 0; i < nodeCount; i++) { - json::JSON node = json::Object(); - - int offset = (i * 12) + 8; - - node["x"] = (int16_t)get_big_endian_halfword(data, offset); - node["y"] = (int16_t)get_big_endian_halfword(data, offset + 2); - node["z"] = (int16_t)get_big_endian_halfword(data, offset + 4); - // Yes, this order is correct. - node["rz"] = (int16_t)get_big_endian_halfword(data, offset + 6); - node["rx"] = (int16_t)get_big_endian_halfword(data, offset + 8); - node["ry"] = (int16_t)get_big_endian_halfword(data, offset + 10); - - out["nodes"].append(node); - } - - write_json(out, outFilepath); - print_extracted(); -} - -ExtractTTGhost::~ExtractTTGhost(){ -} diff --git a/tools/dkr_assets_tool_classes/extractor/extract/extract_ttghost.h b/tools/dkr_assets_tool_classes/extractor/extract/extract_ttghost.h deleted file mode 100644 index a5bbef0d..00000000 --- a/tools/dkr_assets_tool_classes/extractor/extract/extract_ttghost.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include "extract.h" - -class ExtractTTGhost : Extract { -public: - ExtractTTGhost(std::string key, std::vector data, std::string outFilepath, json::JSON &configJSON); - ~ExtractTTGhost(); -}; diff --git a/tools/dkr_assets_tool_classes/extractor/extractor.cpp b/tools/dkr_assets_tool_classes/extractor/extractor.cpp deleted file mode 100644 index 22ae9778..00000000 --- a/tools/dkr_assets_tool_classes/extractor/extractor.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "extractor.h" - -Extractor::Extractor(std::string version, std::string configsDirectory, std::string baseromsDirectory, std::string outDirectory) { - std::vector baseroms = get_filenames_from_directory(baseromsDirectory); - std::vector validROMs; - for(std::string& baseromPath : baseroms) { - ROM *checkRom = new ROM(baseromPath); - if(checkRom->is_valid()) { - validROMs.push_back(checkRom); - } else { - delete checkRom; - } - } - - if(validROMs.size() == 0) { - std::cout << "No valid ROMs were found in the baseroms directory" << std::endl; - return; - } - - std::vector configPaths = get_filenames_from_directory_with_extension(configsDirectory, ".config.json"); - for(std::string& configPath : configPaths) { - ExtractConfig config(configPath, outDirectory); - if(config.is_correct_version(version)) { - config.find_rom_for_this_config_and_extract(validROMs); - } - } - - // Cleanup - for(size_t i; i < validROMs.size(); i++) { - delete validROMs[i]; - } -} - -Extractor::~Extractor() { - -} diff --git a/tools/dkr_assets_tool_classes/extractor/extractor.h b/tools/dkr_assets_tool_classes/extractor/extractor.h deleted file mode 100644 index e878b6b0..00000000 --- a/tools/dkr_assets_tool_classes/extractor/extractor.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -#include "config.h" -#include "rom.h" -#include "../common/util.h" - -class Extractor { -public: - Extractor(std::string version, std::string configsDirectory, std::string baseromsDirectory, std::string outDirectory); - ~Extractor(); -private: - std::vector configs; -}; diff --git a/tools/dkr_assets_tool_classes/extractor/rom.cpp b/tools/dkr_assets_tool_classes/extractor/rom.cpp deleted file mode 100644 index 2098bd4d..00000000 --- a/tools/dkr_assets_tool_classes/extractor/rom.cpp +++ /dev/null @@ -1,119 +0,0 @@ -#include "rom.h" - -ROM::ROM(std::string filename){ - if(!readROMFile(filename)) { - display_error_and_abort("Failed to load ROM \"", filename, "\""); - } - romFilename = filename; - - test_endianness(); - md5 = calculate_md5(bytes); -} - -ROM::~ROM(){ -} - -std::vector ROM::get_bytes_from_range(int start, int numBytes){ - std::vector subVector(numBytes); - std::copy(bytes.begin() + start, bytes.begin() + start + numBytes, subVector.begin()); - return subVector; -} - -uint8_t ROM::get_byte(int romOffset){ - return bytes[romOffset]; -} - -uint32_t ROM::get_uint(int romOffset){ - return (bytes[romOffset] << 24) | (bytes[romOffset + 1] << 16) | (bytes[romOffset + 2] << 8) | bytes[romOffset + 3]; -} - -std::string ROM::get_md5(){ - return md5; -} - -int ROM::get_size(){ - return bytes.size(); -} - -bool ROM::is_valid() { - return isValid; -} - -void ROM::test_endianness(){ - bool convertedToBigEndian = false; - isValid = true; - if(bytes[0] == 0x80 && bytes[1] == 0x37) { // Big endian - // Do nothing - } else if(bytes[0] == 0x37 && bytes[1] == 0x80) { // Mixed endian (byteswapped) - // Mixed endian, convert to big endian - int numBytes = get_size(); - for(int i = 0; i < numBytes; i+=2) { - uint8_t temp = bytes[i]; - bytes[i] = bytes[i + 1]; - bytes[i + 1] = temp; - } - convertedToBigEndian = true; - } else if(bytes[0] == 0x40 && bytes[1] == 0x12) { // Little endian - // Little endian, convert to big endian - int numBytes = get_size(); - uint8_t temp[4]; - for(int i = 0; i < numBytes; i+=4) { - temp[0] = bytes[i + 0]; - temp[1] = bytes[i + 1]; - temp[2] = bytes[i + 2]; - temp[3] = bytes[i + 3]; - bytes[i + 0] = temp[3]; - bytes[i + 1] = temp[2]; - bytes[i + 2] = temp[1]; - bytes[i + 3] = temp[0]; - } - convertedToBigEndian = true; - } else { - isValid = false; - return; - } - - if(convertedToBigEndian) { // Overwrite ROM file - fs::remove(fs::path(romFilename)); // Delete old romfile - std::string z64Filename = romFilename.substr(0, romFilename.length() - 4) + ".z64"; - if(!writeROMFile(z64Filename)) { // Save new big-endian rom. - // ROM failed to save. - isValid = false; - return; - } - } -} - -bool ROM::readROMFile(std::string filename) { - try - { - std::ifstream is; - is.open(filename.c_str(), std::ios::binary); - is.seekg(0, std::ios::end); - size_t filesize = is.tellg(); - is.seekg(0, std::ios::beg); - bytes.resize(filesize); - is.read((char *)bytes.data(), filesize); - is.close(); - } - catch (int e) - { - return false; - } - return true; -} - -bool ROM::writeROMFile(std::string filename) { - try - { - std::ofstream wf(filename.c_str(), std::ios::out | std::ios::binary); - for(int i = 0; i < bytes.size(); i++) - wf.write((char *)&bytes[i], 1); - wf.close(); - } - catch (int e) - { - return false; - } - return true; -} diff --git a/tools/dkr_assets_tool_classes/extractor/rom.h b/tools/dkr_assets_tool_classes/extractor/rom.h deleted file mode 100644 index f0af9309..00000000 --- a/tools/dkr_assets_tool_classes/extractor/rom.h +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#include "../common/util.h" -#include - -class ROM { -public: - ROM(std::string filename); - ~ROM(); - - std::vector get_bytes_from_range(int start, int numBytes); - uint8_t get_byte(int romOffset); - uint32_t get_uint(int romOffset); - - int get_size(); - - - std::string get_md5(); - - bool is_valid(); - -private: - void test_endianness(); - bool readROMFile(std::string filename); - bool writeROMFile(std::string filename); - - std::vector bytes; - std::string md5; - std::string romFilename; - - bool isValid = false; -}; diff --git a/tools/dkr_assets_tool_classes/libs/json.hpp b/tools/dkr_assets_tool_classes/libs/json.hpp deleted file mode 100644 index c5cd9a71..00000000 --- a/tools/dkr_assets_tool_classes/libs/json.hpp +++ /dev/null @@ -1,773 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace json { - -using std::map; -using std::deque; -using std::string; -using std::enable_if; -using std::initializer_list; -using std::is_same; -using std::is_convertible; -using std::is_integral; -using std::is_floating_point; - -namespace { - string json_escape( const string &str ) { - string output; - for( unsigned i = 0; i < str.length(); ++i ) - switch( str[i] ) { - case '\"': output += "\\\""; break; - case '\\': output += "\\\\"; break; - case '\b': output += "\\b"; break; - case '\f': output += "\\f"; break; - case '\n': output += "\\n"; break; - case '\r': output += "\\r"; break; - case '\t': output += "\\t"; break; - default : output += str[i]; break; - } - return std::move( output ); - } - - enum JsonSaveType { - SaveNull, // 0 - SaveInt, // 1 - SaveFloat, // 2 - SaveTrue, // 3 - SaveFalse, // 4 - SaveArray, // 5 - SaveArrayEnd, // 6 - SaveObject, // 7 - SaveObjectEnd, // 8 - SaveString, // 9 - }; -} - -class JSON -{ - union BackingData { - BackingData( double d ) : Float( d ){} - BackingData( long l ) : Int( l ){} - BackingData( bool b ) : Bool( b ){} - BackingData( string s ) : String( new string( s ) ){} - BackingData() : Int( 0 ){} - - deque *List; - map *Map; - string *String; - double Float; - long Int; - bool Bool; - } Internal; - - public: - enum class Class { - Null, - Object, - Array, - String, - Floating, - Integral, - Boolean - }; - - template - class JSONWrapper { - Container *object; - - public: - JSONWrapper( Container *val ) : object( val ) {} - JSONWrapper( std::nullptr_t ) : object( nullptr ) {} - - typename Container::iterator begin() { return object ? object->begin() : typename Container::iterator(); } - typename Container::iterator end() { return object ? object->end() : typename Container::iterator(); } - typename Container::const_iterator begin() const { return object ? object->begin() : typename Container::iterator(); } - typename Container::const_iterator end() const { return object ? object->end() : typename Container::iterator(); } - }; - - template - class JSONConstWrapper { - const Container *object; - - public: - JSONConstWrapper( const Container *val ) : object( val ) {} - JSONConstWrapper( std::nullptr_t ) : object( nullptr ) {} - - typename Container::const_iterator begin() const { return object ? object->begin() : typename Container::const_iterator(); } - typename Container::const_iterator end() const { return object ? object->end() : typename Container::const_iterator(); } - }; - - JSON() : Internal(), Type( Class::Null ){} - - JSON( initializer_list list ) - : JSON() - { - SetType( Class::Object ); - for( auto i = list.begin(), e = list.end(); i != e; ++i, ++i ) - operator[]( i->ToString() ) = *std::next( i ); - } - - JSON( JSON&& other ) - : Internal( other.Internal ) - , Type( other.Type ) - { other.Type = Class::Null; other.Internal.Map = nullptr; } - - JSON& operator=( JSON&& other ) { - ClearInternal(); - Internal = other.Internal; - Type = other.Type; - other.Internal.Map = nullptr; - other.Type = Class::Null; - return *this; - } - - JSON( const JSON &other ) { - switch( other.Type ) { - case Class::Object: - Internal.Map = - new map( other.Internal.Map->begin(), - other.Internal.Map->end() ); - break; - case Class::Array: - Internal.List = - new deque( other.Internal.List->begin(), - other.Internal.List->end() ); - break; - case Class::String: - Internal.String = - new string( *other.Internal.String ); - break; - default: - Internal = other.Internal; - } - Type = other.Type; - } - - JSON& operator=( const JSON &other ) { - ClearInternal(); - switch( other.Type ) { - case Class::Object: - Internal.Map = - new map( other.Internal.Map->begin(), - other.Internal.Map->end() ); - break; - case Class::Array: - Internal.List = - new deque( other.Internal.List->begin(), - other.Internal.List->end() ); - break; - case Class::String: - Internal.String = - new string( *other.Internal.String ); - break; - default: - Internal = other.Internal; - } - Type = other.Type; - return *this; - } - - ~JSON() { - switch( Type ) { - case Class::Array: - if(Internal.List != nullptr) { - delete Internal.List; - } - break; - case Class::Object: - if(Internal.Map != nullptr) { - delete Internal.Map; - } - break; - case Class::String: - if(Internal.String != nullptr) { - delete Internal.String; - } - break; - default:; - } - } - - template - JSON( T b, typename enable_if::value>::type* = 0 ) : Internal( b ), Type( Class::Boolean ){} - - template - JSON( T i, typename enable_if::value && !is_same::value>::type* = 0 ) : Internal( (long)i ), Type( Class::Integral ){} - - template - JSON( T f, typename enable_if::value>::type* = 0 ) : Internal( (double)f ), Type( Class::Floating ){} - - template - JSON( T s, typename enable_if::value>::type* = 0 ) : Internal( string( s ) ), Type( Class::String ){} - - JSON( std::nullptr_t ) : Internal(), Type( Class::Null ){} - - static JSON Make( Class type ) { - JSON ret; ret.SetType( type ); - return ret; - } - - static JSON Load( const string & ); - - static JSON LoadFromCached(std::vector &cached, int &p); - - template - void append( T arg ) { - SetType( Class::Array ); Internal.List->emplace_back( arg ); - } - - template - void append( T arg, U... args ) { - append( arg ); append( args... ); - } - - template - typename enable_if::value, JSON&>::type operator=( T b ) { - SetType( Class::Boolean ); Internal.Bool = b; return *this; - } - - template - typename enable_if::value && !is_same::value, JSON&>::type operator=( T i ) { - SetType( Class::Integral ); Internal.Int = i; return *this; - } - - template - typename enable_if::value, JSON&>::type operator=( T f ) { - SetType( Class::Floating ); Internal.Float = f; return *this; - } - - template - typename enable_if::value, JSON&>::type operator=( T s ) { - SetType( Class::String ); *Internal.String = string( s ); return *this; - } - - JSON& operator[]( const string &key ) { - SetType( Class::Object ); return Internal.Map->operator[]( key ); - } - - JSON& operator[]( unsigned index ) { - SetType( Class::Array ); - if( index >= Internal.List->size() ) Internal.List->resize( index + 1 ); - return Internal.List->operator[]( index ); - } - - JSON &at( const string &key ) { - return operator[]( key ); - } - - const JSON &at( const string &key ) const { - return Internal.Map->at( key ); - } - - JSON &at( unsigned index ) { - return operator[]( index ); - } - - const JSON &at( unsigned index ) const { - return Internal.List->at( index ); - } - - int length() const { - if( Type == Class::Array ) - return Internal.List->size(); - else - return -1; - } - - bool hasKey( const string &key ) const { - if( Type == Class::Object ) - return Internal.Map->find( key ) != Internal.Map->end(); - return false; - } - - void erase( const string &key ) const { - Internal.Map->erase(key); - } - - int size() const { - if( Type == Class::Object ) - return Internal.Map->size(); - else if( Type == Class::Array ) - return Internal.List->size(); - else - return -1; - } - - void save_string(std::vector &out, std::string value) const { - for(int i = 0; i < value.length(); i++) out.push_back((uint8_t)value.at(i)); - out.push_back(0); // Null terminator for strings. - } - - void save(std::vector &out) const { - switch( Type ) { - case Class::Null: - out.push_back(SaveNull); - break; - case Class::Integral: - out.push_back(SaveInt); - for(int i = 0; i < 8; i++) out.push_back((Internal.Int >> ((7 - i) * 8)) & 0xFF); - break; - case Class::Floating: - out.push_back(SaveFloat); - for(int i = 0; i < 8; i++) out.push_back((*((long*)&Internal.Float) >> ((7 - i) * 8)) & 0xFF); - break; - case Class::Boolean: - out.push_back(Internal.Bool ? SaveTrue : SaveFalse); - break; - case Class::Array: - out.push_back(SaveArray); - for(int i = 0; i < length(); i++) { - Internal.List->at(i).save(out); - } - out.push_back(SaveArrayEnd); - break; - case Class::Object: - out.push_back(SaveObject); - for(auto &entry : ObjectRange()) { - save_string(out, entry.first); - entry.second.save(out); - } - out.push_back(SaveObjectEnd); - break; - case Class::String: - out.push_back(SaveString); - save_string(out, *Internal.String); - break; - } - } - - Class JSONType() const { return Type; } - - /// Functions for getting primitives from the JSON object. - bool IsNull() const { return Type == Class::Null; } - - string ToString() const { bool b; return std::move( ToString( b ) ); } - string ToString( bool &ok ) const { - ok = (Type == Class::String); - return ok ? std::move( json_escape( *Internal.String ) ): string(""); - } - - double ToFloat() const { bool b; return ToFloat( b ); } - double ToFloat( bool &ok ) const { - ok = (Type == Class::Floating); - return ok ? Internal.Float : 0.0; - } - - long ToInt() const { bool b; return ToInt( b ); } - long ToInt( bool &ok ) const { - ok = (Type == Class::Integral); - return ok ? Internal.Int : 0; - } - - bool ToBool() const { bool b; return ToBool( b ); } - bool ToBool( bool &ok ) const { - ok = (Type == Class::Boolean); - return ok ? Internal.Bool : false; - } - - JSONWrapper> ObjectRange() { - if( Type == Class::Object ) - return JSONWrapper>( Internal.Map ); - return JSONWrapper>( nullptr ); - } - - JSONWrapper> ArrayRange() { - if( Type == Class::Array ) - return JSONWrapper>( Internal.List ); - return JSONWrapper>( nullptr ); - } - - JSONConstWrapper> ObjectRange() const { - if( Type == Class::Object ) - return JSONConstWrapper>( Internal.Map ); - return JSONConstWrapper>( nullptr ); - } - - - JSONConstWrapper> ArrayRange() const { - if( Type == Class::Array ) - return JSONConstWrapper>( Internal.List ); - return JSONConstWrapper>( nullptr ); - } - - string dump( int depth = 1, string tab = " ") const { - string pad = ""; - for( int i = 0; i < depth; ++i, pad += tab ); - - switch( Type ) { - case Class::Null: - return "null"; - case Class::Object: { - string s = "{\n"; - bool skip = true; - for( auto &p : *Internal.Map ) { - if( !skip ) s += ",\n"; - s += ( pad + "\"" + p.first + "\" : " + p.second.dump( depth + 1, tab ) ); - skip = false; - } - s += ( "\n" + pad.erase( 0, 2 ) + "}" ) ; - return s; - } - case Class::Array: { - string s = "["; - bool skip = true; - for( auto &p : *Internal.List ) { - if( !skip ) s += ", "; - s += p.dump( depth + 1, tab ); - skip = false; - } - s += "]"; - return s; - } - case Class::String: - return "\"" + json_escape( *Internal.String ) + "\""; - case Class::Floating: - return std::to_string( Internal.Float ); - case Class::Integral: - return std::to_string( Internal.Int ); - case Class::Boolean: - return Internal.Bool ? "true" : "false"; - default: - return ""; - } - return ""; - } - - friend std::ostream& operator<<( std::ostream&, const JSON & ); - - private: - void SetType( Class type ) { - if( type == Type ) - return; - - ClearInternal(); - - switch( type ) { - case Class::Null: Internal.Map = nullptr; break; - case Class::Object: Internal.Map = new map(); break; - case Class::Array: Internal.List = new deque(); break; - case Class::String: Internal.String = new string(); break; - case Class::Floating: Internal.Float = 0.0; break; - case Class::Integral: Internal.Int = 0; break; - case Class::Boolean: Internal.Bool = false; break; - } - - Type = type; - } - - private: - /* beware: only call if YOU know that Internal is allocated. No checks performed here. - This function should be called in a constructed JSON just before you are going to - overwrite Internal... - */ - void ClearInternal() { - switch( Type ) { - case Class::Object: delete Internal.Map; break; - case Class::Array: delete Internal.List; break; - case Class::String: delete Internal.String; break; - default:; - } - } - - private: - - Class Type = Class::Null; -}; - -inline JSON Array() { - return std::move( JSON::Make( JSON::Class::Array ) ); -} - -template -JSON Array( T... args ) { - JSON arr = JSON::Make( JSON::Class::Array ); - arr.append( args... ); - return std::move( arr ); -} - -inline JSON Object() { - return std::move( JSON::Make( JSON::Class::Object ) ); -} - -inline std::ostream& operator<<( std::ostream &os, const JSON &json ) { - os << json.dump(); - return os; -} - -namespace { - JSON parse_next( const string &, size_t & ); - - void consume_ws( const string &str, size_t &offset ) { - while( isspace( str[offset] ) ) ++offset; - } - - JSON parse_object( const string &str, size_t &offset ) { - JSON Object = JSON::Make( JSON::Class::Object ); - - ++offset; - consume_ws( str, offset ); - if( str[offset] == '}' ) { - ++offset; return std::move( Object ); - } - - while( true ) { - JSON Key = parse_next( str, offset ); - consume_ws( str, offset ); - if( str[offset] != ':' ) { - std::cerr << "Error: Object: Expected colon, found '" << str[offset] << "'\n"; - break; - } - consume_ws( str, ++offset ); - JSON Value = parse_next( str, offset ); - Object[Key.ToString()] = Value; - - consume_ws( str, offset ); - if( str[offset] == ',' ) { - ++offset; continue; - } - else if( str[offset] == '}' ) { - ++offset; break; - } - else { - std::cerr << "ERROR: Object: Expected comma, found '" << str[offset] << "'\n"; - break; - } - } - - return std::move( Object ); - } - - JSON parse_array( const string &str, size_t &offset ) { - JSON Array = JSON::Make( JSON::Class::Array ); - unsigned index = 0; - - ++offset; - consume_ws( str, offset ); - if( str[offset] == ']' ) { - ++offset; return std::move( Array ); - } - - while( true ) { - Array[index++] = parse_next( str, offset ); - consume_ws( str, offset ); - - if( str[offset] == ',' ) { - ++offset; continue; - } - else if( str[offset] == ']' ) { - ++offset; break; - } - else { - std::cerr << "ERROR: Array: Expected ',' or ']', found '" << str[offset] << "'\n"; - return std::move( JSON::Make( JSON::Class::Array ) ); - } - } - - return std::move( Array ); - } - - JSON parse_string( const string &str, size_t &offset ) { - JSON String; - string val; - for( char c = str[++offset]; c != '\"' ; c = str[++offset] ) { - if( c == '\\' ) { - switch( str[ ++offset ] ) { - case '\"': val += '\"'; break; - case '\\': val += '\\'; break; - case '/' : val += '/' ; break; - case 'b' : val += '\b'; break; - case 'f' : val += '\f'; break; - case 'n' : val += '\n'; break; - case 'r' : val += '\r'; break; - case 't' : val += '\t'; break; - case 'u' : { - val += "\\u" ; - for( unsigned i = 1; i <= 4; ++i ) { - c = str[offset+i]; - if( (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') ) - val += c; - else { - std::cerr << "ERROR: String: Expected hex character in unicode escape, found '" << c << "'\n"; - return std::move( JSON::Make( JSON::Class::String ) ); - } - } - offset += 4; - } break; - default : val += '\\'; break; - } - } - else - val += c; - } - ++offset; - String = val; - return std::move( String ); - } - - JSON parse_number( const string &str, size_t &offset ) { - JSON Number; - string val, exp_str; - char c; - bool isDouble = false; - long exp = 0; - while( true ) { - c = str[offset++]; - if( (c == '-') || (c >= '0' && c <= '9') ) - val += c; - else if( c == '.' ) { - val += c; - isDouble = true; - } - else - break; - } - if( c == 'E' || c == 'e' ) { - c = str[ offset++ ]; - if( c == '-' ){ ++offset; exp_str += '-';} - while( true ) { - c = str[ offset++ ]; - if( c >= '0' && c <= '9' ) - exp_str += c; - else if( !isspace( c ) && c != ',' && c != ']' && c != '}' ) { - std::cerr << "ERROR: Number: Expected a number for exponent, found '" << c << "'\n"; - return std::move( JSON::Make( JSON::Class::Null ) ); - } - else - break; - } - exp = std::stol( exp_str ); - } - else if( !isspace( c ) && c != ',' && c != ']' && c != '}' ) { - std::cerr << "ERROR: Number: unexpected character '" << c << "'\n"; - return std::move( JSON::Make( JSON::Class::Null ) ); - } - --offset; - - if( isDouble ) - Number = std::stod( val ) * std::pow( 10, exp ); - else { - if( !exp_str.empty() ) - Number = std::stol( val ) * std::pow( 10, exp ); - else - Number = std::stol( val ); - } - return std::move( Number ); - } - - JSON parse_bool( const string &str, size_t &offset ) { - JSON Bool; - if( str.substr( offset, 4 ) == "true" ) - Bool = true; - else if( str.substr( offset, 5 ) == "false" ) - Bool = false; - else { - std::cerr << "ERROR: Bool: Expected 'true' or 'false', found '" << str.substr( offset, 5 ) << "'\n"; - return std::move( JSON::Make( JSON::Class::Null ) ); - } - offset += (Bool.ToBool() ? 4 : 5); - return std::move( Bool ); - } - - JSON parse_null( const string &str, size_t &offset ) { - JSON Null; - if( str.substr( offset, 4 ) != "null" ) { - std::cerr << "ERROR: Null: Expected 'null', found '" << str.substr( offset, 4 ) << "'\n"; - return std::move( JSON::Make( JSON::Class::Null ) ); - } - offset += 4; - return std::move( Null ); - } - - JSON parse_next( const string &str, size_t &offset ) { - char value; - consume_ws( str, offset ); - value = str[offset]; - switch( value ) { - case '[' : return std::move( parse_array( str, offset ) ); - case '{' : return std::move( parse_object( str, offset ) ); - case '\"': return std::move( parse_string( str, offset ) ); - case 't' : - case 'f' : return std::move( parse_bool( str, offset ) ); - case 'n' : return std::move( parse_null( str, offset ) ); - default : if( ( value <= '9' && value >= '0' ) || value == '-' ) - return std::move( parse_number( str, offset ) ); - } - std::cerr << "ERROR: Parse: Unknown starting character '" << value << "'\n"; - return JSON(); - } -} - -inline JSON JSON::Load( const string &str ) { - size_t offset = 0; - return std::move( parse_next( str, offset ) ); -} - -inline std::string cached_read_string(std::vector &cached, int &p) { - std::string value((char*)&cached[p++]); - while(cached[p++] != 0); // Advance past the null terminator - return value; -} - -inline JSON JSON::LoadFromCached(std::vector &cached, int &p) { - JSON json; - - int saveType = cached[p++]; - - switch(saveType) { - case SaveNull: - break; - case SaveInt: - { - long val = 0; - for(int i = 0; i < 8; i++) val |= cached[p++] << (7 - i) * 8; - json = val; - } - break; - case SaveFloat: - { - double val = 0; - for(int i = 0; i < 8; i++) *((long*)&val) |= cached[p++] << (7 - i) * 8; - json = val; - } - break; - case SaveTrue: - json = true; - break; - case SaveFalse: - json = true; - break; - case SaveArray: - json = JSON::Make( JSON::Class::Array ); - while(cached[p] != SaveArrayEnd) { - json.append(LoadFromCached(cached, p)); - } - p++; - break; - case SaveObject: - json = JSON::Make( JSON::Class::Object ); - while(cached[p] != SaveObjectEnd) { - std::string key = cached_read_string(cached, p); - json[key] = LoadFromCached(cached, p); - } - p++; - break; - case SaveString: - json = cached_read_string(cached, p); - break; - } - - return json; -} - -} // End Namespace json diff --git a/tools/dkr_assets_tool_classes/make_asset_files/asset_asm_data.cpp b/tools/dkr_assets_tool_classes/make_asset_files/asset_asm_data.cpp deleted file mode 100644 index 14f62211..00000000 --- a/tools/dkr_assets_tool_classes/make_asset_files/asset_asm_data.cpp +++ /dev/null @@ -1,177 +0,0 @@ -#include "asset_asm_data.h" - -#define ASSETS_START_LABEL "ASSETS_START" -#define ASSETS_END_LABEL "ASSETS_END" -#define ASSETS_SIZE_LABEL "ASSETS_END - ASSETS_START" - -AssetAsmIncludes::AssetAsmIncludes(std::string assetsDirectory, std::string buildDirectory, std::string dstPath) { - std::stringstream out; - - write_comment(out, "This file is automatically generated. Any changes you make to this file will get overwritten."); - out << std::endl; - out << ".include \"macros.inc\"" << std::endl; - out << std::endl; - - std::vector sections = get_assets_order(); - write_main_table(out, sections); - - out << std::endl; - write_header_comment(out, "Asset Sections"); - write_global_label(out, ASSETS_START_LABEL, true); - out << std::endl; - - for(std::string §ionName : sections) { - write_section(out, assetsDirectory, buildDirectory, sectionName); - } - - write_global_label(out, ASSETS_END_LABEL, true); - - write_text_file(out.str(), dstPath + "/assets.s"); -} - -AssetAsmIncludes::~AssetAsmIncludes() { - -} - -void AssetAsmIncludes::write_comment(std::stringstream &out, std::string text) { - out << "# " << text << std::endl; -} - -void AssetAsmIncludes::write_header_comment(std::stringstream &out, std::string text) { - out << "/********** " << text << " **********/" << std::endl << std::endl; -} - -void AssetAsmIncludes::write_word(std::stringstream &out, std::string value) { - out << ".word " << value << std::endl; -} - -void AssetAsmIncludes::write_two_words(std::stringstream &out, std::string value, std::string value2) { - out << ".word " << value << ", " << value2 << std::endl; -} - -void AssetAsmIncludes::write_word_with_comment(std::stringstream &out, std::string value, std::string comment) { - out << ".word " << value << " # " << comment << std::endl; -} - -void AssetAsmIncludes::write_binary_include(std::stringstream &out, std::string path) { - out << ".incbin \"" << replace_extension(path, ".bin") << "\"" << std::endl; -} - -void AssetAsmIncludes::write_global_label(std::stringstream &out, std::string label, bool align) { - if(align) { - out << ".balign 16" << std::endl; - } - out << "glabel " << label << std::endl; -} - -void AssetAsmIncludes::write_main_table(std::stringstream &out, std::vector §ionNames) { - write_header_comment(out, "Asset Sections Table"); - write_word_with_comment(out, std::to_string(get_asset_count()), "Number of entries in the table"); - for(std::string §ionName : sectionNames) { - write_word(out, sectionName + " - " + ASSETS_START_LABEL); - } - write_word(out, ASSETS_SIZE_LABEL); -} - -std::string formatGameTextWordEntry(std::string sourceSectionFirst, std::string entryName, std::string gameTextJsonPath) { - bool isDialog = get_string_from_json(gameTextJsonPath, "text-type") == "Dialog"; - - if(isDialog) { - return "(" + entryName + " - " + sourceSectionFirst + ") | 0x80000000"; - } else { - return entryName + " - " + sourceSectionFirst; - } -} - -void AssetAsmIncludes::write_ttghost_table_entry(std::stringstream &out, std::string entryWord, std::string ttGhostJsonPath) { - int levelId = get_index_from_build_id("ASSET_LEVEL_HEADERS", get_string_from_json(ttGhostJsonPath, "header", "level")); - std::string vehicle = get_string_from_json(ttGhostJsonPath, "header", "vehicle"); - int vehicleId = get_enum_value_from_string("Vehicle", vehicle); - write_two_words(out, to_hex((levelId << 24) | (vehicleId << 16)), entryWord); -} - -void AssetAsmIncludes::write_section(std::stringstream &out, std::string assetsDirectory, std::string buildDirectory, std::string sectionName) { - write_header_comment(out, sectionName); - write_global_label(out, sectionName, true); - - if(get_string_from_section(sectionName, "type") == "Table") { - std::string sourceSectionName = get_source_section_for_table(sectionName); - - if(sectionName == "ASSET_MENU_TEXT_TABLE") { - int numTextEntries = get_array_length_from_section(sourceSectionName, "menu-text-build-ids"); - write_word_with_comment(out, std::to_string(numTextEntries), "Number of text entries for the languages"); - } - - std::vector sectionFilenames = get_section_order(sourceSectionName); - - bool first = true; - for(std::string &entryName : sectionFilenames) { - if(first) { - if(sectionName == "ASSET_AUDIO_TABLE") { - // For some reason, the first entry in the audio table is skipped. - first = false; - continue; - } - first = false; - } - - std::string entryWord = entryName + " - " + sourceSectionName; - - if(sectionName == "ASSET_GAME_TEXT_TABLE") { - std::string filename = get_filename_from_section_entry(sourceSectionName, entryName); - std::string folder = get_string_from_section(sourceSectionName, "folder"); - std::string gameTextJsonPath = assetsDirectory + "/" + folder + "/" + filename; - entryWord = formatGameTextWordEntry(sourceSectionName, entryName, gameTextJsonPath); - } - - if(sectionName == "ASSET_TTGHOSTS_TABLE") { - std::string filename = get_filename_from_section_entry(sourceSectionName, entryName); - std::string folder = get_string_from_section(sourceSectionName, "folder"); - std::string ttGhostJsonPath = assetsDirectory + "/" + folder + "/" + filename; - write_ttghost_table_entry(out, entryWord, ttGhostJsonPath); - } else { - if(sectionName == "ASSET_MISC_TABLE") { - entryWord = "(" + entryWord + ") / 4"; - } - write_word(out, entryWord); - } - } - - if(sectionName == "ASSET_TTGHOSTS_TABLE") { - write_two_words(out, "0xFFFF0000", sourceSectionName + "_END - " + sourceSectionName); - write_two_words(out, "0xFFFF0000", "0xFFFFFFFF"); - } else { - if(sectionName == "ASSET_MISC_TABLE") { - write_word(out, "(" + sourceSectionName + "_END - " + sourceSectionName + ") / 4"); - } else { - write_word(out, sourceSectionName + "_END - " + sourceSectionName); - } - write_word(out, "0xFFFFFFFF"); - } - } else { - std::string folder = get_string_from_section(sectionName, "folder"); - if(section_has_key(sectionName, "files")) { - std::vector sectionFilenames = get_section_order(sectionName); - for(std::string &subSectionName : sectionFilenames) { - write_global_label(out, subSectionName); - std::string filename = get_filename_from_section_entry(sectionName, subSectionName); - write_binary_include(out, buildDirectory + "/" + folder + "/" + filename); - } - } else if(section_has_key(sectionName, "filename")) { - std::string filename = get_string_from_section(sectionName, "filename"); - write_binary_include(out, buildDirectory + "/" + folder + "/" + filename); - } - write_global_label(out, sectionName + "_END"); - } - - out << std::endl; -} - - - - - - - - - diff --git a/tools/dkr_assets_tool_classes/make_asset_files/asset_asm_data.h b/tools/dkr_assets_tool_classes/make_asset_files/asset_asm_data.h deleted file mode 100644 index 33c13b05..00000000 --- a/tools/dkr_assets_tool_classes/make_asset_files/asset_asm_data.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -#include "../common/util.h" - -class AssetAsmIncludes { -public: - AssetAsmIncludes(std::string assetsDirectory, std::string buildDirectory, std::string dstPath); - ~AssetAsmIncludes(); -private: - void write_comment(std::stringstream &out, std::string text); - void write_header_comment(std::stringstream &out, std::string text); - void write_word(std::stringstream &out, std::string value); - void write_two_words(std::stringstream &out, std::string value, std::string value2); - void write_word_with_comment(std::stringstream &out, std::string value, std::string comment); - void write_binary_include(std::stringstream &out, std::string path); - void write_global_label(std::stringstream &out, std::string label, bool align = false); - void write_main_table(std::stringstream &out, std::vector §ionNames); - void write_section(std::stringstream &out, std::string assetsDirectory, std::string buildDirectory, std::string sectionName); - void write_ttghost_table_entry(std::stringstream &out, std::string entryWord, std::string ttGhostJsonPath); -}; diff --git a/tools/dkr_assets_tool_classes/make_asset_files/asset_enums_header.cpp b/tools/dkr_assets_tool_classes/make_asset_files/asset_enums_header.cpp deleted file mode 100644 index 0c1b8f00..00000000 --- a/tools/dkr_assets_tool_classes/make_asset_files/asset_enums_header.cpp +++ /dev/null @@ -1,75 +0,0 @@ -#include "asset_enums_header.h" - -#define INDENT " " -#define FILENAME "asset_enums.h" -#define HEADER_GUARD "_ASSET_ENUMS_H" - -#define ASSETS_START_LABEL "ASSETS_START" -#define ASSETS_END_LABEL "ASSETS_END" - -AssetEnumsHeader::AssetEnumsHeader(std::string dstFolder) { - std::stringstream out; - write_comment(out, "This file is automatically generated. Any changes you make to this file will get overwritten."); - out << std::endl; - out << "#ifndef " << HEADER_GUARD << std::endl; - out << "#define " << HEADER_GUARD << std::endl; - out << std::endl; - write_header_comment(out, "Asset Sections"); - std::vector assetsOrder = get_assets_order(); - write_order_section(out, "ASSET_SECTIONS", assetsOrder); - for(std::string §ionName : assetsOrder) { - if(section_has_key(sectionName, "files")) { - write_header_comment(out, sectionName); - std::vector sectionOrder = get_section_order(sectionName); - write_order_section(out, sectionName, sectionOrder); - } - std::string sectionType = get_string_from_section(sectionName, "type"); - if(sectionType == "MenuText") { - std::vector menuTextBuildIds = get_array_from_section(sectionName, "menu-text-build-ids"); - write_order_section(out, sectionName + "_IDS", menuTextBuildIds); - } else if (sectionType == "Fonts") { - std::vector fonts = get_array_from_section(sectionName, "fonts-order"); - write_header_comment(out, sectionName); - write_order_section(out, sectionName, fonts); - } - } - out << "#endif " << std::endl; - write_text_file(out.str(), dstFolder + "/" + FILENAME); -} - -AssetEnumsHeader::~AssetEnumsHeader() { - -} - -void AssetEnumsHeader::write_comment(std::stringstream &out, std::string text) { - out << "// " << text << std::endl; -} - -void AssetEnumsHeader::write_header_comment(std::stringstream &out, std::string text) { - out << "/********** " << text << " **********/" << std::endl << std::endl; -} - -void AssetEnumsHeader::write_order_section(std::stringstream &out, std::string name, std::vector &order) { - out << "typedef enum {" << std::endl; - int numberOfEntries = order.size(); - for(int i = 0; i < numberOfEntries; i++) { - std::string enumEntryName = order[i]; - - if(enumEntryName.length() == 0) { - enumEntryName = name + "_NULL_" + std::to_string(i); - } - - out << INDENT << enumEntryName; - if(i < numberOfEntries - 1) { - out << ","; - } - out << std::endl; - } - out << "} " << upper_snake_case_to_pascal_case(name) << "Enum;" << std::endl << std::endl; -} - - - - - - diff --git a/tools/dkr_assets_tool_classes/make_asset_files/asset_enums_header.h b/tools/dkr_assets_tool_classes/make_asset_files/asset_enums_header.h deleted file mode 100644 index 1c7af6c8..00000000 --- a/tools/dkr_assets_tool_classes/make_asset_files/asset_enums_header.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -#include "../common/util.h" - -class AssetEnumsHeader { -public: - AssetEnumsHeader(std::string dstPath); - ~AssetEnumsHeader(); -private: - void write_comment(std::stringstream &out, std::string text); - void write_header_comment(std::stringstream &out, std::string text); - void write_order_section(std::stringstream &out, std::string name, std::vector &order); -}; diff --git a/tools/dkr_assets_tool_settings.json b/tools/dkr_assets_tool_settings.json new file mode 100644 index 00000000..54c77f82 --- /dev/null +++ b/tools/dkr_assets_tool_settings.json @@ -0,0 +1,17 @@ +{ + "default_dkr_version": "us_1.0", + "baseroms_subpath" : "baseroms/", + "assets_subpath" : "assets/", + "configs_subpath" : "extract-ver/", + "include_subpath" : "include/", + "asm_subpath" : "asm/", + "src_subpath" : "src/", + "lib_asm_subpath" : "lib/asm/", + "lib_src_subpath" : "lib/src/", + "build_subpath" : "build/", + "data_subpath" : "data/", + "model_scale": 0.001, + "debug": { + "keep-uncompressed": true + } +} \ No newline at end of file diff --git a/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/builder/buildInfo.o b/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/builder/buildInfo.o new file mode 100644 index 0000000000000000000000000000000000000000..897f01d1f22153e55dd04b9c5b849c26753ba4c4 GIT binary patch literal 2400 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 ?!$AT2&f;;=q7 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 literal 0 HcmV?d00001 diff --git a/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/builder/buildTypes/buildLevelModel.o b/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/builder/buildTypes/buildLevelModel.o new file mode 100644 index 0000000000000000000000000000000000000000..96180872cda606538f2c4690e427da352f14cf7e GIT binary patch literal 22584 zcmb<-^>JfjWMpQ50!9Wq21Y0wnX>Rk@EpKQ2L=-cW3XC21_m%Kz`(#D2xW^fFffQh z*1Oo$uBm)D36qGN+z`!8Oz`!5} z#Iy5Cs7L45V2{q<9?fqAQarj@R5chF7(6;%R5%O|c(h(B;q++z#^2Jwz`)?C`NpSH zMa8rE4}ZCfN4K?S^B=}iWBzTf3?1w~-6|>`-PS&x$sA6{SkxIjx?NN_QarRF#+3$m zG#?R&j&+PV%rEc2;M@A7^ z-+?8dM!#O{(Q6A*2o?krL*4zK`Q?5co{*-;FW&<47z2p!815M680r`j>d|=>94(D+ zW-u@?AjM3JN(Tc2gW&;>PII5$9F+u*ZX=J*a1Ni|6cq!X-V&7ppU#&)y)`Nh9=$ax zpn&x0EKy1DIPRj70kY+oi%J25PiKva!EqNA2mPYNa*&h-3j+hgF&7mV29M4f6%KIl zdUV&Q82DKJFX02lrh`Xs0V7;I!N>ADM7#h=+(ktK8c80VEGl5dHjJg*9?do?4E!xJ zj0_AO-6bjl9^D}-5pAr9+y~-Zd(q)aKFo9&CUQl=kR$<^Vg} zr}Mc-cZ7gPx3NceFi7hQlfNKs#R?w1F)9Hbo%f;o-uZMs2QxjoO;ijoA$TP!0UoX2 zN;qIjaeH(N#3>NP5chx-WA}ZHihxJ2i;9AW<#9;RC?Ew5B-Ri)Le8V{2q?H#O12}DXbRLGYafu_V!OcDjHV0%bG6vb#`Qb1_Qetst za(r<~QD$Dcl~ufNd~$wXaY<2Wa*0A-X-Kdpxe{1oaY1TwW?E)yiXzxgpgjC1G}xm%p2MSC-^22CiBlRZKX`PP zDu5!2)1$Xm0URP8-L(uJy{-bFAm;Vxb`?N`aPv_O56jo3r#-uMR6JVWmPmPml3KJ! z=X(#$cd?E!U>~RP%eyczfWrJRsQe4{>CG2#3<(YPXnrGsl*Pb>pHHVgxajKymxsSS zI=_2#eucQAlSRd|^N2_D5B_pHkLDkYrH0^A&{+Une02+ZbUJe!V_`xs1#LZ=k4S(l zcZ@yk(R!fd;%jMe`3Fyjoy?w{N5N*mi$GZNf4u}^HBuQk0Tf@3VLrX4pm=Z$_370G zGeUfNRY8nU4~Rf8C=43kJU}l-Zh(ssh_T(^q7_o=LbX98I^TOh%ztqXlsP-!d31wq z0V{>%2p@!+Rsa6~_vw7()AGiK{n9MPL^bD1SlH7%ZYdHJ1gl1XQ^TsB-(ht271DLPo0BYnKa3zdv>H!7@29T*2K$f?t zoB-#x&K8voAaRh1L9UK2zOH(?AQM4~J&w1i>|kJE;Dl&6iDEiL7c_stvXGAozenf0 zU94aeA#xtQb5ub2*rWNihDUETw3LKafuQp687MD83JssmM_|``^ny%afJV_VFh}2` z6HJ5h@{aVx+|>BA{5+`Gj*?;qhBS!0$8oSSZjhV7EJzr8_U1l-M_zXe*hz@GPSKV+^R`1DDHScY%sC&(0%Y0Vo?<6v2f&Iw3U|NE#O#*$9u$qdvWm zxI#7qBnAp$RIwbD1h4=oBET4AORz_GxdNzp-1@DA)1$W@8p7Sy9=*=sYDmbVyI3IF zqxl#kSTm@78x5*lV0Cu4Ij9Qbfl7i}HVjZ{c>VV!)T8sSN9Xroa4>lEh6?y}J_8ln zouLe#y&^0=y{Qmu;Y}E5n+Q~w90s}4v-8MnArQl(^RQ3nbI;B@5Tl^#VEX?5XB5z3 zWneI2bz`t$^=HU|L}7Ab9;ixBE=o--NmVE=NwKmjOHD4xFH*=!EJ{x;QYgtt%u~os ztcWkptV-1YbtB;61YSt_+@?$2>b@1w1+r`&vFPu>gfH zIOw}e89cf}L2Wot&w=q1#KXO%3W#g~Y7#Ub*6_4^Q+md;GnT`n`3MIn$Uw=?G5+ub zsG|&TdmMKMJLmOHXxaoD1_{sOucaZ3qpyRY3`Bhm$%H+e;q~lxL$p;qn~!O{J_S`%%i!5vD&V2{&!hE!2}C0-CxKN!?R>H^(hm$`v{I7>1ac1W5Zkq*PtN( zAS(q1>1cyoumqF<84c=dcy|5?^=N#vff22rv4RoQ&j6L53Ld>VDh7z+4pNUoQx~Y) z1}VS64u+&%FcVtS!u;a_YTPh*bUVE8>0ZM6fq?tbYm!oqN#(QFF~ z!vrSQIV=n_m{@PHFl=XHJ;TCqf{FD23&Uk5)(I>O51Ck3urRc-ux?>t`2U}g#mR;N zL|ePAVr5`h$i{k%i(wrbYa18C7dF;;TnsJjtnWA(F0r$2;$nEj&iad!;U7EeBrb+l zPS)F;3==t7&vSybvj~?nFt~UJDL57vr!=a6c;7yGvs6@=_eNFLKt9?l*E!meTF1ZKT4lLFF7$eBUPUvH$SBqtOKM0 zluXgFyR);Ef<|akXgVa@+%K?;LZx9*OgD8nJJBnkHeSSk&go$9y(BYP*{SLfWpWD zDh3*p1Brpm0nv zw+{mYLkLuT9wStJ0G~iVlM|mrAF~smLNALepGFU>BcDMVn4a{vPa!x^Z$0w$=vZm9M; z!R>Vc+3Ur3fsy$pBUYOoL9Iv7*rWn9yy{?n=exkz%-+Vx*;G*EEwbj7KV@iu}Cp6Gk~fNOc`bdUQ9s-1_ovZ&X6R0?-Zh#9iFfhD?ic2F4 zGB7Z_gNj?CiGP8LL*|MQlE0whUI-xw3tW+?F$6()aFPuw9uF6RFnFNi;Q0ZF5SSE# zilcNI7#J8NpyEYfRR}^3Dqf8c0<%=0;*ePmun?Hgf{Me!9V`fHS3t!l!UUkS8B}~G zlnJ3+-4gE&ao11ydn`V0)dU~zdQl@MkSR2S|MjYn6z@h#P0!RyE6bR4r{eCFo4>aAa^do zVg4!{;@5GAf5jor&V}9m;yA=rxj^p6bY~@499F9^Fo4>$AotJ3Va{C~;-cKx-J^&@ zTpx#cJ`V9p9OB1uh(Ev~{tSosCmiC!JlOrEjYB+`5t3hE?PgHh9~7S1IMnasVPIIu z03RL%52}OIKfs}$i5I(jG;xS0@nUz+Optoa;+A0hP4U;nxi{eX)5;IGRJ(FF76Frk% zT@8(pXJ0)7l3iWPLgItXKfpk9ONBr9IpqSW-choF93PK-N)a_(I-B>xHKu=Gd@1b&(IWY zR@vFeHOSE1CA$bRcoPgAn+dW6tMklD%V&s>@-Z@UadmSH^$Cf03=Vb;362jAbqa6{ z@c_vg8oPK0IflfCxdsJ$`uj1&M+KMoSj5L?=4a+*mVi|lKveiS`nrPomJoihYee;)>#S zOPEf_U|;MK!9mW*5(v9|Je}gvbfHS3>okDb<>DCPh+?K8OvWkH)5it7l(VC=2a4N` z;O6=IyP$g63}&9MzYCTaGcpKr4e*Z-^7jvkck}dfi3dexFgRu`-2D9@(d*(Fz-+Ki zL$FpuuwEmuUL&wxBd}g0uwEmGUXUiRC|J-0lCjMo(=(oa!6k+UX_+~x#g)Y+skyMy z#iSsyBm-1}1RKS>y1JOUmO-@PREw;nG%vHTG&R1UqzJF^rtv@|PHIVN5mEL!n|eB$#3u(E#=E)(d56UN1slejrR5jpCYFFQm0xfPNj`Np zbqy{tGy~<`%*33`s??(RoXp}9Pf##`OBhfvcn6o5CYMweqm&fPir)MU|rxq3E7X^4HGsMRi zmn0@<$0uiG$EPJ`=0Gea$)7GpkQnvG6aA3*L5q~+9M=H9V54|wv@yg-rQ`&Z<&xtB zL)S8f;*z4A)I5l8+-VEySUhfZ0U3s^gok+)qv(g}02xZX1dHTS>KO|48_1xQsRSBi%WA;38WHdLp)&sZaR^aL!6BW zmjrp`(1cGo1cSVTjpD)C+QnpB$Zk(yJGT4V|?bv(TSKrK1fGM9o7kS~zip%%#P z(BhJ!)Wlretx;%N3NFbh_QY(lx&{T87#c&&%ZC{i67L#p8V@e_qWpsMjSEUkpk-~o zXAFNu_DH-D6x_QUul?Tw;=(UkYllfy)2*c&PR9nR&&j zMJ3n_z~uyAI94*i1MUp8! zppk9R934zt3MvlL4l*YO#9&}xkcWzc%xOdlH%+KGNEv8xIm{djs5r>{CM5OFP;qo~ ze4*kXb3kzoGY2-$iLO2!Nj=D&G9Zl%h;eTaS0BmV7N~l3bGo78AoU<~{y_PYpfpGv zG-n8N4`^K-D5%lRS&yV1WX>HZe;bqrnFGozFmuj8#nH{V3>62dH$rm%8>l$C`p-~t zkb024bD;cRP#Pp|jAV`gNC28{k>gPuDh{GR=D^B*IgkJ}eS-21%>5=%adh`sL&ZT9 z$eb9cJDflQP;)>l5Mky-K*iC`iHC}VD3CceP;=5i0#I|zko*Np@95?q%{(uZ&U|?7W5`ek~v~CIJuOm=#baPHa#X%IvoI6l+ zE`bD~=78pqVdjA5-9bvw&3TWc9%K%zeeexQ95kl}GlvJH2ur*RL&ZVbK+HKH%Ru`Q zK^&-itdYXU04k2|9&@NT%$ypiId(|mHb~}#K*iC`iGzy6%!z@TQv(%8SKkX22dM|` zgMs;XDpVY#9yDhT6JG`u2dTG1a?fh0IJ){rNaD!tjrU06$n6bNkO9zeMpo~NB#x{e zGOr9-ABC)bF%I>spyD9+gPZ_r6M%vUymA(5Z#t5{u0Yj;sBk3lJ0Jn5dQcd{!sj(q z9ArLd?HEk_GgKTzA(tD!KmyQo0&))z$T6V3s?Z5qkU1c6*o+@LnmB0v6i5p{nmEi} zWi)Y^`TA($uo+`BG;xsGAnbr94x1T<%*SJfe-KnX$a~1~RRt9X`70PHJiDRdAoa-Y zfu&G!ka|!!!2Hz)6$hzD4$tXOagcgYI}Ow}1-T!zR2D?T#6fi`h`$X@{S}ZP0|Ub$ zG;vt@a1KrU4OIOtH1SDL@powAu=0utx`YAdo+D88!f4`OpyIIb2Kg7c{RXOAK}ta4 z$n7-P3OtZFvU*UMz|TczCg|| zsYv3;`31JV24p@+FD!mRc7e2j#1oOyNgqfMnqNTfgsBIwE`{0)YV*RxuOX?oM=}T2 z4g{H>j3f@Lmq6mk?qq@1pCED2I$oIh(n#XS;cS8=jvO!cNaCO{fteG6B#x{eR{w+S zMGl`tB=u=X?gzCoKwbu^&qNXj)j=R}P?&+%Qo-zn^-DnNvyjyLf)qo;*%3(`wyp|Y zJ;-e!E$HH)umXvL>~%siCkG@5jW1+-=OT$`BdK4CBo5LGbN^N(aZp-o0)Bk>eefUqRvpNa~+L%>kJYTE7f4|1(q^q#m?J3?}{?NxT@z z99aJXWDck=22-z%6u%`%>XF<3$nNw;QeTRs9<+`DWHrb=pg4k=&khoVhCgyXh4n8% z>XFR{ox1?i0uo174_h$?5=T}K>j#6xk=29R@Gx_b)x**!NIkMRa{5GeKPa!k%t1Ck z3?vBk7qU69^^)l3gVG*I3%WQc?y!l&>JyN9WcR@86OcHvdtmGPK;p>mfz=Nnab$Cr zgDi!*AK4t_{xY&TuyPvR99Vq<5=S=Y43hcC=D_Mbka}eIAg6z1bDrQZ2UZ`Vn**!I zK;p>e5L4bFy9a7511PzJ)+EB#(;|z9~;23oTZVuNrp zlKM!H02EgsiNo4-AgM+qaabDwBo6C$gUm;)l4M}mh@>8t_d)7^Ac-SZH!?6Vf((HA z3v@;cNG%A%)^UTRK^V4fN)yC^suu<+gyIq;aafxKBvp$f4pI;5gMq|nAc=#*85S?F z@l233NIj^I0jYSMG!gz#wtq9 zNz^Mzttes81MO8}&`T;VW&jK5#e?T>uuiJ$73G6egUmD3vtZDJn*!2A;_NyHPKHi6#g`-|<)lKw3#Zrc zP9ei00qh>qW*iAkqf#Ye2~XDI2oCD{g#js?P^P!A%%Vd4ZHSik2JP%Y5V@u_ zFDElQHK!8OB)IE~ONtEjU@imAKE@{&6(v@JGpt^G6rs62Ncsh5+M?7PJU&87@7>!FmNG(VotZo762erju`d~CJ z{jj}y$ogHN?HZ7|g!IGOYsmUtNzf1KBY^CI)myOE$DHvWdJ-<<^gu=x;V{h+o5 z%-=8?SNOr&8_4kon%{%zgVDJ3!}c~Jhaaf@0MiGfK`X{VRXudr0Tg6l3_2nL%z!Bb zb1>H|gLaaDl)%y(R2hQ>D+xLRYeo#LMoBb1@_QS#%WIt#O58Zyy`U7nC8$j&`jV-|J2GQvL z2lX4U*}np6KPY}d`at%B+=6aDWS=Jk0~1>KEri++3Nw&?7zVi&#s<;X!TU8C7|_%I z4yb;Ry&!ck46`3*jy-r^Bm)C_`u_mc58HDGo)ejq=hpC788%BfXeL!q< z|8IcmhwbBm=|}g!5i?}$9o_#OputWC1_sdnSddMv(v2k<5do-@D9^J$1}z0gyq! zeyFhwoGhUI#|#YQ>StlWp8guJxF58Z0p@R*`$6-4ps+;GX9ZCAgX(vfTR}8PEi!Ef zbw5Z98P9?0M-~IIVfsOA5cXqXU;x$eXu-#@0IDC9XF%#;80LN$KMiU>y8Z)D{S0Uc z16_Y2Ec{>wLg^XM@I%hOp!FCq{jl%@`3K!@kP!!<1&;@`90jFsP@5iIKd5>}b0SDP w0|)5fTm}XPV`w=976i>p!Wd8*lufYdKLBcMGcYiegAzAXErJfjWMpQ50!9Wq21Y0wnTiNN@EpKQ2L>|+Q?Oco1_m%K$iToL1Z9gdFffQg z+2RZg3=&YbBm)D36axc;G?XvPz`!8Kz`!66g(;L+)#!eMy8qxDh=r$_5I{+0#?1_n>f zH$I&zDxS@M_{&{9x~)B%|1g#s^KWxy=wSEhR#EZjw)W{v=5RX3qR!ya?V`ew;-L*O zt~9`-`G`PttYge!et8E5-_|E3S6|Ca@aVkn(fQ2q(hHDtJUW>@I*)sFv#5Au{d%!SuPsO+SP)En=9l|*ctV;UzkCZwf&s*L4BrWMYv+H*9XY8C431%r zp^hP;!5)ooX0R|YAo;LGrGtfm!SH}br@2pWib{e(fpf}zik^M1BjK(-?oK`fx+<7K2ZAe>3j}$Cd8i3TcDurE>X$w z*m3x)Moj;quNoc)Uom-f`=}&%e1GK8dBLOk(I1b4FPJA28@(blkzt0J75Xn@2A%D9C*}pF?cy=27wJ z4G{3?^ifgp=;rXSyvX0;$^=SCU;z)XjDbhD2gfl70S1sV4UbL%NN62*-~gG0CBQtp z-8p=EOH>qmI=^{zTY#-Gu(nZwgt-AC%$pB0 zdRWG&aPYV8{rCSrJlIQgKyf1g3K0&E-YF^#EDQ`Dy(}J}^tlscsz>tyrnF9ve;$^H zO5cGT0?6N{{QEf2cCMdYOT~q?#aq%(? z>_(XH=c`MSgj zDf~(mJX*h%aC-FCDnQdwErUm|tAK~)@e*E-ZdU<#+<7z~)$p)CADAg$ccu zvGr&^A_218G4`-W>w%Jsucg8Di$~{usJYCZokziDz^fRa&i7!s*Gs?@aw3@kN)(P^ zKE0-(AO(2_TpT-w`1GoRL_$3v<#RA73>x1&U_h&0Zh*?l0}x}o!BrQeR)cDTNOZpU zfSCW{94NnZzVqk?+X7Y!aheZ8&8mO@|NC@4^67l%0d+UDj({2h@=Y5NYLbXhV~0zP zPv>`^&UY{5VDjG(ZUKiB+%4Z<{Q3)ZFCI15h)}bM2sM2~sL3KijT;eal!#FC?+;j* zDi+AHP*HG+2`WbmzzMJDC#X3C(c;tj9jpkH%s@E+TDKBJl^F~S3=n-k zK#p4h67FmPOGCBdG-3ltZEuUp0k{$0K}K8v33s-rfTXb+0Sya}ULO^HkIr|ySRwks zYCU@AsDSdJNAqh9kKSr%DF-VLEMJ#C^XYsC%4^6?Gf1|EdJbG1f^uNdSD)To1&>aU z@sL^(9t_aD2xmn(pp|B!m19vVX3)*iji;A%j~qq|rj+N1dxBiMPM_E9vb zaEI0}9^K}kDuf3r32whYrQ!9@mr#$+zaE|6gTbEl=nWMBH9tDvdvt~}c=n30`1Gbi ztc5oxp#cgi%MXKG>DhVYwGfEm(RtXX^SNi|9f(m-bufMZ|1%2cure^1u(~nWu=+FP zfa8iGIWZ4Z1t%A!CYGcs6qlq}S(T+Gm*f{IEx+)$2!fP%9tPz| z0Z^~twK=T);|Q%4LA@@I-ckif&kLT)K{a;sVGU2qcl<3AL3yG(m%*nymBXXATEL^z z+Nbk{595OpPT$tI{4G;J@|`Iv0^r`A7^rJkvH;XiTl`uLsl8yLVt5IuHU+goLCtVz zj}25SfPCrGodRktTE9&G4{pCfgT?T+2Q(O9?c7dKqr^o;0+C_#JerSafTA6gK^)@` zLvsuywvqE_cZ>?h>wRExNV+%*OCU#IXG27ezvf1`6;hRgdjcitpoSxdM|XjOM{fnV z1;h$A2r6vh(R=`$^u?e84&Y`GDC{B1nq5>lG+u88b3D84J-f>VJT(7#wEi!FngdOi zUroc)Z~!P6 z8Kk2Pt&I(H8C-*c{DZ6%7^I^Oa={W%0%Wu!Bz<~zegpM$!TtHhHyaqynj$M0K|Nhi z*{=ZV<{H3DE_l5Fb}J}8AtGR|Pv<{a)$Y-G+^6#!SQN~B24O-JBNQF==w|Tfc6i~_ zy@d4x0|Th1&)+g1)D&!}QL$hsNpa-gSEAyK&~O}LPUlmP-VzlHxOjJn3WrCxi3&>e zLql~x3#_wkcnR9nI1Uaok4}hbu+qR2G?oDE0C0h_TDOCNhvkKm#(f~3Pv`Uh7x?#m zc$xqI|9`M6K*0$rX!xNFm}_8x1vB^me@1CrRt5&2UdHoG3@;g3Z!j@TVzNEY#PErU zm4N})F4toKjThvk>NB`_2Prrf7pImKD}?0d=P(4NmSq-$8uca&DcMEwiD0StlKlLf z_~O)(lFYpHV!f>5{5*!z;&?+n15p1WwJ1NgSf2r+RG%TWqNFG>xkR@twMd^KGcP%( zG$j=zo2$=IT$HTOkdv9DpIDp=VSq(a5=#>G8InL94}Au`*CmcJcrJ8FlJdcXKc-XG~;Z_{zk3pM&86GwX2q$IwULuy5<4pc!z^~zy_^h-*jaly8TPTWF6CsH&B4mRu$Y7OD+j}B4%U|(5L3&c z*%^Z}FfcGQFfuSUFflMSFf%YWurRPRG%z$YG%_?cG%++aG&3|ev@o5+lTfh%SP1_lEt1_^^2nhZ{S0zFJFd=hQU zE_@2jEbe>;OmSR%3XXgdj(h@6d>pRa3?`tS9Y_NM14Au{c7yA21nFUlWX2dnnx zhHGSCuwYfQM(q;uBT=@i=nbNrUIDEMs`8dFS`vDSXU|;}+3y2BwFAr#hiGhIuG*%1} z1DOM&8LI+(z@fuF8^o1{g%M~>SOp})z`#(*zyKQAVqie{&mH8yLM~WfICA?iFffEb z)%!6a)b}&F@=5eDJMk&>vN-W+^sqYe8MLuE@>w*q2k<2@hcj~VSvc|;IPz&Y@hLd* zNx(b`ijO5w^U4`9%yZ>~ndbsB&zuga zFff3IO?04PX9Eidz6+eq>}_m4ti3FK%>7Ir3=9kbP&HSP?CoRn;+w$4EWyIXXW-7K;eq67SD1Zspk{T!?VG^V%+|)*!_v##2kN##!v&oJ zX=7pd_#a&y#AjvznGRy1VrB+DQ~@ZDnE^Bd0p&m`H3kL-CM0vf`2;G*%mA9HfO3#1 zW(Hv-9)vj+Yz{&koChFM49pDRekPQMpqLpzGad*&jKvI3(J&DR%?zFmfv}NDW(Lsg z2(k!-%?zF`fv}NDW(Lsg39<-;%?zGRfv}NDW(M#W5V8=M&CH+9z{)PvF& zNd7rAd|=@VN>d@~D((PH8=y1`5)XxnH$cUq+89!x;t5c3 znEDc^xB{AZFH{^ESzEPpAQvZ08)%(4row>k%5l^+?hoZzXDaC zfTsQnR2)>6fuun5bs(CL8R9Px8-zhKYam(;njT>30F?hh;#uGd4OEJQcnF*i7FS^a zHCqv)3=Abuabz(NyAmue0Iusmd>F0+i>rX=8DU}|x)~}CnmYvXVYm}24jzz%2{JG+ z^h3qHk;FjEsZjAC5C;j*hKk1^iGi34q2jP{agZ1YFNcbQ>LU;zhSx&Ht6&09dNWkK z9?FMNJE7u`*+G~n1H*o(crQW-%sL7cp9bb3h|^GUSX~a2xd;_s3=@FT*P-I8p?ny1 z7b?CHCIF=$L&dj3`7r7wRD35)07}1yiXVjXVboWs_$inGl>QABzXIjMC`M2t3f$6w zi9l#JusAH2K*T^KH&h%vqyZ9uVgaZ)ddd|Ai$e<;s9F%^0~QB63dDuue6To}fQx|` zN5Dd`Rt`u6g8zfXL36JVK8y@z1NQx~FOL<{CWNVj(VK9H@5CW~4Tt!1u)T=- z5!_Y;&C#=Aw>JrgcorMT{g~z~#G!r#SUsXX1-BO&7#L3D5P!$Uz#zoH%>XM8;UUY8 zU0jGAVv@1bj{hghGL6Hg6;so&+7+~p0m;-zG*x(S)#UZ{C zhxk8s?B*Zf0Qn2koxj22i1q`hoeOfYKPPr`LUD*U;SgVdLwpks@k2PoFK~j~kLgYo zE|55)Jp*c2gWT`Kh28xNNGxv{&)5r=p`4)GN@#Mj{v--Sc` zHV*O6IK;n!*X(dJfMzH_;S1`EfM{bL?EdQDVPIIu09uU$QiVwWt8l1416B`O#RE}) z5<)Ss@M1UL8;AH59OBP$i0koTH@^{w_(wiSxq%)Iiu?==0+_`=gC0m6>KA0n4TpFP z4)GEk;*B`OA;VwbDR#&VJJJL@cz#_kxuAd{KFTk+#5_JexuOCz)Pg*@@0lE2VrZD0 zkysR8Qk0lkQtX-R8l32v?CNT0ggou<8Q`7l>RJ{OA8ZjHTw-L9mS0q!Sd1t1gMef*sqed6Pb zOOxU~UD z;P~KBrvS$g50IRpv5R+*V@Q0MYf!MKzaK+zM1`NDuPc~u z3E>C3hJ<+fxd+F)dHTR4pw_r}2O$~gV`Kue-^nr9HOSu=#RW#jFj;4RKQ~Wz9Fm@X z&OV_ot|)G|gz0n)_Qfs{9OR5Ffw0TR(P6L=-E{-9NC}tYMWSl}heO$0h zIXgOgpt#)#Zl15d3#ymRVCMPyyI_eiBZDB<0RQ+PfB%qpH%~v8cu-UZgJZ_R&EGEs zY?zB@kgIcue^4YtJVnVzFF8Lag+b59*#JbCg9uX)VFn^BL4+Y##?TPVHUg8zVA2Fk zf>j%Wl^cS!8(M(H!Fr9rdX2z(jlg=1zYfFL>o@E$Vy7{ zG7C#n;|ofP@EUI#?~_?vVjAz6Tae@G7i=7FXbfh@r=;ejmZTODWv{cTr=v-Ha2`I<;1(%TIQ)g4x;1WYKP{z(o%*m`uEsD>{EH3c`1p~O; z0R@A1aEWPhNo7H*XR@nBN`8EKW=d+FYcfcR^m5b^RE&b>X0$(lQExoa z4~ZYNNJ-9d4e$##iibuULwr<9PC!{MIZiNiEn_GyDauLBgXqScwxEv1<5m}tVJPK3 z%!iP29<=lfrUqmT^^z!(+o)$K)HfiP;>erMMtIV_OSoQ9YMNere0oJid_ihaaeiK6 zPG(7Ed>OR%#TnF)ICmy&zoALIZ+vkaO&W3ox0Nkh{DNi^X5zhO0<dgN@?B8QI7Ho{>}Y z(n~Usb8>P;Vti6+dS+gHa$-qx1_P)SmKdL!mx97CN(C1LknkYQQ-*{+XwjQ* znwC>qoB>KjQGVV?NzoKyHe|VKQfV4)hZ+}`6oK^zmzX5ymx3C1pz0t#9_p@ms2i}f zim~}3BtFC--Zj`PJ^<8Y&4EU4Vopwea$-qpd}>8897uxAPm511 zDoU($4e~}#1V+dKi#t?76>$`5A~Q};EpaV#waCmXE=kNw2Iq8?RA^{iTAZ1e4qhry z1T9`b-4u)X_>|O=#LOH+i}?7G{CH5;q&VKtAU-pN3+aONt?R z1|A?pIvKTh^( zg7mzgZZid$n+RF}5}%oul3IbacScSk3xe8*sPLT)u^Nuj^@~p_&X3PX%uC4ur@`P7 zi_HAu_@u<*R1?p<%o0e+1??aBySah34}>^6`M83;hOQctf#N}BdSXdx1-NrahF8GG zfQJb{E5$(!(6Fx`0|Ub!@FKha{}+J-p>wGINaCBI;-Dc2&?pK_{dTB0$Q;mIGE96A zl6WAJIsVZ3Cy;v3m@Z6x4w5)%P8=p)3>632TZd#$1ymel4rs0drhYM09HbsJ=L8eK z0u=|TZ$vW34x|t~cgO%9O@gU+gNlRHHzBE?izJTh&W%Xo%}DAWAc-TZcY+StgUkob zsle=QKoUoG=P@MlRwVQ9A&DcKuLd$08jo#A>b;S~k=5tm5C`q+0!1ZA8reNhK?2Zl z1C2t%-2V|t95mMj6aNMk2T`DfcQEnaAOWa5k<$ri(GSR8Q1F39?_uhNp#$tNaoBnl zc{FjTu?*U1;;{7@=4j$DbM!!#LfsRL6mFpP3Lq(vxya#`2NHy;M-~UIa{)<#)Q2IN z(*qKOsz=UupvB!FDUf>Pe77DX2vv_9KHH$;pm0FWkGrAbAajuOBW%1Aq#l%H_CWK) zC8&CsxDANGz`y|776y_6aY5_RVd4K6BnXXnkU2FV1q=)fY*6z+_JYb5n0j8QILM9N zNZ}v_6$fbtnG*wIfc9TP#X;tP!U|@NCR7}x3=~H&aSNz8$b8ToBuv~HDvoZBFH{_4 zjy{rmVDsqc>eG?bgWM?t(#XKTkcT7=nyZG{+X59wH>Vpa4$=-X=MR)W2}*;+4Uyaf zT4f3fYIJkfBdG_Oa|g-??PLV02bp7pWX>6=Ji0lTq2eI*#z^YlK*iD3e};;K)PwAW zt+)AwBo0dRuyBBlRim2&TAu)OC&-){sD3$+!O(OC+W7)A#{?>lZjLon97KW4iGiBq z1QLLnV}|6f2&g!^Iq^_&5Ct;F25L?kNC0Y%Ig&ZB^p0*$Gm?6cIWkalx{$;{YuI4^ zS^yPCH)lCi97KW4`2z|p1_p+8AOWa*K#Krj<{W{FqnmRYDh{GR=G=jra|t8>H3u}e z2{Y#fR269*NCnFCu-Q3Dl6SKkX22dTG1^6xCD zI7mHc?FG!<)lhMedV3`G8=&Io>bFD1LFz&K+M!&Avrq;|9E4%!UxkW;%!x-bAF?h2 zvW^e5wg#sD2~<7E3`c1EfPxOP-T<_w3W8zkB|rv4)gha&fFzD=zB*JKWWE#9I?7-q zagZF${Aj2+h(b0$86*I;7uozQs5r~@26p+M`{bdLh2e}2*?gEurATNLx z>4RvPI4F&R_?~F$CxHYR7#Kp)#9`}<64At0LDlD?iG$iMAgM|;@mU~21_p*!G;vTH z9V9goO&r#50i6K>k_UwYa=Q*xcf-Vy+i##f+c0rt^`LVlVB*N_I#62|Bn}E65QfDg zs4fGEgX~3)M^G6B6Gx86Sdbtzev#8{Dv~&Ix&^hRK~f;|laS&axm}uuB)$uz7;1hx zk~pkA1~Lb^T?*P@1=0c%M{bw4LF+e=UqNjzn15mI9FTfY9Kytr+c_>s_D+YI15%%X zBo6Dxfy9y1?J*?v$l-7fNjwwD9OU*4ay$xy91aZ!MM}cOCyO_B8h|68-uI{nFESDm^t1^>Oo~8OgtG$9NC@ONaEE<=EKHAK<+_KZy-L% zUJ#9J4i88W8ve-Qu>LMcJ+e8lJq{poWc9FqGe{g+J**xEi6g5AwY@=Bql?4p4Ujk} zt-`_qxqppp4yX))nS*REa(Res4sv;jYz`>Qv6%y_H_+V!TSp8MM>Ypmzk$S&-2mK^{*-HV0Pkfz%_L1FNq<;>hM8m)pqZ90GX?8o$WqK!q7V$q3X2fvrzO7Egw8 zkk(~`(k;ktm=vf_2V#T7K^VjaVNh8OqCsNFt43k#zd_<4dqHYI7}oy)iF1Mkpcs}P zLE<0`bEg2v;n4CBd9AiSl6V}{3=rjlB#yjm1G&Es%L^d&pmqBo8e}J|t_SgJk<3Bf zE zNIk5*Qh+253TIfjRU(Ol)Wh0udyvFI=7aiLAoGtRiG$RG#tK2=40^?txh08740^>S zMG!gz#wtq9Nz^Mzttes818s$5&`T;VW&jK5#e?U^u&!ayE6N9{2AOB5XThKcHwC1L z#KjcgDR?9kic1oUN=geb48=Jofo=eJPS?fmlPT5q1auTmy?;Dnp25sIMjupnO?}eE0Ryin*;@Ae!ci8 zv~a?hg@xn=Z~;)1nxhArr_RyCx0*yRIX^cyHLrw0FE76&RnOfoR2RH93Cd5;E7b$7 z(M&BWsf2neH6uQ)C^0vcK`*^1zZBG%1s7zL5qnq|uwPRrG?m=Uyp!OcD?u5~} z^uyXausR8(A0!6T2cvQ62lYWfK10^;32g^}#0lvK^*KT6ko9|!pdU2W0@4qw^FZzg z?O}r13!`zlA2x1>tRJ)=7N!qI4@A zY?1YY<|kqLU^FiMYe0d=z`%eU{-E{@OdpH}?HmF%C6L=#Ag!?a-WodI0TKgYSa^Wg zAPhR+5@Z%Ey@JF*xBxmZApshUVqjnZ#UH5M1oIDU-yLZGD#(7QGLTj<{*7iYSP;~{ zfia*osDA)56J0+8)I*KX_6Jlsc<(Tb4WdDFA|U(O(A2^7gW5hIbuf(Xf6)Fpkbcmd z2uux#=78GY58@zUkXu1qkRA{X8an~8(d}OV)eq|@gVcgBy8WQGIyn5%+}{Chn1S*< zNFONtLG3b_{jl%{%?pC<2Ps0r3Q&(vMT-Y?`$7BZ!1g2Q1u-u`?VkW`jDze4?Jh>Q zA2go`wja&?2cQWTG=~5(4~Eh02hCH0?MKs}02(AlIzIqpKWNt#y8WQDkg(a$0By7* zb{s)mfNnqNTp(=rPk`DF3ulo1pj}z$_IrZ&*)lMo$G-y9e$bc(#AXPIZa=7Bg3bOF zQ2Rmg3(^U)ALJKw`@5j_GogjwM5z6+emuww5C(-6h=$?oQ2prXe+5)OD1X7!f@qli zFmvp|`*AV-{{X5Vwx0{67lhIMZv{Qq0JhH>qy~foK!f893=A`%7J>W^+IO3C3p3khvIi|GxkYf-*2Lz~&`E{s-+cL-&6s)P8jTe+Ly7p!ssJEeHbU zewfH&sD5<+i-9_O3=9mg{oOG2F#RwZG%p2WLyJ3@GKOzZ{m0-U5C&Q@W!MDsKSUZ% zI)DZb84!D#K>i2q>PPoKXx$6Qespv9fC?)H28KSki4X=zErbOjLGxjtemr{p69COP zF#8~?5&Ots;x}-(KLFI&f}ST0(hG7wXiqv!A1wWX_8o)VgdTqhQ2Sx)GC*d4FsQx< z(J-vZ0&x>FS^yY86E4g?n0j=6C<|!cJOcx{`U9Y6bD*c+3@rYK)%75^!2I6`wI4m7 zT0q?o(gRWt!=SJNv0-!{bA2ch#rX)ZW1VGDS&^R5a z|ADR_RK268eUJegK$(q!fnhiDU>2748>pDUrhfvcvCqK3a2Tz?1-TbwJ`4i@m30vK literal 0 HcmV?d00001 diff --git a/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/builder/buildTypes/buildMenuText.o b/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/builder/buildTypes/buildMenuText.o new file mode 100644 index 0000000000000000000000000000000000000000..e07d04f279eb98baf0fb103fca56d710de13b675 GIT binary patch literal 23032 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 literal 0 HcmV?d00001 diff --git a/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/builder/buildTypes/buildMisc.o b/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/builder/buildTypes/buildMisc.o new file mode 100644 index 0000000000000000000000000000000000000000..13215ddbfd432e39e9375b159d4eb16bd3a45c3b GIT binary patch literal 63064 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 M1(g5MDpqv;0Q3c4t^fc4 literal 0 HcmV?d00001 diff --git a/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/builder/buildTypes/buildObjectMap.o b/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/builder/buildTypes/buildObjectMap.o new file mode 100644 index 0000000000000000000000000000000000000000..e2aa38ca237bb5079d2a0939f6cff150a66ab648 GIT binary patch literal 72760 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 literal 0 HcmV?d00001 diff --git a/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/builder/buildTypes/buildParticle.o b/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/builder/buildTypes/buildParticle.o new file mode 100644 index 0000000000000000000000000000000000000000..bacab3bacd39c9e99b9e85ae88497aad58cca28d GIT binary patch literal 22568 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 JxfevkFaRMee>ngE literal 0 HcmV?d00001 diff --git a/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/builder/buildTypes/buildParticleBehavior.o b/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/builder/buildTypes/buildParticleBehavior.o new file mode 100644 index 0000000000000000000000000000000000000000..ade38f5c9c6690c25c4bf2a86c991c9e444dbb2b GIT binary patch literal 22632 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 literal 0 HcmV?d00001 diff --git a/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/builder/buildTypes/buildTexture.o b/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/builder/buildTypes/buildTexture.o new file mode 100644 index 0000000000000000000000000000000000000000..0cca735f59558c8478543b15f32e50faedba4f5c GIT binary patch literal 48336 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 literal 0 HcmV?d00001 diff --git a/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/builder/builder.o b/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/builder/builder.o new file mode 100644 index 0000000000000000000000000000000000000000..8c35dc648f48d6b4db879962ce236ce7a1e52ef7 GIT binary patch literal 102960 zcmb<-^>JfjWMpQ50!9Wq21Y0wncCon5On}cI56lj>N0{vQyCb*deRse7}BBa3;?t~hDIp6iGhKk8Om;9U|?v4vfCIK7}}xi z4h9B>PAI#Jfq|hL%I;xcVCaRi`xqD)`l0Lz3=9ktq3lTv3=ET@>?sTk3{#=(X$%Yu z)1mAc3=9l2q3l@<3=FfO>^Te!40ECEc?=8;^P%ho3=9klq3lHr3=E5*>?I5g3`?Qx zWef}q%c1NQ3=9k_q3l%*3=FHG?6nLG4C@#e7}hf|Fl>N|ZDe3z*aT&7W?*300%dPy zU|`q=W$$EQVA#dLz_1(2-^0MbuoueS$H2g_pMinl00RTVL8#av1_p-1Q1%f928N>y z3=GGh{1Xfe3?~^F7*0X?rx_R+&M+`AoQ3kwF)%Qkhq5m)Ffd$%vM(_(FkEI}V7LP1 zUt?fkxX!@9a0AM}$-uyH3(CIDz`$^afq~&Jlz)$bf#E)s{eXdi;UNP9!y_pFIRgX3 z3n=?Flzzj&!0;Bzeg~!BGcYiGfU-YA=}!y{44X zb1^b7a6{QVP@0#Kfq@Uo=7-V(j0_BdP__`17G`8%5P`Bqp|lty1A{n}Ediw^85tO) zploRx!<{O_*6&26sKm6q`9^KZS z&3_n6jrq5^GIX%}bgQU%bX)s$CUZC)V^L@D=yp-zNb%5y7*`tL(R@T8I@U4fFu%M5 zgKz7TlB=&}CU|t-_vn0PcnOp~7(6yzJ5Vrh*X^8zm|Z9=&^1 z9KakOl?bGWYEj8xWMD8n;L+Qn5&)L3QLzBUpM*ze3slDkk8U%M?f?!C#!oNU|NZ~( zvEx4k*n3#EsCY0kFz~koaxgG>bl0d@>;k0_k6u%FScBry!J~T%SfNMv6o{d{6$Ri( z@aTrR%eqEIqD0W68|sYS0!FC3u}60>hfnVk6;Rm#awaIB`*c1BIg-PpcZ~`tFM2S3 z0=XBY zR9}G2JMP(e>^MY^URH7bu@)6jahd0FyhUXP0|NsqsN8H(0TrL%6d&Nx>7!!c(b=N{ zGU3JDKmY&x^sZ3>8SB&e-3OW;K_LNhCMYC8&T{NL4vHI4CI?v#%7h-BH7W{V7l2Z8 ziwa2YMIYF>Eh+}!NP6ef`5mO20XbFMFqU$h3*Y(>$zg zR3L#3whs~5d%$k@u&z-tfXIVG2w5KF9gw^LL>?TV2>C6L*Z|q-(fJ1vTP0D5gCiZt4wD$?)lXha7s?BBmP@5uh>!lDxnX!3r|D z6MqCqvw|E)P6TX$xVZIO2^T0kL7m&Z2b_$k8}6O=d^+Fz^wy}ra$<-|giq&7pH6U? zXFvi9l2@=r&flMCkpqeY15j889B%>VEd7$o0+1&%jg33paZXXp3kM0l^g=3Inj{y{X8K7W-l+|; zJ-&krc#qC&KAn%iG9Il5_**hTg;TQy1Aj|ABLjm^=QCKw^=PgTVBl}DVFJZUiHd_y z=P!@WW}M<HO}|IR{+Vz6kyX zsu00W_v!owbuQRoQ0RkGn&o}|mO@a~j$Z%1j0TIwfJ`n?QSj)z577t>iOzed#!*=v zBu2nCA_!1B$D{M`OHfEsfeovpDKPIS4!yX1(Bm;PKvKt;isD`vRN7avp4evNNHT^OV& zfpqS0#0o?b5iy(|jYmNG(c=abNucsH)PvUM5BBsl>VHuBpk4YJ?D0SN+?SMCoS7V7 zTvC*omu_Vh?;D?-pI2N`RGM6(kXM?MqmY+hqEMEYlbHg_#0(4!8ZOyIj>W~PB~GQ8 zIVq_{R#s>NnhKtI1*IhlX_+~x3Yo=V0}>Uyg8lu#LW;=JwhBs6V~H`>IlnX~1#Dhg zW?qUyCc+ve65IuMi9$+#D#UpiiDjt@i3&<3l?ACvI2@=1@=J1QQBi7MNlqo$6`8pO zIjOm+c_pbSdJLf+ou529|9LdN0d*lzQn&?VOc7hX)}jKEL@hx<`Y}sTQ2FTr>c(6H zH*>-D9cawk=oV{!pocN9(r|PLJMN1#ngA(Ot{n(d#PUVR^iS z*Q4820MQX{KC0ni`MUJ9XSa@uN9)@XDbMZ_6@h3_?^g3&tYZw=$~18M7t~7xwR=JC zLD(0r1#y^BW1I z_yiB;`*iAqhw?!)Zy*am5%U%7VvkN170=Ei9?d`a%k4axe=wFBf=Bh81;FDr-NGK7 z&K$>Bn9xV{Z9STgNPryg7<<^G^+3tR*V5qee0U$Tli9QLDA)}6kiHMJee`+>#A>7t z;)GCWSJb2PDQFnn2Qmf?@)dae!ZF0BR~3}^f;}4F>|kMFK=PsM3Bv;r1G~YK1U{Xw zP=>G}MnTPgaT(kt#-%f)fEw`&WlKON<^yr^#?Sh35!_V{=Gz`x>ZD~ zYr<5wb;IxfkdZG$((&nh{vsS%=`)|sS3bQ<9big#F@Z`NNCE^Y2Bmh7-n|*W|Nlpp z0!On)Z|ef^=$0s0RcGr2Fb_%<{RGXXbwYX^pd)4Bu9YlTonKRh~* z`}A(T0TRS*!UvEvY!s>W0hkA+ioSzQ*vkO&E8GM~Xut~x*cciE!+y}DHPVn75)fNXDmt%1-29Z&PI zd|V2OO=!-8l{64-P}f32ySL(lM{m(r==dVogV5Xyizd(Bx(5((cqxW#9=Pm@ZSd(W zJpi@s1=BCk03p~K$S~*L21rm;fG9|Mf{y~V7J$M>6C7GEPJl+@A>%_(od-Z#I-zL+ zGDr-O_vmZ|rD=XmaJqZZhpH1a>(JTy1Ed+G*951H7ZIqsJbL#!fP%EM)dEDJ z>ooZD|3ANGtHPiE|6j;q=xhLK>1?e4QRq4gAUYF3I-mSN51j)bEuF19Koq*p4G^6R zKsr}p=wtwuM4hcau<85&(fI(Rvj9V<14O3m~wE{$; z>nwoiOaSTp^Bu#VAT6D(J3th=&J7Tq3qU##Vd!K4)i9l{Kd|Zi0MYpXq_YDkJ^<-lfT7a?qSFFIq1$QjAL7sd|Np;8L(>T=kXkFS z=_-KeN&x9H0O@Le!vV^ah9{wU*QdAF?)U%yKAoSyGc&F`;Nq?Jpp4h)y1}Ej)fU8r zw5tO6HC-2gi;{?_vsk|Nm#? zk!NLK&|x)W@BpVMaR0`m+g$+E78dqse#5Z~wDixT^WXmq9?eHM4j=yiA2j6zatauO zOoqlFcm)o~G4&oEz0MKPK8SM!ybl6Z=h0hj;nB$)jR;Ce*$na!*fSvgt}y+sSoGIg zcyzi#Cu=+3?*pwRgv2If{MVz~9MlEl0b9T?4_fyFUTX$&Fvz{2{?iwTZQp~TAr>kC zPLA(AIzt&edqr4$dQ&0wDJ-mDgQLjd`C15MoJZ$jpU&r=op&HcVTQ4Q4l4tL39B1} z4XZyx4l4tLbhM$hv2iX#xMPr?r=Po(0)uq40ch1D#QmU-gJY;?=UD>ZZP|}+Nn$i63(V3$n0CtHFq|powb;EC<8C}pYkl_K3ZeCDW zq;&Effl&X^sX@EoiJ)NV&;*u{cr2WY`W04S_|x|gtk#z4SkxHB;@I5yO% zfM(HGGBPkY^6x8AafaFC(Rmzfx<_w}ior1#6$1uP%STjJ7+7XL*3X-3~Mj-tD7OVR#9YKHqz4o`4wK9ipNET85wiEwrJc zpp`I|_e=OdjyAw3SGxCrSA2lNnTUjfSP2AAlN-&_z2nr@}j)B?($=2{njK3AM$jhVg2q^c1 ziXKSabr?S0m?m4^$PP1|6iIvIQFWkd*q; z64c@VC3~>PAm!xI*Xj_);n$&{P=S_1(7-`1KcF!H3h7SB;y17{umlJ*MI6LsBs?2h6ND zxEQ`L?_^xY#n8ycx}J++IveW)PKLuAIm@^h4s(J;E^)Fh<6>CIWezd}T7HLkc0$Gn z!Q*qj;P8Qt&$(KFYF0jv-dYW$nico3T>vQVphbj7>+RC*NW*q0Lw3=zpb#6C z6975KF$TT52G{T4in{r*0VGJft1ozT7vJ!(yk8;&8r6f;%dqtw(a>=@kZ~Xk3P+!A zc8~6I4v*&J2A-BbN_arJe4x!CH05CXLOr_kIY8r^P9EJP`ro7T{XS3-K&p3sd4^c9 zkH8hEVJ?GfP>_F+l>*3NPz-V(r2cda0afwf7EtS&A>}-Loo`lw}$6HiBz@(42sQiGkeHfpEjAsCi)qqnNv<8M2PSCY; zV4Hi_fa^Vw3qa2FXg;6;VuM@*bt;Gpsv1FcFL)LTG$Ut=%Dfz>?qIxHON-5Zpg}5kWy$< zvA0CU7rZjqr}OzS7ZqP6uriPC7?l8@?i`f}PsY1Gmaj`$K4$o{wkGd zdi0j4_`$R~bmXY`L9{j>X7seYTcX9kP1~X2Z%pY$sG4sO8~kIy%3dEpwC6!4`9M{H z9N`0V1f-Pn=$)eiu0oHys6ZMgy*VlcpbE9%SPNJNQlEkv;Xd7vAO%;c>tR*uGH}}H zQ32H(SZdV@P_0_v(QN}6)d!V=1)!`CUi1vM8D0@W(*kVeEG%K+iGS-F6%ELOKTxP6 z>gVnn6$yA;LShjdFz{Lv+#H3*F*uQd+kQPPU^dhpoh{&Hy-)T{!nn+B)& z?k$kq2I;DT-3F_H_k$W+U=hPh(Bk4aDAO>&T2G*=JLn&%D-5YJJ-b~Qpo{xZtL(i0 z|NnzUd^+Dl>g^bC*Lw?ifikSldnpU6aY1FEN9SR9@8q>HMC9meKbT_FkOyU8a8P3g zJ2X;24hQ=Mlwd48I`6_c&|(r=MZqlMgfI@jmV^bz>q{V^*RMe&$Z;Gnr@$2~`Tw8M z+nbevA>Ml$7sE~_)?O}#X)LTQTnuYjx)>L7gDT(I+zhMOSUb2GIyqveaWVYmVExa< zu#D4Y8W+P?PS)An4F5S(LF`>G1)yfg{edTSmpR z^PETLU(e33o}Je{y1hMKtAOk4Zevg%GQgwT&%^MNXXhP{&J!NrOF29(ua;VSbbj`+ z{8)P1vpbx_!#Y@?^de}NiGW9UF^6ZjJveAu50vf!b(noRA0Ri|Cb$|tc@5f61S;b| z7!(}fy%MnAeDfO)kLG`j{4Jo}Pad5gJUg#=9DHHJ-wN8@DY1$;U=Jen;TN_f0Gd5(B?UU=QXFV6s?8^G&Y(+xb1yBmP~?A!V1 zWf*9jNZx_L~MBU;-2#@C*WK!*;qtHcmh!j)E1zk`8Du)NDycLCfom6POs6 zFtM&=V%WjN3fTz-vI*KA3-#>$3hGOr@##Dm>d|=>(f~TH;L-d>!lOIJ4-Nv z`XxwPhT=ezi|`Zx-Z$jYc@4Z}2)bUm^M&ChkMG4Co}E`;&w->nX919*KAp(|;5K~g z0Zz)Pmll9hr-cNvFAw>64KC7@G|;3d_d z5u)#<96p^7JwdL#<p26fER{|fHzw4w}Q6*fEI^A5`|;j zVMKkmAJlsD=+uE#H{iVz9>>A%1x>8>R&aRqI)D}ndv>~VfUN@!7dnE+8GJw+0Um*t z3wOTvJnjmb!e;P1?h4*t>eHE{!r{m-2u&U@Q$Qn*AY(xx;L&;fHM9si`dS=pD!3U5 z%Qs*Vk4{J*8J3zL8qreN|Jj<1iZdBm85s64vNka>er9CtW@1>z#JZb_VH+r^odOY% zRu$@+j>Lk3)Vvf1eFi0lkc?F5vI)>q2L&Yt7w;ei@M?}?g^>LG9EPCOvdrSl{5%B{ zhLr50_{8Gk)RN-(lKlLf_~O)(lFYpHV$kNFJciQZctbq{hNQ&e)S~>{VtodPQhkQh zijtzli}thnFF_uA;{Iy#n)9YH-#ZRF*h|nEkCcMSf9ZuGcU2IlEDqc zWAI5WOU?05%1TWx2`NgFC@C#UMONdRSODSr=BK3QK$sq> zi7BZ?3=l(5I1oh;3CFz5T(H>;AtCM=`Nbs+?uognAS)PrQ}aq8jLhQX)SR5eywv>C zVus*?qRf(12FKEr%zTD`#G;bSD?q!mh;|aRe*vwM z2|MZaDTMQ0YWxSaNKkVINE+g1m|+MJm``8og4-k{gdD_~FcabCJOxc-fc89r1L^fu zxWpN#1gcA5(lB#8o8LKj_SQiH8y020md{F`!QuiYh&;4}Fa;L!(73Ul3!1j&Zvkx` z^5}-l;dU1&c=T3)m-#?yF1Un+NAm&j3Kwa(kOO$Vk4GnXRu=3fk7lqj8m|{YN*u`i zwrA&k59okxH)O_A^B<^khT1@Q+7{wqunlk@!X|d1B^_>Yh-O3xLE;}&zy4=D!I;9z zz%YrC^@lLS21eE%VTN{4nKzq>^@|WgA2aI)A%=y_jtxQ#ADCH>2r>L&X6+GTxX8-N zz;KV1wMB%XhmCcK5W_My)-Qq#yVwk02r+zQW4$B9@RyBsh7iLp4ps(+^Bk-V!VK>? zSlkC1Kn}Q&BKNe)2Aj0tfKO?K(dvKrk|7=S} zy)2_v7KYhOtSeakIGgm7M!wnYJUn~q?S&$nQ|7Yhi zCfUzoV_>+$#=294;RzdSrwGF|c2)+4dF-qUMHrT`vwjq2xB(J)z|Oi>gy97{>tA7p z$sDXxMHt?2us#)L{KLU|Q<(7!Co2O(GZ*VwVTK+q)`P+fJGrj2Gca5iV%;hXYI1|> zGX{qLvt=1YWEB}0eu3(t|BS3_7#XHBnIboHAPQ01yFR`729PljkKTF(@Hj~4IgjQy z9v+}^5R_Jch2a68&in@+$KAn02_DDYK|Lb|kK^v3ZRrfh*&(}x+&MtjcpP^Jw=Kab z4b)_?cI7Cu0WG=WZ%G7oKEbWk6h;OHzh0B4ARVw|=hOKK+FFHFvOb-;3_hKy9FF_J zJG`u8R5(giUV?VGBiauh%@zzL4j#>i9Xu>!R52dGV??%C_B0h(-stZV7? zQIYWIJpccKN4K+uXQ!(J$N3}})@0n~zlv~3aIYgGi5qTMbk7Vsh9QXP-x zBOb7(m1F#2kK?Z3X7tNF|Nj5?JopBs{S5XFs9f>vJn}jO#>fFNK#d|b2;=Z;HW1_W zEl@d*G#(1p4J!pOTTD=CNOu)h;KGVdkbxjeZ+Z0As6dL}*PzoFKq&w>_A@j{0yRNW zi+mFcoJ^A|Dhv&MLvw-*&0U}iUW& zx#km_fyp(W*bGdr`9x=6SZ(9(>};i=5t>w*S5m5AXsBnRXP|3X3g#Nt85!vrm}o+U z!8$;L!=PpqXq?jBFBCKpa{wg943=eJ5P{N+RY44l6#|UXJnS437#SEqdSsw-pj8AQ zCP)n2B4A)(052|QfT(i;Nur5GU=ahIxdjqN)(e^nKo-$4LnbNrUIDEMs`8XIrW5S^2bs#Cw8FQfU>Sc1{ljvb~tgO{xU|>)IDPUk=@MU0N z06QP-Usrg1By+(c!jT)a_#yxGd!|K9k(8lJ-XVJ{=#W#V4`5!YEpM@izfg_)W6Q6<; zp9CZ{y||%n2!WP;py@<3H$c)yJ~+HWKpp{w{|l%;j6nVX$88)uZbAO!fL3y#@B}FV zl~v%m0R{$!AXpfK%QPluEc*FrK&tGJ_{F&&~WBvuwh_eNPw1ewv34I?FEG|G;O+o(k3WFFF{M2 zPTb&h%>qgY(6b0ZZs}!m1*L0uP`U=|_2zS6O620xa6wAfuG|cudLLHC`Xkxh$K=i@ z(F=;(9#Fn$1I2AKn>$|sQxX^04~|GN>dnmnN+T-JvPgyt;Rifn;>EXtnOTY*YZ`F@ zr4dm4RY1+$3v(Oa2Igk=HntwtUY0)QekPE;bD(PanXudI29G}vK5*J>U}WCPh}B+D zwG1wQK0wWMh4}?sPI~dOx%4ylv3T~fdiJpSH?uRVbLt5&g>dn(bGUMY+^Ydj$P5fV zF!%DX2{f~}G4-(Zvi7m`GlSCU2GH_N1_lNw1xl(|F(_HGFnok9=SES(%#et}hjEx0 zV7q`}A`qIH0d%q|gpEuxGo&GN;cR9G@CsNsAI4y2$bvCZXl4dj%MeAFftdkxGApVW zh{wzTURVoaqF`nQ(21=mLSPOv1L*WtFcXDfW&oY!iXsH&Ff)Lc#DLkz1TzEZgjZw{ z2%DJ!blNL~jZ88#fKGlz7J;yt8DOnm2p>i=Gk{Knh4BzHGXrSi6TyeEm>EDP#lm<9 znwbH%v=|`AQmcSW&oXBiz)`gn3(}|qAjWzh{wzTnw0^uP%$$D=%iazF%XZL0oGdq@er7q0dxW`f)8SWRwOYY zWd@*Wim6sdU{X+D8&pu`4`GTqL>*#Cjlb~K$*EE)B7<0{n3(~z&JtA&#A61Zm<(c}VrB+dPaj?U8L9y2Ol@%bM5qU~ z5nzg#8IV^_K}13AJWzUu-Fh<1jG zH$c_H#KWNC3(&;VpyIGL9!z~bRNMhg{S2r$Xzek`KA8G#P;uCJ08IQcR2;U)1}6Ri zDh}GWgKQ2bGsM3QP>;gYD?!CUiwBU^+e5`cJ3f%bW1!-&@fDakWl(Wgp8+O55h@N# z5is#JP;pqiz{HP1#bG5qO#B&C9M*yW^?yL_0(H6=8B!R){UZhj2Jn^=1_lNR7En3% zgaMX5Ky5RS`be<&b_M}%5D(EFs{^;;)<6W2$Y!wkV+K(qF%Yu@EWU<80~($nF%a$p zi$7+7^}9e~AUp*sE)L=#;hA9ZH5et(e5g36500dqVF^?my```UEdCf-DVV(;Dy{|Q zA&9L|ad4j*A7r_g^GjDtOxO77<4Ev$Q;m_^)N9Itq4_* zUUI8L#X)D$gVe#WE>s+J4n0f^L>oiJVdJPEF%Y(dilcWt?4jbIv*JPOVAvHZu85ZY zLF;ot?$<;U4}_`*ovQ;g14M^I#huaA$3n$H{Zo)S7*2+Y!^UV~;+ar!&_UraF%X>( z6$hQ93gW|XDO4O*9>T<{q2irr?rDUIPeK!Khl<0>TbMbJMd^fkhe6ToVJtWL*5WNH{4jlpj34!rSsJIZAhalF0#jhd+psdYMaddNbfW_6Isu0wB zu(&!x0Lo$pkJG?PU#K7h1A`h^ToWMxW%+`|(Mu%;hIFvFHdGaYS^^dajbb6hK&+o& zaq!tWATAu6fX8XjOHT%dM__UAXcAm4h@lDYn1e1W=`i)Zd?59R(gCLa3?ImRSnZ3L zM~deMsR!Le0X7~yjtOGT;|Hln^y^{f8w!BbgVykXR3Y47AOKR2s4ZaXnFT@W8R5AC z<{l?Okb1;808IT=uzJw#7O3Wn2!Yfi#s^^PmkWW+2i<&us{R>RJ!0GdroK`bq#krD z2CDiU!XWbzwHi#lj|fOT=*A3G^*tgW^@wo>n0f_Kkb2M=?x^Y$L_z8i;}0!164hTI7mHWyaJ|vjyOm?=!Ond^>@JP5#tyz^#u|j z^`P53P}Ogc0GW?ywZPQ7NP^UZZuUS`-y#W8j~Mp=&%J<@NFmY;hzrBUIK(}0h(}6+ z%twr$z|6mfLp_Hyc6(){LFORFTVUqQ#G(Eq4)NPya}eV*Fmobgu-n^%Lwu18$UTVG z63iTVS?uP7;SkT41(|~w{{hdBF)%Q^!J%G74!ikwav*aM<3%uYcH>b01&27lJjfix z_!7)tJ@VM?J%U609@rejcofW>Xa(%%OvfRo~-vwXoYe6^D8)Es%dP-4h5FM~tJw<~g%* zh_`AnFbFXuGQj#Z;O0651H(KV;@iRIAjVx`<0xNnxZgk0wuIfzR~d)6ArA2>9O5lF#HZsB z-+@E?3l4EB1MKb(!XZ8hhxi-=Q2Zjs?O`pgn}#59#P~d{XV`9pUEI_dB#s!jhvmm+ z6OcG!+#a;{0F+KnnPL|gGzWL=k4e}+Tc#sPFMDCqV?kg16JF3thF`3+$8h*3XS{kRw`4!VsIVh;FFEl~Rt zhdFGH*v)svA>M>T{1gsx(7H82q;(OnksVnl?Dp#85O)TNL+5HBK7)_}AaMv2g^a}^ zUWh}yABXq`C+zY5&k2-%5c6E1^)Da?V@5~tJlUM?ubJ?5{LL?H&DMG zbQ>zjbRSBZvl&gZcRlM z{|puf-JFUlZsY+nA9Q;vs(2w-95$Q9zyPy%16Uk%iz=%6_h50*O{%EkdY&NjLAR-* zisypGVJnvz!0W+4D%OI3PtI`-Hi!>4ibpbxa;JMk-EKjQ+ex?1*~l~4INsGYz&km} zJJ>j04}9lCK~a7IBs2_7VSC=d8{JZioQ+(uZiMsp3obDrX3UCbZ0Ld8|yLbmVhQx=t z1_gWi`+@yAB82W zGwAs^8-NIN5MgKxCQU%31&A;-0+E&=!q5;znt=#I2no>wQ3qCH1UAVCtk4Lo(+F&! z5!gT@Q;=RGuwEmuUL&wxBd}g$uwG-ZUSqIcW3XOhuwG-ZUSqIcW3XOhuwG-ZUK6lh z6R=(ruwE0eUK6lh6R=(ruwE0eUK6lh6R=)WuwGNJUQ@7MQ?OoBuwGNJUa%xs4lD(c z0TrIXC1z!*$tC$kp7@J{M9*NOcvn{!Q`a((HbVoi;`}_1)SQCUBA6JS;)Dn#&Ze$G z-ob|PAk%|O3{B$QO7oIIr+&nP&M83{04t^pO_6Jsq|!9pl?y_%p+RY0W?^Y+d_f6* z51YpOWEPj0#(U-#csl=$4l0#F>l{YPZY=^9*Okp>MaPq#9xMLp7< zXV>5olZ?dT49{TGc#ziA!qUW?_>z1GKhZO|#H1iGv&hps*fc)aIo=i3qwyYz#Tg}_ zV_3*^Dw5%(IUCeY2zHBi^$RYsh>uT6ElJGGF*Jw|PR&V8E-@@F!SoA~KmCF|;teh0 zee+Y|ixTtFQ{zD)keQe63X(7~h<8a%ODxSPfk>u+WnoeQMVYy&@kOa19q|SEIho0o zU@1d$L|DKYGd@X%u0BZyt{~bK+@=Xm&M!z!iORhzJWD!RT!28Q=|y zde@Nn;PCj|An#z`_#p3KZxG=gA6#N+o|#vYnqHKc1G)byF|Wik2^w$aBK$+HjD?g%;H^L4GrRb<8u@9 z64O(QT!Vs3EaM&XD&tcUOA>>;!EIVlVuVP?=NEt)wVC;O4DnGRo;Zvql&j-m<%v1< z{bMi?9s=#W26rS3Y2YJJc}({x0`2vtnU6qKGu?dz+FedFAA!0!boUWxKReBQWHJ!> z2(*KqW^3w6Pd7kL@pU%DKIMQI zhr-a}Vh9>oj4v)pOwNu^&d82WOU%pxsiI9M9n`5M##aVlUx5!LCel+#Iv{=mO^4B{ z7fXZ}AYty~9}+^G2N3FM>wHknLxl4UjleMgI*7TnD3v%bpz5KmH$Vk5G2So*djou~ zHTe8#B7K6cjkcZvmB_?+#th*Z$jRD7`UXQEZM_33jEV7%IoLap1Hno152i-idI;2+ zBgR9JaE5q@l+=cykG9?c_2h`~juE6tg?I;kU^{V14!d63dJEK@Bf?v-QVMeJJaOJZ z)k9lvfO=Cz)%?cb>;pSDpGc3OYND}EKs`5NVg%wS*unoK`2?nk#y%mk)`V2zzL~|z z#CZatp2qG6_05Qh2}o-aa@PWJUVt`0AzEnc3t}sMNWlfZDuPH)AnBm7ABe5%A$bCJ z(FKv-K-ENJpAcEi8$r?(%qOs$I*9WT4$TOkkveS;$^^+psfi`2u0grE47sVf$pw`R z@lnAghL-X1B^gEe6yv#sYONkMFHO68B0SGa9Inf3Vjm`h;ux;E`+OT(Jvt~ zi<7$W#0bC@i^E8q#H5_i)$esIIfCIigHpx6U3k;Be+z8*7<=K(71%_ z6{V)>#mA>tRKypg78U2`CFW$7RK}NqmrLSt4F32xV z1w~nCUU_C-N_^7NU>jViCIp5a$-&@I5mJ13_Mzhx0f=_2B63U zk7ZDC4HYCH!Ks>h3$x%+i*t3Wvk}3CS-5f;Jd1#r!Qn~Eh9>d8@x=u>nI-YbxdkP~ zh~UGqTNJt2>u@=ZH?TSl^QWJA=FSY|ESWxP=glNjlFUF=8q{=V2gn%Lw(6V9I0PI-> zGBJXh2}yP-B5OHAl1*@lp;>%k9GE8Oq$U=*2A3Eb#e3!#gK$Y=3A7|9 z)eE3jPhxR#W_liIAlU?z`XB)gY49W^ro<;F7MDQt7Tk1_q7`1urN9CKluHrI%tn{o zA;JR3k~?UeL!-fPC@fNilv|*hWGJ{6Qr3W6Yk-K1(S(Tz3mgg4$S~eFJ|#6V2hyKm%4)Y zSRgmd$g2Y3ZJC^6Ps|;6pcTpJO_$`5c-LUlc*rmVYU>Z$J^(dxKv&2T)%-(lJ(8{; z)X9f?ocR8YadAlzs8JK2T#*D11ylLM2Jv`9%Bxoi8XA;j~w|MZz7FSTbf{ID_UMM4jcr06$z=IHZsi`T@9ZasdxnP}0 zo2V?~eG?17eSZq$$}FD5ooL`KUGAVQUGcbga+!g4sX=$FnL*TI-^dk@a~~H-220qu z`US@m-o*tD?#v3;pkNDVZ`BYSqwz_VC8@;$-er&g#TZ}&jmBcTew5&@YqUy<$gu%X z-iO>3584zDkHrvz3Qz|2Ez(m<;z1*IpdE)e1JX4hzyh=p)-5v!;!Xn)3lchpAUDLP zWEO$9*H%J;2)9X~;Dt=Xg6^huHgrXp3=Uk}I)lwXq38#9h;c?@F~l~KBLw6KxH*Of zpfG?W3o^}vM6e&iUyxQ4xP_Kp3OdsvF}bibvnZ7zK0c*5KOV9N4_d7xmZVl>mOwcW z)kUc}sfop)paz`_0jty?)fnYON>VLo3lv5ADNK0KO*Z8FpTeXE-8@3R{h-7Lx}OMg zd=}_h8qkG141fMZ0PI9%(6u6<)9hj5o1p4JN6dk46M%`sZsr21XJTZ4n*%!u79@V2 z0U_=QJs}??4m!0AW=;~4II_J(P;qp7%c0^RbCB(=K@vx{R}N$V1L&?D28MJb_b5Zf zLFPmtx!(~`o9~Pyj;uZ(NgUZf*v3Y5=S-%a^DRk-jTzT4@o_8cp4yy zBm37MNgUa~X-MM8>f4aSk=4&e5=U0Q8%Z2l{b?j|(A`(C_c07l6W#wIIKq!M^=9xhxlu#ILN;#NalQiii6w}h9v$UDh^W*k_Wk*3wqEf zi0_4@UIR%y6iGZ0NgUaonMmTPNa`Dq#F4{i0g^bfIhUd0Aa^3?yW3E4kUP_m%zp(H z2dM|;JJ?M&Uy;Pqk<|Y|5(lXVg#ie2gYT(<nmE)M3`S_;uzOf+(8OW)vbm#)!|rhlLKBDG7!->p4!YwPpRCNgUaHf2cUR`H@KCxk&DhgNmb@p9&QRnFG3A2>sRlf&K+#D)?0ZklsLj4^y zaoGKAFVMvOq2_!+6NjIK3%#ch=3m&oIXr0MuoG-0(8NJ$4rGN2nmFu6A_FvW*iAe( zXyRtj_MZouct6N+1_p)@G;v?3`UEubI;eOKnmDM<0WzurO}q=L9&~>eNFEjruzLt6 zpsAk@RX+z!d?i$T1)4bQo;qoe;m~%`N~Cm!EWR3tIOw)tSUN{m54vRon>gr}4Q%3| z+b*z)gKoRPCJyQ&U=s)3B7seOHxBpj#UT#5`xl!z2XUxBj6?h=4sp<}cG%1Z-Ia(< z9CUg=OdM99fXb7zNan-p6Oi~hByneG{DQ=h%Nb;IE+VN%Hs=zOI5Fm2K~j%w&Q&CF zV$8XYq#oIv8%W~Bm~#tBJ+e8V)AeEDiOU?=4S=9XE}4 z*&NX6_b~Oy=77%5hl%4d2RXh#x1GY&Bl`<M|HV88ZIlew4nL~`f zK(`RW%t7|oHzae2@fYZJLTu*zB+(qut%cak`9q>PpxX?wnFG2@6()|$U&!GAI#nK~ z9(HpjC?A1tGlYo;BIP^e`~|Jnz}HrTZqP@4@T1+o`e9M+#e z7k30H#xlN=%ZK?FcB3E2eB^O3*v(%capZ9@ zP#q1j8YGS!p4&iz(DnfGxE!bs1xbO_Bae^4ZVm#qPe4OKdq4~Z1_n^w0a6d*g2ewo z+aaK`7bcF}?*o-xFmaIj8jwbi08}5y-U6iX1ceny8WiWCF+Er~2tw6^w1donxd+td z2dM{{gWR8zMN*%Sl>T8iVZqFq17a{RFc?79gX}Fva*q{M9Hb0nFHF5XR2ashfq|hPsvh0^nNV?%GSF?OF!Pr}#nH{*1QiFV2bnJeVlXf;Y=?@Yn|}~0 z4pLT(6fb9?;^^kzf{KIGgKkrWx#vDq9NqknP;qo~{z1h-=78LJ2g+v#2|)8Za{A$g zii4<9BzH=J1Q-|?(9Ktaii0SS`Fo(|Yl8%^m~RRd2T`C~Ut#`&jVGgTOkN_6* z=Rw6m6v%wgm>?*9F9r!OoA{yiPWVgT?$(s5nSH=+Bty9j;ZO!h9E4%!$3w+I6tem0 zAOS4qmqNusW;8P}FhHjj7-k}ggXCc5FNBJNC}i_jf&{RbzX2)^G6NJgps`L+R31PR z2i2({aoGG0Og*R!0*PONss~Y^F&kL8y#Wb8!x>~gXlxOr{ui1!C@+D;b)g;vnGeD+ zb8MmFAZ^I=ATdyJkXn%Wpt=fVP61RLq#kse7|fgsByrGf*D&#Rs5s0Vm^=HB#6h<& z!PHNNii6BYuD@nM#bM_7fE>fXz_1WW9CSN2bb5ke1Clt%{WehbTam;;X2IeYcE2A; z45U5=s{RO6J;*)C@qQLb968-yhl<0@f!TWxNt_QUoj-<(gUmVEO zITuMBbXy-x{U#)F&~5TC@tsKGpj&!j;&+k6L31N8@vlhYr;zN0&BuY_9eJKw0y-}P zDnIj)^1CXMxHyuyE|NHMJrxEOM>iifj|LJ4wZUQTEQG2D*^4|bk%J_TT%OlL#X;tP z=EZhG+w+}h;(4tabJdHhNrDi3lCXzT^19#)@&+ylCe5#~->o9_j6 z56E6*ck&{MgT|U*?h!%~M;?EJg(t{gAPg!)K}tB0=XYKUfe-~PoraUDhm2ADg|q4^jjj-1|lpyD8Nb&=dZ87dA^kDQ(#Ld8Mqk^TD? zDh^UV9jRRX3Ka*b*F!R&5u^~>znFofo)apLu3idB967ydAc-TJZ;nIU8%Z45oJb^b zWOGuX;vi}!k~?!j0?>4YtbQSqxIU79S0agn#!g}RhzZmgfSO~7q+S>*4$@|XBrX9J zM-LwZByr^YYYr6$nS-1j5|G4^@1WG^VcfXoA> z+XZOiuynf$O&pdlcA<&G^3g#waacNkf+UWde}6&6LGCa{3Qrf105tqfki`9=;vn}g zM~e4Os5po+MN+>SBmgxBS^Nl+IA{$8EZ)x{iG#`znD}KRaZsLxiGP5KgWLlOPndtX zkos}R{*{7?gR~+0R|!cRxtw%D5=SmqeUQX0ko+5hB#vxODv~&8EeXv1g-~&r`$6sk zrH3-8IEZhFWIm|w2FZiOk<(!WNDvy%$l{cKJ6UZD8hSkfUz6ne{a{UNevjGwZsYOm#pt)(7xHBVUJuHY13Ud$* zQV$Y`)tjI&2Z@8+iCkZR!UQA^QtyIPPl4vPVB*N-%t@qr1i7BN02K$BgItb@g9M=I z1le9aByr?&8#c}lawoF*1RUx&;}AzKpOMRRZKU!C*?c!7apd%aJf4gaK2Y@_>yiCC z0V)o1Ke9PnZ##X%IZdM}Uw)EwmcHwZ}_x&BQ;5_d()ca>0a zkiE$DZyi(|L?Opx8%O|ZFLL=g0ZH5q$$aE-V0R?(i;Rza>0*Qmn2}W`cXzdM59N9ghIKmComxQTDju+6{ZdWNkp z1&Jf8hph_+i6g6rjWdA6k=4W2FN4I9)!Ty{35`c&^~n8bWcA4FzL5PDiDVA4df2*M zbbDdzltJRi`!bN*b;#}k&9Q>40I5edA2gQ%6GwIrXzUs$j;tOw{|Pb&*?d@g2_%lJ z9yAvKGY45cXzUs$j;tOu){0FWH1>#19JXEvWG}M$pf#M>)Pu&@VdBXCg|*W_<{-NV zd7J@R95j~!GY455woV*m4zl^6F;8sjL3IaA99cc6&jJ%iHXpgXLKa8PN66s-Dl4#= z16wZyawoES*t&9%II{VmJtNr6fvpz;sYf=a5~(~vHm3uJ_#_|$mS!j!$A(8)kx}*!(j)KIC40^#>+wGBiB2yac+<}viWC`%t1CE zHjWNbk8D0{{2L^WY|c|0=D^13LF$psfsL<&#F5Q`t=j>KBfEzc6o}AxL^cPxoX1(h)Al!$obSBS1dY!3v=SKJ~D*vQVX9 z3ZHt|9xt#$D1lFXJxCI&4n~25aJjz$BneXpr9nct)Hi}8q3U21NC=nuCXggdA(RFQ z;ZolWl7y;*Q6M2)>RUjPFojSWB!o+SD@YQm4n~25aH($tNx~FDX^;@CPXrP|o(~1( zVUQRI!`AtOvN5!a3=(F5?H2%vLzlXM#bN81K;p1DN{|F>-5E$6mX|@|pfyw=8YB+u z`+)ec@*gA)o!SKnGl16cfEXZg=(obt^EMeAaOnr z1BzkmMnU5IP%#iC017Z@djM7@fy6;`mmnIXUJ%59V$c``hzSyh&5eTipuRJR28qM^ zbRa(H%mEM$5{HfDgZQwr4kRuL5`bb@I};=h+baQ*f~{)?iHm~-p!fii`(b;sK~hhU z#3exjP|N``0P0^Us2GUSK@x}cJwf6DNaCu(<$`)D$Ff zSf3gsz5_`dwl@kSeg{ch9V7t5&`bq#CkVrYO_0PjVS)?{3=v4;+DPI#Na7%KVCjAV zk~nP69i;6Bk~nPd4@g`9nwddnz{UhX;;?f$K;oc!86*b6$G=!patq_)#QtU~2rV@jXc5u(b^!@uNuMb|3*L zeuE?q8+!ps@jwexkiTGKbRcmBByrdp6_B_llDHE{0E%6Z#9@2TKvKR);;=IzK;kt> z;;tY8C_aHC?gkYDQ5TWKVPixfaSmvq4{|@O?f{9qAc@1~&OqY6NaCd6C3H>Op&MLE;fe z;-LHj%a4gj;vn^)HZe&31SD~gd-g)zKNCqDq#o8L*n%VuG9TVf)+?^eElEsb&?_z} zg3uW-R#9qBqFzaAMG1pmN@7VOgI-c`F#}jYFCKiYnrSlVXgkkjSBsSV`0~t@)I8T@ z20geokSfq&vGH!DdC8#j)S-uU7J0gr1z|hs7IEmOD~^NsAh(CR#=E+LueQle%u7s9 zEdm`+ZyE2HR~Zj-XOMTWd3p)kG4qn%RE)N~Nt^-{NI(S_Ny2N|%x(;+F_uzFM=xXi3>pIZ!nuEA1 z1D)PEn4LGcs|(QCqk}p026u%4IyrSPhu+|>GU8obL02|p=9T4Vr-E)yEI~AoA&qFd zwS@DtsDfKggCazTD^~MCqjsS2M?*aev{s3?p+Qnh7_)g?Liloc?TQDGw7u!C&xo>&5SQeOv*`xj{FkV2pV06DmFn36DK7W zr$StZ!(gmx(Z-!⪙ZiI#7t6R4~WDwG2xzLa*v8C@I1l+oth8nZ+fh@t(N_Ij(-e z#_@*6V0L^;YEEiNYLTleR(Ik|J*E$D`fPW>TJ5l;`Oc;GK+o%PY}WzJY2Q$PKrULc$O&Y*DUyqncgVgN9aip(Q%# z6^`J{1WGLM#7uOcm6#MHW)^vR2b+?0$)X$R;=~g8jaj&FTQo(wZP65@$s-;#^OBzu zUzC`ao*JK#Se%iWm+lI>m=foGiypWyT=XE~#zj~7?ejQGBJd52qrn+WVsN4-OXJeK z{Gyc9qSTc5+{6MhQ>F#%ZapIA0bPSjpjUZ<6PiV8VQFGcd`Z4%Fo>V%8H}9Ho#S0` z7LKC{ATzlVoC^uxVCo9KU^XQcej|2LX>xWd_})y^#s{c%F&eNW1gxP^d~kApL23&4 za$ZP1j-!n;dXqINH(6r~SRAbp)6}A({32L$1ZT6!72M(`y4^vBsYJ9e$TAhB&>p>P zK7+(NEDb?jI9!*_kCuN}Zw)85VgUs$@`dxG?X?VW&|$xe9V|seb&V0KC?&vXB~4-h z0B-$c<`t(FmBd5)?0NYqsjj)X0ia$Cv~LEk!99cB;=%X5yXK;GN`n!dC(C%>#DaLx zpaz)@W>{CwjI6GlJE&I{kGltFhSY;IgQ&HL_r=nI19j3|QqvMkb4nncyA*Km&ebm% zBok1SnVT99$=rwlC!+TT4!_I_*PvhvoI^?Qj_7Du7H5FFvGFBEiJ2wEo}ke4NiuK+ z(XJ2@9+uDsP;p6-p&rVhNoihAW_D^$C1wi*BNanaJJ?PNlkZ3viJ;_`a!A`EGcU6w zKC!4Mv64X#8iDaqWZxef?+T4k@EChhYK~q}zFvG(h$oH(wuDC3!REn6`N(z^=q_uB zZ>i)gh=CNl3v@{~Row+KkYaa%E@Lu?-c)rL#6XJO1-i7Es_udqNU^&> z7m-udT@V8)b{FW9X{x#lVj#ut0$rU>Rd+!Qq}W}cJK3q~E{K5?y9;#LJ5}8UF_2<+ zftF8Dw;qC;NV&@(B{XQK3ze!O(3)9l)ZCy27E}&1DwX=66&F-?8I{U?Lr6JI&DeyP zNO?Mgl+@I88N@`&T?Q$usp&GXiAlx9dht>2VNrg_OB9ULQ%hXSTrD#5ic1pnl2gH( z%Jkx+h*o9jlA2VS4q5MjX&89m1D=s{@{<#D^jyOAic-_`;^WgRD&h-Li;DB}5_2+3 zD&xxx81$0!b8}PkN*MI=@=H?n-2Fmzi%Sxdv!VR-yi&b_BGC4+5>RU#6h^5T@o7bg zxv30#=|%aau#k?jZVy(d;b>>M3r{h+h5h}93fj|N#k z=)MeM^~25;K-LesCxcl1pgSNyL5Qp$bUy~M`saW&qlG`{UJPROgW?)w1hW00GsTG2 z4{|HIe$YJ_#OjCbV@0+fbVe+(`ayTapxX~RTb5Y;u>G~j_JiC+tbW+NiOBjvXRi^f zA9kJ)vVPG07R2g@og;y)A9Sw;vHC%0_n?O#=spW#^~3fXBij!;V~$w;3ebJY$ofHX zO00g++2ZK#2i^NatbW+}8OZj7?)xEDKj@5Hbo)VP@Dr;abfyxze$c%<#OjCL&xh=O z(0x3_>IdEBfo?zO9v))#!_EyswjXphAhG&k=PV%W2i?0vtbW)%0?7J7XRZ*de+HKH z2fAm6Sp7?|=m*`eL#+M{SoDML)ge|t?EXq*|AWpfC073lEcS!$(IHm<6)gHe_va9+ z{{a^LpnG$O)&B;nA9j`vsQm#tQ<7Ny;EPkx>Q7LeO00e!&;br;`sYH=Q3K^Gm^rxG zUlLgK&m%#<3RFMrtRRs8=aZn{1gal7{VX6szXMc1a`-PKK|kyqIb{16k)S^TYCp37 z7n7jB0E>RmnY^%ggVDI+uK|mG&^dN6eJ~oAe%Lwh$o^kKg8O0j93$%ootFo*7e?c< ze+3rzFD1c#*!hyk;qQQSK0hJ*PeAQQc0cI+M3_Dpjm!O4p!$*R2c3Nd(+8t*>3;&% zk8D5a+(no^7>!H+2dI8z`$1>I!t}vtT>4=bj3V0)Is+J{4@TqC&jURN3c3FWs*_>* zU^FiMB2fLv_OB!%{uQA5k?jYag9x)1M&q&{c77JJ{i{i^-vo>OpmP;r_QGgf_S-=9 zBip~01p7Up`jPz)I;Rn4FO0@ze*jcJvi+dD;bHn4VX@^rt}e zBip}`1pmX%Gefo?bdDsPPnfRub%= z0o9LeKj@rGn7uF>m;JDNiIDBzPJ;cg`;(FF2c4SbNI||bWqjBkHfhs_@{~!te7l7(VwjXqkDO8x? z_@e|=A+r64Nw8l9svp^Y(7C8kVS@JSKoug}54wX0Dojwn1ymuj{h%||puz<8J3tj8 z+kcz{|NB7oBij!;w-qW((EbppLS*|-l3;%VR6nx)pmSiM!UXNlfGR|`|1=5qmq7I+ z+aF6p`?Cg%{x}l!w_wp9O@jU&sD5PsgU-E#3d6$>bQUS7s|!805!AH=W7v6|Ymg7A zWk8%~4OYa!zyLZ!6=WuCz5pgJ07~o(3=BJ<`a%82L4zQ%2~!R~ z&l@HXjzfO|)PCeMS3!E9!XPFX2SL*$tiKBuWME)80UB&%U|@iS6Da)Bu!J9IOa>Gt z=g@bk7;K_@6+e{j4n5?T^4>e-Re{uVBIM{{uwYzZi%81z79{ z-KB-@e>Ya__J1JKen(d9{_ntIe;F44Kfz(Y0`$;sLh0{54*M5iu^%+2iSGXOGr?AZOkfk^vz;jsS& z7W?b4#D5$IcKaU?X@4XKcK)XigqI{;j#N+h0JW{bpR)?f1Z9e;XG6-@;-40wV3dio^Z{ zEcSO`vA>cVyZ_33T{vIs$ckp2Me*uy9H}hckKL=>Cn1KO)PX);TeOT-l;KgqL0V3_^=EZJ* z02cc}Yf8}5{|p@V3qUV>AQb+Sao9fti~WE5D(2GBi)BiLq_8ahH_rC)4QVl}kug#C${{>j=2i<9c9{)RV z*k3@T{hM*vzXOZ?pgT6v?ROBs?*9W&`w7LrwE%YiGhBtF807E=&EKNie*%a73ed|- z2!;P)9QJ!)u^%*li*A3QAa?&35NW@UAa?&xz+yjW{ubT-TR7}L0JWb`_+Q0g{|zkm zgXVA1?N1iM?tcYn!-Y`z#|dHgzXE8n4O;mNnm%*0p;8XsQsWjr$KxehUo{j89-vwp!zY!PoS3ug@P0zVf6OPL=o)nceoDGgj{}r z=Ko;!L!*b`9S-}!18WQn49IslflNfV|0NFlJD~Q%>;bhOK=Xg-_Lqr5!Vlg50-%9C z1_lP$y|f^^K^WcsLQ(AgUjVfq+5e#VKXm(d;IMxJ)PB&K7m&R$jBfvC9QMC}+7DX? z4Dvr{{tw;$>p1K;fL;QHe0L7W4e0h?!ePG$bO9*n&J&P6ko}U8w!&_QCQk#B>IRI;ej1^!ov-ANfu#kREjN=0WwN z+b^gAQVj`P2n#}@+kYOaAKiWhsD6xbafmT+@)VBn;{YudWME)G4nNTPWAyM77l)=F zwD3!S+K+q(5Xe$={|kvj{D?mOnE|yQH0A@+2TDJn^~>n?$K$Yn1Jr(KF$^*SjM43n z!eRddsQt+07ij%6y8Zic*na_Pe<9db1c7em{s*m}Mzm_rJ6x#7*e_e*?X&4L$wC+zoOI2=_qsqr2Y# zdZ`M%5`;u|zp@NOKf3!b zK=q@?E4usTWU#w`0o47-^~X6Z{l7an>=%G)Bvk%g$6@~ksQt+K4>To%9)6~B*!}MS zwI4LU1qnF_iSB;`Iqd#_0kt1$40!($Xh;U#{w8^d{pjg$5>z9h_`9tD(T^Ta)1dm% z-3yC<7;UTw(T^Vg8=(4O_XR?Hk2!y;r-v*^zuW{np22L z5E9*f17+;t_X27^v>60WKew^upL!LD{pjJh0D8$Hv>67m96DDD=P)oZ+){<;#|S^D z{)fnlv5Y@mRmJZ913w`ek;|`pSll0=j@|wZ(90k}cXvZff{^Ip=dF(2eh$!LdjF^rPoL9jN}}XbBd^h0!0N`q9@f ze1TqK$%(cw0IiwC@LCh?NYiN*f8+7SPvr=J9<{pkHK(0UalYZzWY z^)sV|(*me|^zeeY8)n91nETQ6J3!qJEyls&2Wk?*^uzpRtb^VC2cY&tlQGOX26Xq= zL-nJ(p8<38EQYe`x~J46LSB0sD5h>PHX% z2B>~Q?!Se@{RUXv4=U2p-LI_=2|slAFM!%l$o=I|{pjw00M$>({YCoN!#@Fw`~P7{ zKZl|Aqr0C0I`B%!{rm6p!x~9e-RG%AHd>%P?kndKcAuYqr3kA)P6$lw>QKd{;-K(LhiRR#2)@1u(+Qc zOZay~?MHXN0<_^t$o`_bL+0JWcx`c9{vtc{e;|q8Hf7? zK!puj`#}cH3F$wFBm5RX!w=Ta1NHw^u!P@#sQs{d3gkx+ z)`0pSef$Gbt3l!%q>jTJ!3ObRI0UL6#)r``{V=|SIRgV|j{;ivk0Ao8A3eO$!@~e- zKf3-3sQv?-FqJfjWMqH=Mg}_u1P><4z~E4d#0E1R7@Qa!!D!v2AQfx)-+NlAob zLyd|BgGcAz5?M$7eI+W+9-Z%BfOL5@AK{4g=sfNi^Ag1M>3j|r_UvX+*~i7ez~Ipf z@*#sqw}XL)<%NX%9X|NjTM&cLPfnNM$uihvI^MRdM{B?6z$m(b|<>3oJ9-eCJc zvF*`$6db$AY(x};L>*(xpZ!IG6tOJ)bAbXI~jWZ&j9R{Tqs^=(J zk%=`wm1D_IpfU$XetHMVPv2a7^N{n?yUxSl?9u%De+e`{-8lGw>EL6g3b)P}P^p8G zr5)}cD?qUfS%@3U}Dk2`%#R{dHJ-S0wID9(agUo^`vwT{* z9qeC_JrW52@q08M(SZ05T>pSoBeeh~fc)!m++6_d#^dgw<`aX*ad%KNiNT}Oyfd7m z`6nBH`$Pr?hEQl>+j$ZiE*u`oEL|Rq7wrB&NQ1>E*aA?4COY;os63!0|1j9`(CQDV z{Q*vW9^K^}yVx`Nk9&06gB@Xb30g&XbRP8hZVL8r=QW?sM_^gU9iUdIN9%zS9*=GY z5Y6J!?V#b(dB8E|Fi0&FgRJcQaM+*%i4SVOAZpmgHz1=rOH_D#de^8dU|?YI>8(*w z@acSyRBX1WtYBndFg)PXS)(EWc7R8>EXYWYURDrg_|2oU1+3ZdfJZkkNGPqdMWum} zfx)BO`Gv>v7L^K+gF)?`<1H#3NbCtn>={Vx1u%AJjEaIsrw@yQ$8i@GP}7RRqr3Wr z595ERJHQU`=*>|vF#P7xUGc)B(?!L=qZ=a3_}-(F9YrC;bs#?$_;mgUwR$0jLp%b~ ztl-gnAOPkckLDK|AVCADPeE)8kV_muo&+&GV2l75BLc=qfH5*a42Uxz_V{$Z_vkHA zv49xY+oCdofq~(;i%JD3MSFCzsDSJTb%1m;Ffbg0C}RK{w2KK8n7z=10cl}) zbo+q39{9q8@m05zgvW6w0Z^;cr@Qb)^MkFPjPH0k92giJ8}>Z}nb_$h!QWEN$iU!u ztnC2<1A{?#i3$(Ak>4%g!R+*+J3ylG(boO{|2Lmv>I{(Z1Qi;dAm??vs3ds8TD6YH zTvP-=sgS=VnvsFQr`ts(z_;}Pe~T!HXL*3Xod=u}d{iO~FByLG>3r^~c>?SUSg3aI zQ33n5(?x}d;J3C>DG~JOh6IO4Zvi8+S)f?$bWyQ@h(Xfkr;b8d6$hww;;V3ifYz~H-%mI@)7`j=H zGHvEyxXW%jiG$%hM=~fcBqbJSCdU_-6lLb6TUo{X#wX|J6_*s1CYLDWmFDCq5@tz{#QWw@2r9kIt`9AF`-; zb{_R;{=r}F?$P{%vDA=%TPQL1#EYCTYL@wE!P zKJ(~&W_StKVe{x@_Ut?YZfbNogBnoauHQR|<=reQKHbW%r$Bf}J!9!;Lu+HhTn5*m zApamM1qSJ8gIu_e!TyExemy(Cf<_M@^#_u#AsNB&0H`;l04|r|Ne2?^@FJ%3IC47h z>HLNy%THLz2kNMHo2Wo5O{gM>W~PB_WAPIjL4w>8U00sd*(umGSv$X~n4}nhLHUoF6bzs;wDY}3=UuRK;9i3k>Y$|V$jZPFQ1FkD;Q}LTI}<38 z|6^oW!o^&bNG;hmM{ zHxfSG=^Q@Y_CB2td^CSR2J0^Hww2l!jBfW|v-yBfar?R?}iu>y!P72M^3l&e0Spg8pDbOCi-cvK)k1R9I;>E=-Z znIq=WT`J(y`QJzLA6WAB8gPHcr}L0c=Qp3u^I$>W*8e3_USH*xXYknl1LFO9kIwrZ zoj#yZH4%uh9^E1;poSX=&He|`_k4<7vP$2@vvj)DUC^>*Zv zP9d>Gp(sCB0aDH=Ft{h?riP?elrZ?F=9PjOAtCOd%*EiFS)81jlarX2nqOMX;0P)z z7#LuYk4Sy*!S09gVe*J_5hf2A`bCIC_%MA4aqQ|nx~oCGMFkJde;%#>OIX2{!Zdj_ zzt(`&WImRUOW*r+eg`Y~|DRFN_%R~`!)zwjQ%nq7m{|8QG5r6}$RfF)@5#Wc|em5+q7ez^{sd;VdKTA4Y~}jI1As*T@=>x)-8a0^$Zx6#bv=%4l6~ zw2p&eBNOX(4u)OKtV=l&39g~Q=KN>mc3sHGz%YS{^&Z5hBGBpvB#jq?^B;6{qdQ)}qxE))8L0i~(RtUS zTiT<$mcyghRl>vacnPmZx2puaExivkQ2>vL*4w4$JVB`+H2h)s&7)TYoCd+M5giNa z27tOP3?K%$XO8HDg6xNMzYiOLm3wqoU-0NIzTshczeLF6;4|iE@MtisKOT+Td1Zi% z&-;KTC(1cInvWZJTK*{E0qOGTJPy`}rW`z;59{B8+hd@q4WDk651=WHIL~ew70=Fd z9-V(ZJHL8%UiawsHh8T94v%hQkJfJ`0Uq6c28NeBJMVaOp78iy%He5wwba_9^RtiT z$I{!L-QgS_*1-a$7d=`pm4H$%hbOeR-g=;P4`>(xwWXgn0W_xa94UrC;Q@D_N9W&Q zkIv5?o##B7-$ZzHhNuW2wWC~AJU~O0?gk#m-8n!-p+_e>`p^e> zr9rTIpKfc9;~>{Dfc((wAmP)U%>i?7ZG`fWLJgXq2Se71BKS?JQ9-@a*L|;L*+K0qXRE zMmIdV86e$cMxRavk7id1Mnssjf;xU62YA3+_WZ3MLE+SVBm%9U=-c|1zjZ%IuG>XL z;-%MrP*2bWG{;t=;s6>f@TA9aS8$g1X#G|y z{5rs+Til~l5Huv!$pOkx_8y%d4KI0gn|X9Q8hC#H?%B(7!K2&4qxFC36_0MvFuA2i zr>}rdr+`PZB?Es;4Fdy%cPGyY&(4b=6Ayyo!K1sD!Namf#iB$QlJ#9wIKX}ejWclg zbbc_r^$|#`HULa`cGswIfI>;4gb!3yBZ_jL&gWn~o}G8VD&eI%w510#3uFh#GGU0SZcyUy zbcLjQu+ZzHASE81hhO)CQU@4=L_(on^5}dDYTNnrf+nOHe0sO?|NsBrF~p~LslfmL z|ARexV{dpgz5$IiA(e8jHw+JeP50;qPtJn6sF0>GSk$NU6TGnvX+PxBiN z!;>DJw;aQKdVBf6#y|7vZRG`}6iCQjW$ zAh7}{8?;6O#Dv+wSQX#{b^-frkgzn&9iTB*6_5xhtXUWsKyGJn;}hs-a^jQdV|L;KV24#3$ecaT)`tn)v}W z6I5M*%cZ#1l*q-W;mD`p2-EG(%>Y_|u?4F49|OWYeN3)= z61^b(Js|yUtnPddKw%8>a|)=kVPIg;1nGE=JtWih5FMGZ zj5{}j4+8@ODDFXS2t#oLIILayU}23g&x3CPBhzWD20C(s#vLAj+yq_s0**Vr1&qz? zZEQWPy)1pq{Y);PFa+gQ1_lNpBs=>+@zD#4-yRkhK8-e3M?QmQHW$7Lj7$r;z>arB zidKkSK2UQ&ZBvL{6BwJ>+E{y7dYSu}7#Kiy6+qQcYS#{^Ik@byVPIgm162cR%z@qG z#wXAViq9TqN2GK%fstu8T0(Q=2IUJGPy#{;y9tcVtZghk%)Q`nvw_M}>X#O%Ik@}+ z$}bvV4=^ws03{BvKb-g^dO-OeDZebn@CG=2ra<*Rf$GJ`yNLAU&X>TnA4hUx0JRki zpk|!}r5liWIeY?bOkR8v&CKq63Ner}$Ptv$Jt<*>i!w((4#&gC9QhQQncF~72@0PL zQ2RlXVPGay7F0I+fC^a#28K$IyWBu!qYJ2P1R21>6ah9egpUKV=Bom#7PMB2!Ie*- znJJEokHeSSk&gphcFusx!^%!jK3@YBn+i1_PdI`~uRN?Jpffjk%^A%8P*^yE-OJ<$ zav!M7h1q``UzrPzH)vTjfsvVw32V%Ossjd4z3~R>{w!ENcLm2CFPlprb1zFk535Hr z8`D!g0VWqN9(E2_aQUGCs$>}$7$jltY!14hzG_|JY=i8Nd^k z7*fpOkjD^aU}k{TRtPyz8P0@c4!AyqN;5NnR{lXbNE9=8B_NUjl*!BhS{VrCAW_T= zpjCoM0#GJ1I0m5{B#M~8Pt(@5M~eq z0|OJ1dQct#$<#u{VSE_98Y&J-48AfNNVA7fv&SYjrpm&R}K$t+0f1;S6SQYKC*+3}yy!Zie$=3}yyU z?GEEXXalf25#pdc0g@?W1g#wv0Jl*@;+ExmI2m21Brp~6R7wK5C;jrf{KHitw`b@pyC=}8X@rw z%$H?I0MiKZKVZHPLIBEQ1QoapVo)A}VgrkVN&|!#h{X*R2Tgy2_%JL06$j;4m>7r_ z1&hNgxhD`JRKz+@d*9Nkw8 z3<6-K++a1x1gNf6LMpFdZTET>NShp4Er{KXLwqI<@m)B?FR?H%2r=+7fF|`p=E6eu z84mUDaHt1OHh|3805XJu0qzq?Rt5$oq;mBIxbkISuwrFkP-H@cCM=}FSh4#z6Nfmc z?}wg7Ku$P^L%lE?cJqU9h}Yu~pMXRB3=VNAcI@^V;}EaGA>NBad;t#eXE?;a;}Eyz z!0yg!9O7L##6eS1*y3dh2Pi!t>P>Jzj)8&U77lYB;t*Hm#O_WV9O9mw*zN5HizDi5 zP~Q-gezxE+=L-&T9WLzd$-yCBhC{p`hxk++;tRPT`S$|I(XhTM0|UcRs5oqL0#=?q z=K_TTqP+p?vx2mO8hc7e?Fw+8l!1X^J9JC{qy`!9$02?chxlV|h&w^`C&(O7KNUoC z@?Z})H6Doi3E*-R(#Hg;_lJsa0GFc(@d~K;1!(yK>brr|FMx_afVN>leJ+srQK&cr zw4ep|j~Eyj-a*9=K*hm*9|i^ndq#+RHb4t1P(KD_jtDPyac^EwIKx66+P7d}V94Ra z?%!fQkb2N41;|tec#DLUAG`Q;usEWf11q;r3V_tZT4@aMcE^7~?Dnz=LEPWK39%Q{ zuK=;Kg|Mq{5(1U&h@1^8!Dk79>_xPrK>ZJpIq!tAo1-j(T|5?tcq0z+SvbVk;1J)1 zL;REocK6GPF)%>dA|T%&ur^2>!G*J&afnCa5HG|b&X5RSpQ4vsP{0r$6pT;b#-+ybuELs$ROS$u{Z;~M2alu zARCUwX|BPEp23#!u71HK7V+^ZsU?Y-Ife%D!Kpc^$t8xxC7A9-@{3=vQ@o)?yl;L= zd{JUvdTKn#mzjC#t{@2`gLs$Jw8YY!5{P69SQaJ~P?VXQ8efzO(h*;fpOcwf36?T6 zNB9?(+kKJ@U44=aTtT#}tE;oAXMi`z&8{Kw!GZC)LEgdc@j>3ft{}oOKDfltJTtE( zHN7Y?2eMQ$F|Wik39K0urryCNrpYCh1*x9Nt`;fz@#UE*sd=u+AgSPd7~3>0 zr?fZ&5)sIn42|P`A-dv0Sq7{ixWv#bKE5QQD8D>DDKRBJIkC6|9D~T^kBbplZAwl+ zSuV&r6gfk%97=g*0$O4R6*hE9O)5?INX;ooEix;~kIzW0a54p_c-JfjmvFtJ)HJ>L z`1Fd3_=41;;{3eCoXnES_%d)A7+hkJnO_{AlvteV3~@q82y)7{K+ZDIvJ^{^8w}1k zt_<-}Az{HKmJm&u`Nh~W8Az2MK}9Cu@CyhoF*Jpk2C+P;G|e+P*f1VsNJtpPF2!az zW_<#Rkl+%toc!d(oK$B>Y@k|>aARg(I>e0_#vsB7k|Lm06LbX{){w$ikp+N?rW~-- z@-5?iVaDWws=xdYXrV=F(PwB7?;Br~T9A{Noa&mJ8{nM`PK|KSyFfe-DiL7G2AXn_ zqk_nC7Ub&0;^NHoJl7!aV3T-;`1s`GX^bGNBXkK|{UP^pWYH?{Us7~|?P9fjV&PHf;OL0k2PHG-F8cFskC;*d-QWHy3 zU4wFS8FEu|lM5=rwYH%pti;L5PtQz_Pc16SFADI6lw>5^<7|lLXi$3sxzsTQoA2ob zN-wUiu4OI-7zvQ1fQRO>;F6qTPvY8l$szHs!KU$0FM1=zIPqE2xVWSUoM3`WOp^0U zOBg`yhQxUAI?=?E)cDkjpQ-b#*E54~Yk* z$lUxgP^QT%2l+0z#K-`iFjMo=OEOSWCQ9gFZIFY*8MWnV4hqF$V=4qGthTBT9SX@G%D?gLo`M0*0VGmIvCmm6Tlq zX1N0v%p(%>_qoaEXxxtX%@?q9+y=C054grIyF%fLke`?mB4f z07VUG`%oFQ5tx*ko|zY)oLG{a0Tn4qg*FW1lPePAQ}aOmez0s5s1P4bFBs{?kb?9Q zpHiG3pOKiCk^^dMBKJ;BJo7S3Al(V*=%v4#Td-?Le2Alyk1Mp73?BjktA_OYz|odi zl3I}o+8hR(K>$ssm@_ai{DCe$cZZI2gTz7SQ^CZ;q2i$F8Z#vIAhSSHAoW&A;-Jmc zAaRg-(0W6dIbT77&^1HRNa_{A>kU9_N*EYGa~&}CYEW^I`N-;FYd1mS*+}LbKvIt^ zein!LFC_6aBy%)C4u`rES=gwxJ;>r=Q1u`Rv=#y8uLO_)cx?^jJTaJf zDpVX~PAZc5SxDmkNa7EX#F72`9*4LBbY2Z)KC-{!ki?PQpMgWX2r3S;2H9UVNaCQ? zEHHmHLd8M$BKxZiNgUZO+o_#~(}y1(WiiGx;Q z!ThxlDh{HM{k04v0ChjIzvQ9wlptwjf9c~8k3|wk_SY07ab$nZ!yyh@M*+%u=>FOS zRSyzZLrPcMq2eHSBKvC(k~p%z458}*LF$qHWsgI=1W6p(U+a*>k^Qv;hxj3=ILQ6T z=@7I|1Lj}Q>Nr?@U4*I!xf9u6*O0`K{bd84CkClU_Lmn9@tH{C$o|@cB#vzU7bJ0H z^KGH?(CGGh;}9=G5=XXo0g^bfz4xKwpl}mKig!lnJTb`Ld?ax}B=IaHaYZEYLL_lR zB=H<1aYrO^&}jy+cnL%j2d#C3i6?nD|OGaghH& z=>xP51Vn@Qp!LBp^`Nu|69>(K!^CHR1flsFw3ZwuUIwxdTAuSExw8pP9App3h)K|L z4p}h`d7+hn>4oiWHt8_rux&t{}sp;p2!D4lsK_<~xD*R6x}QLurt>Gmfd(%F3$&d86NiPr z43ap=?=W}TB8j^p`KuNx4l){IbX3V&6QLa2Yeki>hC#J!QkCquWpyD8RBIk?yP;n52 z91d?l0#NsW(gw`^pP}L)3KZ`k^FTrI3nT!w7bFe~e_o{g0uqPCy9k;%EZ&XK#9{Ge zha`@i4nv^gAb0p8h0hrzaX%#Sdr0EQ?dMleagaBV+s~XJgQ4MoTt4$5i6ghG?U2Ml z`vG9#=7A(0h~%CCByrH1aG3gVs5rl9QyC_F*?$zbZwL&ZVrBa!R{r45i2NE}qw z!qkILGlPZ?XmuG(927?|^|46ifWibM4zd??7BNgc$S)vqkom~!lR$z{e<6#5>SB-- zNIi1-04vu)=7aJa%zRLt3saA54&*dpNIwpw2c~`sNHNsjI3)Kkfr^9F#v_TZgo=aQ zgItb*Hjjg(K;p>he>X@FYCdRB0?ghcP;rp?iAd&Of{KI80fh-n{VODKWb;2Ei6iH) zUr6GhxPX}hN|PWdkom~*3-Sv{9ONG4_yw5>5(lYA4o^^@7bFf+j~u@sKZ3;3)q~oQ z*u<+rg3#~*xdGp9577au0HPfW;$7J+e7#kko_p!0g=v6$hzD zP7i0G;vlui>ER+&9HbuEJ)r$5ASsYIa(q1o2}1n~3M-hsZ=m8J^O4g7ay%lZ2hhQJ zAT8+T%R=j4kT@vrVCJhLi6f_n6CgvN?ny^Vhv2gwpyJ5o6|#Gf%O80p^FfCh!t9NM zii7+G+V%|-Plk$v+?k1FFNhCv5{O0)H(0v^T^v@vg2a*i1*>mC;>hN}>RWViP?~|+ zi);?8-HNUr6eckB$mWCELNIY;b3k1+k~p&YyOG2} zdw5{xgn|MWYA>j+hlv*)F%$=aNI!GMUmgz!L4@#3D zagaI4<|CK4-AL+@`}?3>4>0pVV?H2rK;DQ#QV+_TAaRiSpu09;>ia-~&~QdpKOZU% zQV*K@fT>>x6-PH8);Y7R&}XqN;`{UfM2y7{cod<{~MJWeGD z6$hyYwasAWAlLiI^@1Z*J-RubNaE#4;T8oI2bqtYUqX?@QQ`$E4l*A!&I7Brpxy#+ zKZ2F9FfkAf(gv$@L44305Qqku1F{>$24Psb1Brt$NDPEQZ8i`M5(8mS*$3i-@(zdw ziGeU|KjLJNAhg_o^`SsQu>G+hwa}p~kT3(R9|01F4#9%O|A0wI{{@yuKtdKE4?)d` zR%sw%2ITMu-MIo5WME*(KvEB~;{sHo22C6sfJoiN4yzME z;vygepzZ`QVf(RUK^&+!KS&`Iryz-g;uk8+kc%V^QV$v<2FZ0GiG!H1{aX`393=B$ zJD)EgiG$3CwGVD0iG$1sOxQlKzaS2h`Jgcokb2lz8z5^_ku{`AoZX!7oY=7HcByo`W zpkvQL=9{364} zAc=$G3)W9wizE(G4?o~SuedU|Br%CWuehWLLTA8OMX5Q7dZ2ZZ40%1Y3z#DMbv=I?_*tJ0eu(+hiP!HYfC^3wr zot%YWXp5%_$2FDhgZeWbv|fmwi?*@HXK)EU-2hL3;8;dUTcvq9nc1m1m6+)VnhhY~ z2IYW?3s9yUU2=(K$t8TnGisSP$W}dLIBs<99QxWh+{=wo18;QYF?feKDJzdr18}q$ z!BUJ+veFkRc#BICi%LohpanN*_h&qK87@=++=wem&Cvtz!qmgJtyM2MKQ}iuuY^G_ zFTW&J&)qLn7rd_!%1_TL)hj5@1);9*}1>Lbq ztbW)yKeGLxIX7bU!^R_!^@G-x5vw0GR)_9>&{!C;`eFSxWdDQQM67<;d>*oX(3lLd z`eFSjWc{E%BeD8nXSO2i2aSsps~>i*3$lLD#WKX|hs`%4>j$N2bp4?5E6|V&w3`Qt zGB5_6q6}hOMIIDlz&!f|)E5Pr2{Id`9)<%zi*6Vg7$Tq<2$X(7<2g_+_+Da=TF}}| zkp0kM1dtFIZ$%z-0*gQhkXi@}LW1VqKxU%rKLFJaTaN%y4Y}_a#s<-#F;I}1kaONZ zA`lGIk35D3l7Zz15F3O+W7r`5uyG!c7ziJS+K=uokXn#Dj0TNGgV^ZyUx4a|ojV57 z1H$O`gXS2(;SU-x04adt6`;i_3=9l2K$4(yfEXCSr!waALjpdsQu{i_ZeytY!!8tQ)Z_~U~fafmoE3t}b6 ztq>N3RAK_1|A-lX22lM|(KNv9hY6cO^`ra$0`y2y*g0Jg+c3)yLng?YK6L+Y08K)G z${T3Bg8UEi3(S64{LO;ekM94U(1~1-9+=%A8s=^g8-%%-vHM>f8u6eo2dRT$n0^>N z0jeL}{|-?7u=B`Z`qAURn;E|IeWMLFEHTJq$ym1IA?#ho0AqQT~G#%P=r7z{c}I@dw&pfbM>6sQu{X zP61_B1_lOpm_wm9g7ONK38tKI=$`{kAjo5%APwmHZE?6?0<=hnfq?p}R z{r*t<(c}LB)P7K%53(1A(c|9>W019T7?Jzb#N zU&e|({c%7C>|yf`Ap2o;EyyoW?=eWQVYj~lYCmYt6G%M_quUQU*Af&b==t9QYCp^# zko}MDE676_uycMPJk0X<11Hpem;xvr0KT=7fdLjTAp1e> zXLS2HxEL5f^9AVboC%4(wGT-fcO0P1WYoxcpSAJqSX>4T*UNiK;0 znW5nXvu6eY`(f%tVD_WwUxCGb&{|t``(2^-gVF}fOc1>QYCkB?fcP*BE6!lFA5=d~ z9!8&m>WA@RG)y0iAIHT2o+?9gKEnm5ekcV~&H!^iOaOGAC&)~6{U4wj51>^H==uv` z;RiDiN*{oR-w#mchPFRJ_piY8!{QH{-5?`2fHpTVFfb^9It>gA450c2Tl|B%C+KMp tr2hgau`)0))IsYpkQfMq>;us-3~Huf)4v0>8Hj;_p&i-|hp9)`4*(f>|DgZ? literal 0 HcmV?d00001 diff --git a/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/config.o b/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/config.o new file mode 100644 index 0000000000000000000000000000000000000000..d024982ae8f22282cac79a990f8873d15d642a41 GIT binary patch literal 145144 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

Bpy=-M95XiHJvcxqwgSaUacN(3IrDz;IX}6b1+k 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 VeIji79YB|)F)%P3Me{$pegN!T9m)Uz literal 0 HcmV?d00001 diff --git a/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/extractTypes/extractLevelModel.o b/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/extractTypes/extractLevelModel.o new file mode 100644 index 0000000000000000000000000000000000000000..3d33f935a687ce7746252d55daa57e95eec53ea7 GIT binary patch literal 30992 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%0A0Qn!Z&J(5& zM&r^C8@EMHKcK!DOdpKKrT+-je&qNAwP#`aU^J*54{DM^hsU705a+vwAvdNOFwX!1 zU40BP3zptt2CM*0t}!q$WI!ABApe8h0`m{-q$k*Y=FnyzOgn=ba$_AX3OXYYiNnAE zKKT)3Cc1tHsD4LiyA-AiCTw z7>EWRu*$%|0J?qv#D`&!TS07)9uN&069lo@(CmjzsDtL30DWo zETHr2p#q@r2lXFd_QS#-w3ZKSKU5uzY5+wR0|NtWoi$7x-F{e_MvwmpsQn9|7J}>t zl|@i4{9H!R`b4n(X#PI{EmYCXMYkWc?h%~+(DeTR4K6S+z|T1Z*$?VZpxe(3K7W&e z0VDiDfyKbU08Pd)?_-<*3z`?jW`6{9U3_JhU^u=zg#YCr6}Gmse| zjP8Fo==r<5iaquUQ!UkI|F2`&B}LhT2o8IXP$2C0RyL9`|KJW&Ru6Ollo3=BV@`a$^{A_5^{ z_QT9s2-S}s{|3-bHEdlcL^o#n2kKX2i~k9r$v_4M2H1L3kpDqt56pg8y!?jRkM92k zP>+Mo0*BcRqCs|nXc$fepLdGs{|iw4puROsEr^Es8%8gM>PPqg2dIA7`E4M*AdDXW zpgXxhZbDCgCqM-g0|Nv2l4J%329W{Y zI&TythF<=jgX%}G7eH!3dSP@83#3j#_x}T^e%QHcAUzqBtAJDD=ET4kh4_fmE z(+3kTfVm&d0}4?4Ve9N+_Jhg*7#l=yV1>95blx+F55pgz`eF9L#L@ZJq4q4XwGM_fa*t&FPQsb=D9=N zkFGxgsy_iOVWR7IV#A()G@#)JTNeTfKhXXJn0{FJf&7DRH^^-}pc7gF(1-@D%LMg5 y(e;ChCp0I5v@>vkHZd?TFwBG217Ja<@Q3k1%`|NKXB0zJM4%NcAooIKAS3{cmy&z{ literal 0 HcmV?d00001 diff --git a/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/extractTypes/extractMenuText.o b/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/extractTypes/extractMenuText.o new file mode 100644 index 0000000000000000000000000000000000000000..08a93f4054481eba8b7da62801a87ef9074df010 GIT binary patch literal 44912 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 literal 0 HcmV?d00001 diff --git a/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/extractTypes/extractObjectAnimation.o b/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/extractTypes/extractObjectAnimation.o new file mode 100644 index 0000000000000000000000000000000000000000..baf2e9a76345db2c4863be245b02c10b7f34ece8 GIT binary patch literal 30432 zcmb<-^>JfjWMqH=Mg}_u1P><4!0;dw!FB*M9T-d)jKOMo85qDcKLZ1U0F*7vz`!8F zz`!8Nz`!5|6%%J*V32^aB^ekPq!<_&q@jFS1_lN>1_lOsC|{9*fkBCZfk7F{*J5B` z&}Lv@a18P6yb|is`8C+1^S4Ly8-Wy$ZWdJy1_lO?P8Ssp!vh|zmr6K2TEFqPG%zqQ zcxt}!=~PkiZ2rSv?&8sH?b-Z?vDBDMp7kl*Df)s)U!NgE^|7U)=Uxz28>G8|AfIP+k;yZ?Wc7E`I_|&8G znq!z_D9D?CLW4aT-)Jy0Fd)TIi;4sz1B2lKkIrxopUz(%y=zoHFfcIqbh3MNz6Xbp zXSa-sN3V-Yfk$tRN`gmcjf#XvcX5G7cW?zLiVZ+Sf(PTL7aRZm|L@V;q5_I%kKWA_ zz-iz(NSXs|kViL2D>Ozty0@qZFfuTBw0%m3mCzwJiAL&I6QhqL7s-W)VEtl1>}GQAe(#ls6bp$qoUy1U0UGT9SU}@g-2%# zM27Lxi+_J1PTl}Yn!Q^g8o*8#0NVm`vH~m-5#eO4P6g=$o7_D`Wd_J;o$oz5=Ro|( z_~}K}-~a!8dZD4wU7{l3)A=1@dFLySUQ@6KA#n*2MG80$xYBNDn33avpMO9OSfg?P z?6!A4(0KR2YbH4SK?w$?y0=8d!Kb%ICBUQel@G{=B`O*|oi!>B$6Ztc^otV9J&wDm zc(5=qFdTDH31NWxrAEcU$MSy(A1JQ}c)%hT6k@Q%L9`!BR5Tz~gKhQL;h&V1nq1C@nyWQbC{{(E$nDuCjW z)1$Xm0UVwl-L(uJy{-Ztmd8tYJ-S^55OLCcRKvsab?IqOP{G;ywnPe)s|BJ#sZjG> ztYZw=pK1K^E({EySUL=w8VbJ*I0RviPd4mB|Swf8M1~(-jtqiC(h(zamXu1939H>g{eCN>(wgs#d zQmKMUNQfI=torx=zfb2QpU!u%dJO6)s39QVv=N~ui3l}zxYYP`e)s8o_d*UP{|(_5 zXbl9WKt<3mP<;h*FCI15h)}bM2sM2~sL3KijT;eal!#FC4^&kW@cS(y)NI34)A z?Vz>*sAvVndmmUGC}H??K7u5!-W(NyT}+_-1xY_1o$q~mb5s(bvNb9e$g)sTQBc|j zH{!qvujnVJRR+-lic*j)$T|=WZBzO5u2Ja#+tLDVv_SOz06A_2NVu~FEDbgvj}hRi zrMCs#wtyJ%9c07>s1YD(tVTe?!lTzmh2Nv|-7Zjdi*Vr_6;M9(Xnw8X(OV5Ipu@_*V8ZIgV8iOqkOK}YhUCONP?eZml$uzQs!&{#Vr5m9np~1! zq>z(Xl%86oP?C|Dr;wXi5nr5Hm8zi$aytlvE!^<~)MWbqzuqw%)EV;Z{0pwYdSxbg z9DK~|)2kxq(fo$P<2XA=hsSYu4k!)kJTrJ$9_DWcXNA_=B?TUx_dStnHO9l9ovsX? zoyR;oV+A}q5Bpj^FR=jiPd$1;HCrizM|UU(xR1&VYRiGm?JZS6BwJ7w+7!xNy6GQ90^+#T$k*EgYw7aV$E?{yx3Ee&BDeH{d4AnHeG zg=6`-B-pdNOu@6a4%|Rs1?%_hw)5z{L8L z3DmCxg#`nHl>&owv_UR}!vIN-kXVAJx?qpa%N~tyb}*yW#VeRWbuqZZ$Hc(k)4NAS zfeAG1a2(PB01ZEYUFXpY8W3SHykz*zqq9e40Z36dSSYP?ib?}BNKX$$Z@1$M4~P_~ z7f`_raTbW(fyADG#GZk~UI1fv_OO7Rf-p)0RAPhr)y$PId^-O_+y#*am4^mQ3=9z0 zfmj~ho-ceDKYDbYhdHK`A6bV-H@G|p710)8&p5t-`q86v3dH8#zyOe6!LDdNr~zVw zP44YcDFA8dJnzvt1rijnKD3XD0Z0sN;_((02dIldp7%gv2OzN{kk|=G>KAq2eKw0t-#JbkE{4IKHph$(Jd~iSMyGJKP8o6?W)mytjy;68<3)=ba zHumTa<^b23@PQ8x55`ZRno|NqK&nsBCeIVK1>8ddjYq|(KzmV;g4*yKC=g$O zI+Dw^lRo-BOn-6G!ECIR31FF2UMFp&+w?ze1UxJ3yI$cy0K*sC< znE~>^aY%g*;)29afEZA5P{j`7g2X{JFo=!f98fFwKFCs-Euf;{c#8^15vY6vg)G=n zpiwB0DWI-6$dqG{-a8}>c=VR2#O?xxl~3pMV=gMON+A6V9^El22|nF9DjA@Wh|!Sp+HW+o9oaOzB0antu>$ z;$y(dULQc12Qn!JstV+i7??|1R6t^`A5dxrc>@$qy=x$2WSw)sG$?h0q&!*= z@V8uHW?=B?h6J!LNI)7SV0nPQT?kZAb@!-%f*Vqnz4z2S0d|l__Y`nz4Av`$C2Y_T z4yZQwfDH?QodO?afkruOoTsw|l7jK13hNpb4ajH!DB2JWmF^l91+)|dbr>XNch{&0 zKuax9+=CNex5EoiaRp{WUDDZtJPZgLZM3dYk-#>T04~fxCUmc1Q2+%DDA%uLVqj>f zwP4_H`Nqh=z`w8586FUw$D!_NQ2`ZHplAW*3Qz(AB}8!Wcg_L(|5yunK!gDt9lD^J zrMpE1RO*4FqlS@z!3Pu_#o&zFqXH@eLD2zf(jY|#$W%~tK)eU;DMDSa2W$&GO2E#* z5+&d=u(JhHFEt+s0EZi>Tx@;;&L7|qK!h8(NJR|RfJ#=B=rKTw9*|n7W8l%l0jp{t zb&CfmY~j@yR28_+1i1rjH(13K76==n0_I$>6toURI1ya&9&b^B)rC+ew5Wh8a(Gjn zzx6dJk2D?u)%Qp(A!xhQv-7~q)_?#1!^S&6{AYgF59d6FhpisDPpl)|`F${x8UJ3?OlEkp^wAJPl}2Lq%9b@+7&jA0C8WFdS6 z31nyl!E!4&tf#Pm(-}CMAp#s!u7gbnjq7=Mbl!z?93U*HTVOW8-2D1H%<^UkF^e0ke@J8{`BIq%;Uh3@DBOnfrPfi1g?@`g#$F@$%Kb|NlV@ zkO(i#buX>|g9c2Xm3w!MiUYLj1{?Q!+W-HI>CYHhX9zRQU}F6*%rKXQb)pEv9+r}R zVTL1YtPMg83prTZgc){l^fPt}F>K&s{VvFGf{V37gyA9&Z@)0ZeqPp}!VI^0Sr-a3 z92O|=7iKsu2oiZL2vYf0khNc!;k{57BLjn8Qf3~5URH5_9)onWp|!DbE`w`DNl{{Q zNoHQU0%QPM!7&ds%AA>>$Kc`}q~KUwoLW+>5R#vt!w{5OmRX#cpQm8Lkdj>#p9q$U zFUil(i7!qq0hv(@F}$=m-cZi~G-jAul%HFy&j3-X&yWhSO}8wyNS`4yFFB_)B^4x_ ztItqel&sH?lbNKSSey%CfJIUgOA_@Nl1ejkQuG=0k`t3NQuP^f^HYk!IzSp==D@9E z2y%6F@paY9O<_Qkr;y->cgaC14;=oWc!qQYK`g|mumnUF)=P(`yx03csx+W-5Hnw| zLWrT;_qq?3R$up^%e^fB|NlQs`ehb~gUwYaQ%z83ybOST8rEK!0q zK)m?+I;e61wS91pPr!7+yZ{eIsC!5i|Noyc-m8%iy2w(aWQ;n zWWB`2u$GDS7#G7yCe~eC4A+=g*KsjyWM*B&#c+(7bs87L9cI=pE{07kAd#aitp7L} zKC`fX;$&FC%KD6x;UgRCEl!5@?CPI58Sb&Op5tWrz|MMzli~k=Mpox*j0_-#rRy11 z28JnYtj{&8OosIPt2g7|f)pTvSW)@XnQ0-JPAS6f{DUO7lue6$}maO!N$N4NJjX!#X1)Jp&U>s4!S7s0j~h zKZ43gcfU|jL-_zm4B90F&wYawGFAmKFjfdKO7pODOkiXH&yUN1Bp4VNz}kaC;m<_Ao_q@kzLYZSdxXTgJd(!N9-(YFvV}><1A}d;+~pZhR6w%#M5t zZ7hy_8qKUOd=5yJ~`xi9Z1=0ozD-aD@1E2tEOfxVrfY%cE@Ch_C z<@14tK|pdgP&q%4Vjn(%Hl|vz94NdapmLz~10ZQwSTa@x_<%#2eKtr~8W!F<3=9k^ zAQ1)zhC&7g22dO^ApGqP@^>K@EMOhEeHa)RLZIsN7@_I|_yqcyocJXAn4S0(dRbig zGu!TAcRikShldIritqL{&}X^;ea5)VTIC}A)#Fo4oCNPIg~ z98^Gq_%QKPP;uC>6I2_+O{h4iJ&COTB~<(YR3Xe9CMJlz2hhZ&q2deB#4VxX325SB zP;mz|@nWbrth|KT+XEE`^^1|+xfCi68cabJKLizrg&WMA`%rOEdmdT+PpCMkJC7_b z!VK|m0!R=kob{pN;PM~M z1rvbMOyG(~g#k1d0u=&N98mFmFb_fSLB%T(LSU8%RJ;+)Ll9C>@jiqQn56&}pAP0B z2sNnq9E1>sQ6BV5SZlx6^Ermupk2igBMgB zG};6c1JMCc@pB*!5)OlkUqTWCF=L?O*FYR3oCFoWha?7KWYVkgI@-gQFiI%uov!$E?h@fW^^OGcbGvi-QRyQy3WBzzG>lpolkuh1gKU zK%A?rp!Ji8dJWdr{J;ungM!o`V-q&);?_9CBXEdkvVrUct!09k4sK^MFfc5@q5cUD z@i#ckQD(>PPAzr@1|bGcc=-HLtKCZyL%Klu$vzT z76;F#fCC8J#${k&m<<+3)Z?(4`vVSfS5A=mFjbJYEy%zIP6h@=CeUhG5RZWY)TRcp z=5S(n=TRKu-*AXqabY*79fx{PF6{1X0gEHr8=$r}$elNEn12t4I5#(T_h{k}x5gpv zjYB+=8{~dWcdiACBicWpwmr!GKX91C&4b;YhB(9vaENckA^ru2I4du9dxLR^PsSmB z8HczGA9nNgafn;v5ck9(9*jf01c&$r9OB<_i1YDdcfTJF@qQfQQH+rC2h_(0r2|mE z3`Ebwq5e1y@pm}Htp%{VGZlyU4IJVog4oRo#34Qlhxisj?Ed` zxB(7v4;!W;%#vcyWY^$C&tz9uLnGwHlb!+I$*!(tA@RW$@xdiV25I?4<%vZp@tGy5MTsT( zMe!wx>3W&PMTvR_)Ugg~n>lT4b2jn}Hja074e(A5@(wnR*8{H-Ehx$_0J-1Y$KT1( zCqBNoG%4OQK0eCN$jB8kAdD8e&PJ|5hUPBWMUc_wVCdj-kf9+|y=PupK0|zzkCBm! ztD9q}Pe{CDaIkAgaC~s6Q-EWL2T0D)*u^`@F(f|BH7MBA-;W_aD!9bQB0fGdKQk}0 z1gydUqQcM7*A>jSgz$r1Lqa_L+=JuYJbhpiP-|SggOCjLF*1SK@8lTl8szVb;sPUM zn5?tEpPQ#U4oOcxXP;0PR}{Bf!gM+Y`(l>}4su48K-lHu=@gHq3sn+brvc0^7sn7s z6f+HBGESkMJ}%g$oE@D#P~2_=H_zAK1=Y)DF!Oxk zJSZxI8RDs%ZuFA#b5a=ee4GtHgb9c+1rcT-!W=|cf(S#fw4ouGZ3HHb!6aCRAy|tc zSdSrClc5Dz7Od9@tk(#v*9ffF2&~r#tk(#v*9ffF2&~r#tk(#v7orJdmN6v9n?cr% zdHMyH7#gHy=A;%^7MG;v!pa?!g2a*xP}ve}6z}TlV(MB3(FT(@G(|3#l1kHX7flGw zh6bg1nT4gP@dYJCcr7-K_sJ|SF^%`kEy!{83pS27GzPQdQ&MwMOHzxFU4+y1&ZeG@ zCh^I^hVibhLEa(pe!+(EW@-6Fxrrs9?B^F;LQ)two4N*<7@C1{d1hixW>soYd`@O@ zi6fV_iCOp{A03sOCkT`f}b6V}(9lX-dH7GZiAvZNQ zxu6nU;22uQ$CqRj<(J3jJ zMv%Dn#*;80@q-pA$vLh8e!)iZ&}d_bk4ni2D9a_s35Kp^48poN#9#J21V;(g;&GK&lHi&H^ngyxlJ=B303 zr52awrh>8uD7J7E;Le74!T_8zNGckfjR+TkdF9X?PdEgFyn~J6!R48e0lYj*%}X!I zKrYadD-z?AQqwc@;*%3gk~0`U4dcZ4)VvfFeo-p8JcNV?X`V79>?uD(LzmQ~(sYm1 zoPyLML&MCxwEXzw(&Cc*Tu(1>%El1^uCA`GWdYvF!KU#p1tB2M`URI*WabygCnXlA zIzzGssGP8bRHvEw#n>uRPyrDVf?N_=K-5EaP8F9Fr6%TL(+KGtfVBGsmk_YS1XQ)T z24F9<4C6tDpq7T@xWNok#zFHBs6vg8&xg1_J~OX4wWtJ}H(Y~)OAL)6UWTgn42cgh zh<6P(iw^*G2|zU+Y6wAn3sRn$mkzN4o7spULiHW#`jO*@l+0a}T9A{Noa&mJ8{nM` z%{}lm0;}YL^NkBiOQ21OeABd?(&7wIaS#<;Vv?L+3hH_IA-6sZjpKbG&5w9+yh7V= zP+#FnXQs(Hsfk6P3}F=SnO_XTC5a`_VusX`3)Fr|EH2JW&vOm(4mJU$en^Cavub=& zA}9+Nmq1+xH=U$pg{88DdXdP8hZ~Rr3u%<@prKiMYDs*4X-PaNhl3i$PNv|FIjA!V zDQ$2TbSYsVe;b1Q?Pq8fUX)pqn3R+1Rh*yamYI|4Z0Jfxf&t}1KU5bQfm{f3U0z~t zDw^vst+gmlEr|#D!!^j89Q*N>cAx;kw9?Q3WGAGkBGcAja~z>)Qk+-@t`?(EL&eCb zyeP9IHNGf6Hy*UuE50Nj9D|@R#~ER+S((^<081peTAI#=M2#%OrxfSMXC&sOye73_DUdIPK);-+{|^_W5INbWa55(kALOuZkHcrcRs5+rfZdLEd1&{|oLJ3-Q*O|md?*wznp z_uK+0#NwXkNaD!uVT4ZUfy_a6k35n%vU|dj#F71*2o(oeqle_L3?y;ToHWe+xlnPC zy`XhYF!3fNab)+v_6~v6BfIAslKL(rd%qxwBdcct82}9*(ApT7y_QJgJxJyRB8elL zlZGUY?9LV>ab)$NtzDpa1WETInJ)#M_ydU}tGB=*?tml?nmdQNKOadPIbI<1t&p`( z{YdssLsF0I{w+x2$nM#LBo5jo0kiiqk~p$CpOM6o&EbMh{et|9tX>6499g{|k~nfc zje?4U(i>=26y}~ZG;tSDpffNq6rqWO$`p`P9h!I&NRWYnp$knMwi0U^ns^;l{US7R zP#FP|T8Ab+7bM8Qz_1HV9CY>&Na`4xIBfmGB{Xr+0$PyzduZbOK!OYm46o3{K_?D@ zq`skvKLH7X)^@Q&7_jgZg_d`GXyUMSe4soI(t#e2pfz_eapZW+0|`R&9kMuRjVDM7 zWKI}T`UK@cm^dh|VDSsuHv$t!F8|kq1fk|5r;}|^age`|>!aOJage>p^}=7ZMOz{H)Q;^^l1Ld8Mm7$TVuTL*@& zJ{?It$enkfeAqlW$Q&aib6TMC=;m}o#X;&p=D^lmPC^nlMlxpwR2OZ}gEf+Rkb7jH?r=g92d$Te`3tmN3zT%x-4lKhBPE`OCOtnf z+L7y!#I2FcIRX_&H|I1|97KW4fvqpQ1QLL{#|Fuq7f^9@bKXP6K@`ZG8jzzI7#O~R z1fb@CcDcdAnFpi@T3#W?moQWuqz%N3ftn));y}%@LvoJ+R2FH{_)9<)XYX8tUwI7mHcO(9HtHB=m=-Vw=P z8=&Io>bFD1LF%2Lc?0CHvq<6~IhgrZq2eHOl99}Ztiyz~i$MDlVCtVh)q~7%hQ<%b zd;yRF(C`Pz!PHAY#X%IZ`H*#tnC7d46hh4bwN0SSB!*xlab)wOq2eG4+5BXX0MvcR z?$3gXgUkSV1?J9rs5po!KnjN`AOWa3pf$2E^>dKKQ<2o4go=aA4@DBc1r-NT$o214 zkO0(tOpxL7S6ObAGWR+ zWG}KiVJj^`;>hiAA&}#t@rB$T1NA*YQXqeUFwFg+IuRreG6y+*g33CWICA=o1qnjU zM^0~`GzO9anFC_O%!i$P0TNF`N^hXJfT_hk~fuLXgCf z)x+8sAbXL+ClN_KXstHP98jAX6h0vJptb5SaZp@?#6jUujFfI+$EbqDOOV7NyL~}> z8yFZs;;{b9d5|H{@(m;o>o>vHD}(GUMGDV%XzF40iy+kfFneJu<|U!x=;pxo8^F|q zB8gWZnU6ePgseUWhkDr2A|PouBy&Kgnt=QVau2fkuyz_qy*rZn z7LWkcoyh9fK*d262*cce62yV3M^0B4pyD73IbD4R2|&{cXwLx1T_E>~fhsK|aaee| zLd8Mqki*jlDh@KP3Mn3|k;IYX5p;e8$R3b6$nkg^Nj-8rDuEP2{e^5V@^}$)_*5dP zM;2dzL;NrfaYJZ*1d^^siWg5Lab)w;k;IY9hdih_diYF45=Zv$MyNQ*USxCjLd8Mm zAcyBEs5nSHa=msDDh^VQ9KUzb#9{IK14$e?ov=d3D?sLh+SIW0CXXbJ?9L!0anM?R zn0nZF5y%|Sm<>$)0Frv-aJ~)|2f4o+OGjhM<9D!k-}ju zR6WRFp!5cF{}wcHSUP!tB#!K_w@`7A`N;nIiX@KgPC3xwCD8I2*`3-*;>h7|4i$&F z6J!s_KQ>Tt5Wfw{Um!k69z-LzS7H7Gi6h$!^B+hYd7K<{Ry;OykoytH=77e^u&GDx zMfjt)CR^T4vK4-I7lxnU4h~bCXQ?l zC~UEbgTe|Xj%*HW|3A8WmVy*xasL)1ab$B~S5#YAaUgQl}9oMS-lyOII{V6NaD!qVf}1$^I`pL zkT|kA(KyV3^}j*tk=+UFXM@C%%>f+~1qxD-II??S{dJHyvN^DRIY=DY9N4%qNF3Rm z$w=-*HV0%U2!o_SML7EYPLOyyNC6bXc2I)K4UipBVFu6`GKdWl2VoE!gh69mAQ~hF z!Z7n;;{ohV2(u0XY!bPKFj;AY}}&{n#M2 z$a{ui{X~#Btn315fQ2(i95(j_5{K;z0*S-M3P9pBk?cj@-3;4L4pNWUP07G;5=lMi zJPeQ-APgJ#2B}A!D!{-X2@-(%3pN%3QlEk(4r0RGmkZ)R)x*kOkop}+;-K**kQfLb zL=p$72h}|w@jFQ3pzw#q*Ha{Mka}3Trh(L70GSWl|80mQ4pI-_Ppns5nOl;W#GqGP zQUswhV639loJ75n)QS=YJVg|5)UVIeF+AZXj<9bE;Ak`rA4D~D+^x&p| zG?BQ39lXK`$%NvP#G;bY0t`dpORlX%Cc8CY9_oB+0TuAU3qGbYVE%?P6DpWHZnrMnkiVXEod{CN~lbM~GQ^|l~Kh&R~ zHKFl|MMa5~PyuiuQKNvfW^U#Kp4*9nxLo>!^| z+MAbJR01bl zS77>JG^m{hYH~n_V?b7cG3Xdk5JL#L(S_t5kQ@kuP8tH41)94A@nN_CG#LoG4-9HB z$o-%$DX6UgQUf{%3`DCz@Be}}13*GxdUV^;M?h*p z8023N4Z|RJf&GuB4yGS!3`{xryfZk5fq@|i>LytK6DIcpsu8q)1SSTeL2d=nAUi=c zsErL`v!U6q096PYlLM)PVOV;C@e`qG5_ZlJOuPe>SwQEMLIptn1hq4v#=_6z0j&=L z+YeO-qZU9F8bQYyVdCiaFNWCVkY14epi@E6?FaQEvH8CMYCqxx5RfUDd+gnyXSt!rzXxdY43z&M+899g zgH9how|_Mb|4)G04=Qt@Mt~`F|1ZN~e*)BgQ2GLC1lbSr3%dQFbwMEigU;Ckse@rg zP+~=zpMZIc~iRSKqH_JiyM2`mJkgM}IY0Z{$0^;jUaAdK$+ zIZTi>3+Um`0j&QUv0G%=dvmaLe{f63)?*9W&i$H7AK=#5gD6PZTAR4re7~~gp z|9^n$huH^G3&J3^$n*j5IbE3khcyad=bnJ{fH2fp5EG1dGh_F^18A`W=-f+Cp%1#` zh=BoonjFkMF#ij(fX*9ZU_kf36R2WgU|;~vJ%cTR5-|5exeTCloIqme{$C5#{}HAT zN`usbm@v8tYCp7^0!e}KJm|pvbeKZ0C}g|=$^=uO^PfO*f?iG)#DS%u=bABq^B?H6 zJ9Pg~gxZf*d@z_o2S5)(jDeGA&S6-=!oUE^s_6CK52${aeJ}%Hd>FkLdd?%d`#nI7 z1+?-5H1-P92aCU*Q1>&VdjNFNCsO+n-F_G!bWRpH{Lu6#V6h)mm!jMM6ly;loS@PpCsp!z{_$k+s`A6X2 zK+0E8`yX9DD0`zh5u}~r0W?DTkq4!qZ6&Y*C;@5{VAHR4bSQ E0I$oFJOBUy literal 0 HcmV?d00001 diff --git a/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/extractTypes/extractObjectHeader.o b/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/extractTypes/extractObjectHeader.o new file mode 100644 index 0000000000000000000000000000000000000000..7f8540133153eb2d4da08bd642dab5eff2e9c37c GIT binary patch literal 64520 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

Fi;L1G{b8p{UpVdW)A4B9mW z2{VAkYCsH-I4tde_{igaAUW7Q%dmPIBnCYa1Eic`1<2vh^bDIr0ZCjy5(nvl-7EJV zNgOt}3sMiOA3)Wg>0!0v|x ziGwigeyFQR=77xSgT|8rH1UDdg2EYeW(UXuO(b!U`nyoR3zP<_M^5LyNa7&%&!GGX zP#UBjWIk*?%1k72ka}h4I2VInab<2vViJR1aY+$`&VaFsQgagZK*uLC=z)%IWY9}0 zE@l7==*36*As@4feB{1fQ9ejD$UH+m3kE&7DIiTGp8XF#p%UE$_zB%qy9Wrj4P+eR z20Cz;x)=DMI*35?Jy+!++`wMLcZb1 zd7-!@v8bf904kK3mst{@SX7i)iR35p&gVpgJ7N77u1diZX!&`ZwG1zoqmpqH0llB(zK7pe=sJO#>6&nwjf-KLgW zR00YSP>xE?h)*j@%uQv`OE1bV1#N2sRhbmwb!-d_&?9+J%z>>_fVJU3e9%}SwEBc~ zHyCi~hplITjW2`r_dwg(Ad6t;;L;Ckx4`-(ApM{*Oqf0xjY~f)aA0jLkbcmb6_`F4 zjY~hQ9fa)ueiGadyDuJDKS&H_FO0@zKdgO?tbZa2_QTrz$ofJ19bxvuXk7M#`re>; zLe>vDpAe=GM&r^C>n9+mAJAG2m_8VdOFw8W2grV8{h+ocOdpKKr5`j`fvz8P?jKAa zjK-xOG&cp(kL-U?zXGNYMuYmnpe8MJS`nlLj6Z-$28L;{jslbqYI8!FUt6uXzYx@bhA0J-Ape3HPy)1_7Gx$HnmU+%zhFOq1!(}O2Bvp z)PB$y3RnP2fZPgVg7koB&{+^5HoE-@&;?kaF>;VP7)G}rbT$e&{L$S10+d-87#LvX z7%2QfWeLoFSonkT88-VLK3>NK(KTOvLDpXL${xck%0kZ z1-kz?fDVIXU|@KQW-hw_Ss5X7>ge`!fEIl*FfeQY8O{K?e;njzbo)X3v_MMG?Oy=x z(1FItk-X1@1_s!AACMjpMhi{`b0%o`fh3Wz0ccSJ0|UbYkmsP`2RhOQ z-TmH7koZG4Hw1JzAp--0HmrXNH5+Oil*hmT8utdfAI*RU=z>&GxWN@;Nq@00_oL|- zfEK`@vyVXfLFRz+KDzr?LEVoY{|BJ4#zT_+N^{{sO4|$ng(4N(SBjPdMxs z03H6vz`y`KmI-D(M*0Kg4^Wt*r~emF`$1_Qq#5LY&{_+0`-7Mv@rUkz1E~G5{Tv`O zKp5TszRb|{gBJb_phb%e3=E+11*8vTKd7unw;wdl4T^vC^uGdXKd5{L>4#yMevlrJ z*l!%}e*o2=2U7@Aj3xbi!{PoFQ1@Fv^@H3GI`RZ&KP+5BSs>wu?tVY$#5(d=7|01w z+~3K9J^UYl7KeiJEi_(0?uXTtAfsUJ-wCxJ-Tl|0 z2_LQafx8>#ED2VK|Iyw50IDB$Up>f95Jpcw!mQZcuK-#+!oa{_zzNa?DZfE$=F!6+ zwC)V#7WDGZ0CYGW0|Uc*Q09Ob0VdJy&xF|zmPHT&phav93=BV@>oq{(2TF_R_BXOJ zFo4=M=;5RQIs}e^0e){g%w(8;7+r(Ieh<)L(F_a>uy_L558B!f(+3mpg@!*9G@fDh zI6&=(CS#Z|eEb|Ha2AJt1?WN#Li%~xAbw;@PWJoXGy3)2rO zvq5|qhQ%L@c8BUmw_gBS@T1#@&Ua$Np8gWBgg>ZB1k(=-|6-{9uz4exJ0+m@gYq0q z3`B#{Dl%OI)ejOw#x79($YLNiOh1SX!aZyZ44^hDTJSS?K=q@CAI$wAy&${>0cr(E8yq`8C#)ZVIw){aNLoYUg2xW9>7M{POr3#&VJlj}0&*|1egH*Mz~}$~ literal 0 HcmV?d00001 diff --git a/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/extractTypes/extractObjectMap.o b/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/extractTypes/extractObjectMap.o new file mode 100644 index 0000000000000000000000000000000000000000..f32b7c26ad3f30e546097976b85c390833d9807f GIT binary patch literal 81520 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¬MLh<8T&bUui61RvfCo+ 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 H8%#d{2Ax_{ literal 0 HcmV?d00001 diff --git a/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/extractTypes/extractObjectModel.o b/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/extractTypes/extractObjectModel.o new file mode 100644 index 0000000000000000000000000000000000000000..dc88d2ecbb9c4ac55ca9cc5f67d34a5ea638ae82 GIT binary patch literal 30376 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 literal 0 HcmV?d00001 diff --git a/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/extractTypes/extractParticle.o b/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/extractTypes/extractParticle.o new file mode 100644 index 0000000000000000000000000000000000000000..ba46790eaf979b019d6ffa04a09a4f9224da55d9 GIT binary patch literal 30352 zcmb<-^>JfjWMqH=Mg}_u1P><4z%U^b!FB*M9T-d)jKOMo85qDcKLZ1U0F*7vz`!8F zz`!8Nz`!5|6%%J*V32^aB^ekPq!<_&q@jFS1_lN>1_lOsC|{9*fkBCZfk7F{*J5B` z&}Lv@a18P6yb|is`8C+1^S4Ly8-Wy$ZWdJy1_lO?P8Ssp!vh|zmr6K2TEFqPG%zqQ zcxt}!=~PkiZ2rSv?&8sH?b-Z?vDBDMp7kl*Df)s)U!NgE^|7U)=Uxz28>G8|AfIP+k;yZ?Wc7E`I_|&8G znq!z_D9D?CLW4aT-)Jy0Fd)TIi;4sz1B2lKkIrxopUz(%y=zoHFfcIqbh3MNz6Xbp zXSa-sN3V-Yfk$tRN`gmcjf#RtcX5G7cW?zLiY-7yf(PTL7aRZm|L@V;q5_I%kKWA_ zz-iz(NSXs|kViL2D>Ozty0@qZFfuTBw0%m3mCzwJiAL&I6QhqL7s-W)VEtl1>}GQAe(#ls6bp$qaxwiU0UGT9SU}@fk$Tx zM27Lxi+_J1PTl}Yn!Q^g8o*8#0NVm`vIHy<5#eO4P6g=$o7_D`Wd_J;o$oz5=Ro|( z_~}K}-~a!8dZD4wU7{l3)A=1@dFLySUQ@6KA#n*2MG80$xYBNDn33avpMO9OSfg?P z?6!A4(0KR2YbH4SK?w$?y0=8d!Kb%ICBUQel@G{=B`O*|oi!>B$6Ztc^otV9J&wDm zc(5=qFdTDH31NWxrAEcU$MSy(A1JQ}c)%hT6k@Q%L9`!BR5Tz~gKhQL5s+9^l9`;7 z3J>c}Xc9W!qVj`*fq?_$lok~ZQ0WSGV@YKJ$Z4ryhq8iXT~tB|ITT;GBSNx7CBdUR zL?y!m6flse_w7zm;Q(cus^9hzt*e z-CI;ZsT-8fxIoDnmaw7O!@5Sr0Fu2RxdxiOKrsN$$F1K=z}gU5IKjiZM#TaWWd%r4 z1}RAp<+YGU;}K9{11ho|V;$oh;}3&911h0BIuE}DCG5e-_Ut?YcN;b~$lbUx$VZ(Y z4l^Vr7H1~M7nc-e=A~O%#rwu5=jRod6qP2IDCCvq7eVb&LV~GmT%~g@FMSONT-Ad8kiszJOy$Xs}1~8wsR} z0$iEx1&U_h%3Z!mx=Lx{26;HCnk6#>-- zk?4F6Etg-M166sQ?>xG}wt$sFDos!c2yw%URsa6~_vw7()A?RHUdX}ZzaiWLtzp0vs0jK6s*gbK#iQmL5o$IOp{9=rHCaTcaU(*F z5)o?tfvQ3Re!oS8nr)bBI^RK~9aPtYidIm(_kq=c5{6IbBS_-v%~289#RSSggaZn(qQxP7y+(YdRxG42Z#~hK}KAF8Ud2VY6LVaJbHap_&qw`?E+P| z2p7�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 literal 0 HcmV?d00001 diff --git a/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/extractTypes/extractSprite.o b/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/extractTypes/extractSprite.o new file mode 100644 index 0000000000000000000000000000000000000000..a9cb289eef7f363a15c20dbee59c47d658750d18 GIT binary patch literal 32960 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 QU|=XkYyW`U3(^O}0L^;?F#rGn literal 0 HcmV?d00001 diff --git a/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/extractTypes/extractTTGhost.o b/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/extractTypes/extractTTGhost.o new file mode 100644 index 0000000000000000000000000000000000000000..d783b5de16144db74bca121d6c97f853e686549a GIT binary patch literal 35944 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 E0Of`N5&!@I literal 0 HcmV?d00001 diff --git a/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/extractTypes/extractTexture.o b/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/extractTypes/extractTexture.o new file mode 100644 index 0000000000000000000000000000000000000000..1813801d02f0bb6c49c818f741b5a93b4950fd02 GIT binary patch literal 66384 zcmb<-^>JfjWMpQ50!9Wq21Y0wnVRqt!E*pJ9T?IX(!grv7#JAj85qE91t_h^z`&ry zz`&r)z`&pa6;owkU{GUVU{GgZV9=C>_eczz_yyhchrRL_pb*P&x`q$1*T5#DT*L zLO6zac3uhf==>V&(fQk>`Het|M>mTqC^S4eT~s&>4|ud*D&h2K{l?$Yz`(%ZsrkmI zQ$@wI`44}&i$}M$XY(J%Qe*yYt_&UQKHVxR9^KYHoyicA;y&k zcr+goh>mrPIm|Ebz~I~Zq~z*rnF$`9_dPnF8D4q;a*jtQvq$G~k8Tzfk4|R+pUy`f zo$tUBP@`Wj_UHu#ECW~&OgM&wdNjY`@aSgu=yrJF)4hcK0|Nut^a#g>8Wjr$kIug( zvX1=wN>rRZI^To!cr+j3i1p|^?id43L_VF*!NQ*1EGqlB7#J8ldPTvm>2@&iu)I)m z0xam$`TYL{{(T=_?*uF6mu~^7VHoP+_nBYr*Wn3idNBWh_>SR@VUD4WA)&z@&2KV1 zI%`xUP*O#NN9P5PgD-6OTR}nK)2nh7M0<9A_vpL~3rtYz(eP-!&EKNL$N)|X8pmB! zct8q$dUI3^JQ4wQ3}OH_C~yX8H4 zdBL`JzV~7L%)iZ5 z0UOG{Etrvio3Y~#P$A^g`O>5FxM$}Pu#`_{DuZV?yHDpU{%ysK{M)SkdQ%J(z)~Qm zdvqT1>3jy}@^5!$1G)X%5f=UyssI1~gXF<7FM0m|{}0L!Ag@FqGK&a^ui?>rBm@cp1_r|e9-ZbsozFZv!#SWC;F!ArgHPvwu(clD(jL7nDhEK3*}F$&1BmY2 zqcQ`OUAl`4Ji3D`JUUxcc7XVuEf9IePcQEN`TrlJ?*d4D@8$_$>Ej@kASTpgh%r8$ z|DgOWDic7?ZT(il>(RRh%z?^4-0su6MWum>fx*Y}dx@Y&cMF(LRce-CI;Z?f?}!oh&L~OME(idGvxxc?RUN#sj1h>L^Z+ZX1YN zk8Y@ga5%(8rND7_NGb!vF7{0R<363=_pyTlpgV%Yqnp{Icl8Da1_l@YZ7V=D%#Ft( z-bu^JEJ$q+mx7&#J-Xp#o#lm+5NNb}v>qst_2^xr zA^?iC&U^boN#CRM)&C0~-BTcf-BlbO-H<@C{9Yp6V6VjwE)Ky~wjO{K4B+(W!oMw> z1C*ExV1eb*ks*L1=6YLHE`V}w=W~!xK}=B2_3X}3;Q%F>6(Dc)wy1zgc#wh{AX$*u z@fMW_NNkWihznBl1H^!;0XGOh>`oVz3b0cJz$L>pMqiwt#1M6@7U!v-v3ComwpcZaX0V(v*{O8g7 zzl0Uy{O%Z)0*`Lyh8+o@6v^Kr3Cbzm#jtV&UWW9xs5pS6p!I9-9F+htx9Af%2fBc& zffyAFkIp#|b)AP_#C(SoARv>WiX0%8cHW23-7YExpkhJ*WK`!K6;Lz9qgw(L$_iki z7L^WAq$8D5V5N+oUfBPD7;XSkhg3SbsCYolE>TecrCX4hP?0SvVBOtQR3yN<_NY7n z1t2H}K{Tkc^kDo1@&ZWw#T~Hw*QhXn6nB@Xcp##%MnwX-%mX{3^;-!SsH%h6zXxKQ z^&YSvAf+AHSMW-&dy5JAa9Y#` zQ~cW;m^=>tX6j7ot|=YNmxVh*TsaFqy&4roNd(;uQr1Sh`E7Dz-getL20E5rrh z_{N&(AZZvmZGbDQ)^DIT5%E=zM{|uz0;5NF0SAA}d|`OA7M>fsp_O9y6mX>i$}kS# zh}xrK0HQnhsGI<098hX*Q8@r&cD8_}Ua*1uKt>WWybX2~!#+>~^4xp)t42)!p|2V~ zy`Zib1Al7|3j@Q;Vs-|GG+2Aoqq9dP0OXo(4*?K60m9}u<{-cT;zxk^odO=m9XP-V zrnd!BrgXZ1$`NRJ)7=6w!`el~fWM`Y4b&DwNP&&)gzD>VQ2`lwtVIPR%m6A_L42^; zoh>RJ;B4%oVgM>#!S3p9f#knVa6*FSK3G8q5rnk~_ds1yqhbKb7a%K;+AVuj3P8TG zu2Io|$Txtvh~Per-CH09LiZG~C(v3&rk_EL(h?O1 zMBAqMHz$8vE-M3r;Wv-w-^mXA(~o&HA7cXLQVvkg6#z9lTEI?%W`{j0Ge8akr3*#| zhF<^wAbn-F9-X&54!&aY=)BcV!j6w%+Le{4&!bQ4p4~{0rHmwC|Om2Jkluu zY79bC7AV0%O{X-T5bayyo06#24!9Ts6`72mJi2vmz}k*4@;*YM(E|~U-6bjtuq+QQ z@SuHQP%MEGGfAZihAUt;gId-fKM=4S+LM5E;X99lLlabXJG8vzZ|N3vlm z&4(F1EJ5wG7DZ+T1`lv*e-G*h!BczlF($)HNcjZpUQlZQ)C32$vOu{Fn#%dx9)nX1 zN=m=#0Z!>}nLHR@5l-p7t_B^D#0^j6pw182*cugq4mOaL;DWigMFpJmyQipFfTdj^ z?PGB1!1(D!#{2*OJ$C$u0DBM17I41gZ*dR+1#yjv0J#2!_Hw|!^67@C0X6VJzT3eM zYKC|BfOEG;=W!ov9~BM{e%C!aJ1VD}f`QO9xXPKyvNMJ0m2&6%HpVHXRixPbQPI*-F01Sxw#WrPo?G>6qPUq};iGjx6OWS|{|HJFA&;0oj0{ohD zR6zcDIr%qO$^}%x~$&o&iQ&w>&j za?cjjh6Xw4IHYRUFR3gz)}j)^#J~Vn4yuY-8Ni+6P*Ar660@*&FRbZ_*6JnHU(W!S ztOiiC;QrZ}n~3nwu@;puCI*HQboZs@7p1v$_JCao@(;*?Q2&He$$?YAjb3P|{`1(O zUzD1cl3Jt-3u2Fhk61mJA)}X_konn$1^nlzVAh((|P0olz5 ziLpK+?cQIU%D}+CZ3?(64XVC&=qKmr78Ioxr*-ZDdkh*F5cj~WJ=UVq1s>#r4w!I5 zZ0#n}R&XPg5!UbKZ#xMpLb_d40@C>39{|@0aJlUcA|9RZ;NgE9(k~ZbU|;|Z`0;N) z@QGjRz$gAVP)cP;^Wd+8jN*X`T2O~QjXxhO19CVx20H(NJ>=0j1w5+7F9_0T=F)wj7y;P}wjY!#U~Wz8ED-SN{CCVjD1~2;0iRP{Iv;Q<{!F}$>bg}*g}m4RUe6Mw54h-Tz()nf%Ulp%wSpoX!6 zPv@^=Ei51hgU9kMz@9taq7uQxz)+M}pbPR2sH_GT1|ScXgG4}u@39t@7$ydWVvrX= zB_hZR$68ckLEeIU1*{e4PzAx%jPPm$L9be~K)fmmq8a&H8Nq!5YI?PVmR?0ku&fy2LWp3+!&Pr{%y|8EeH5pyBHZ58md_s_*+3uAW-))U{_`p zIAelSk;iWR@}kU=RNZ3!?G9pTom0TYy5S{QYHd9Ls%Sw;kALbRXu%Gz%1ABPLEeR? zx*C;?eW3m$l)FU*JRk!bMk8SWu0{nhd;}hFZT(*YZXbh3QIQ5vL8Hf@QB$xaXuujV zy1GRLJVOGW^61_Jo|J&P3p&?gy$3wE0%>+ZW?|sXF31E9eDa9DRR@%&8;^h{eUPS) zz~k}YAm`tA0TlN;^@|I@ArA{`P|p_>(8nNc2KamfC#3r9M9H(D@*j7DApmR40QYB`C{)Dl&XF@we;;HB-^&dtR>m`ybM?^z1z9gKc;nG|CT|HGqw- z9|R5hK}OeK+P(b$pMM*Va7T{_$VD&T|Nj4;zGS|>!nqxlfi3P%2x>%ag1e|@c6 z7+N!f`xPsg_*=Gv#Lpp{aOf9y6IT7gZbBDG{2Zw70xk!kqvNP!M;N0wAmyNeUwGJp zhUr{X9A0ESgtX;BlAvJ#kIrKt-$F;GKp6lus?oaz(zolK1Mbp!?9k85O-xTM*7xWv zQ4s*;IB;*W6VlZ@)}pe4k%7Sg6iuKp9%wYJ1P$ZC(c{cIRZSz2zF)Ps7^)E?|W?zMSX9_Me#_ylqx zqyq&XX?z(35`_%IfMX9#cy!)w9MZ9|pq(6cr51N1W=sb)xJw2S* z$kXn_$6v!VvM7omQ1J>bjX|R!NCAYL0+89bEJId<$p%d;pyH&&6otgR%J}5O;u4Sy zI6py}?}uUh&JSQFhznlt0d4bobh3jT3KoYENcuxPI{$ifvO}_T=X-GDCl*}?NPY8v zmU2DlpnB(jk7Sme9*igK{y%_>12OS$3*+br;PB`c1C7HSX9HPv7(QRqjVgbbUmi4h z%HYv_jKibT=rG)^Ob9=K41nRJ#Ny24_~MeH%)E3ft9ak|(T8h053&7nvW`YSiUa3>)EZN z;?erHM8vbZL`5JPG<~o6E*84D4AlNY_9-ZQL2JfP?Q=r1uT;SUJSN{;3!68pWx(kI z4Uh{?!(1SR%>|HkK`?hXhWhm83qaR)p)Tvf)xASQJ!B}btUiIfJ0A8-wE$q?h%mEsP05$NDR{hy}G#`-wS?(Bn7__kD z;%jN}dOukI)1#Bwv-2p}4ET~iALu&0*GnK)BULXGKx>MIg|NlKY-+6R{ zO$IB4%%J!n)GYt^|G!V?BcIN9uqkjKh(n-;fIQSpgqnCF)L7$Ensg%6I1`~po(MI+{}A^3bt2Sk##Gb! z4jS#C1!|zx37~lI2CI9AlyG)|x>2BYuaF3VB)Hxhl?aFglBiGb8pv`MXqTY31>7?P zr@W${pjJJ2T@Gw7C3u3rvjx1=iI5TC z?rU!gc&Qb{i0`0o97q_f6;x${`@fK$3#3zwaEgnHzDMW1U7(RDkIsY8b|lCT0$|-B z*MOEJc{ab(@a?TbnzQ^4miM&0SNa$fijeT}=`8^*`vK=)u)Gg+nI|Nud^*qhbY6eK z_xt~UADGA^kIwf#o!3A^x1eb>ur6o@1(imReu312hNnP_9(_8`y}0lT)RO{d9#F_0 z1aZ4-R5+lTUTgpf^tPygmhVBuz{^9AznBIx3tm1zQ^ku0ka|!D4667=K1iS!y0Qx5 zuNTo^F|ehe4D18qf|sdw-t*~vzYEm!0=pbmuR_a8kIq*f&2JSvEN_**@j)a+P@x1V zuAp{;eEQ=j$X_)o0Z_3Q&wqmQ#CIqcTD-ov2vUaZ-veL)(2`k@TfT#Pz+kudbp8cf z4s(m;-O~4<@n2AR3m=v!mG@{o0xFWhCFM7t&i9aN0kpIg+zJ631*#uCJCA?`(An6Q zy@J#rizDkr7RSa0wP!&3UoQXo|373Qf3!67#YC)+AydDG;2~hPO zpm2aG0Hq*MoLi@YVp5+0O`>Jpp7mqT>&3PxS5quR{Ub z2~rRNXF+o!e913l0T5goF(w8taX|VZ86Cu`@aVh?RlNsMq=2T(C&1QffjFQ=!w_Xq z&%kCeU(ei+7?FcyTWFdDE&YSEf?+LKP{e^I>!9lhUe5%Lb%0HUnFewZy60b-fL32a ztpzDSI39=Z&`rRw<|PxzNKm#0+x~hp$XN6+#n1&(gl_c9E>K$oK5hQ87+jS@#t>ds zgXJJgrNI_~);xm755OF_pP^oZ@n5=twLuq+!A13uO;$wah=9~X4FS0k5v~nCCJ8*Bm>_Jv^1zg=j{r&>118q1Lp88)}f&Ggd z0vnLMa|GF_8n995@wo8M|NjgO|Nk>8IC zx0V^Chy}C*>i>U60UcHb1`}2{1{+p?h8$3Z%)sz}wl1SmBfz7#6Ux9^heE!Nxj)hv7CGD+9x0Hr5q946oT(e{eHQV`pVxSk2D5g@<7? zJ8KIM!xeVcIXnz&IgT?jFtl*7zTsv#%w@~KFoB!(0XN7itm3m6!5){gU}a!%54^_6 zuma?6hKr1>*BBXoGO|KsjaeBOoZOBvGR$CPJZ5Mj8;!`m;+ zu%DOpr!d29Ue<-e42K2E`-K@!3xY%*3xZU>6=dxfW_T|In*I1cTar=G@;c)LCdMU9 ztSgxqc7OsDGe>sUQdKXJq}##Q2uc?H?1vOlH=L%nWBhq4@wrK-Ku$GbanG?faM%G(S3=5c8r#Un1VPfraX1K(}y2zPfDGTcc2ZohwpP63R zGo0sSz39O3gp>8C1H&6m)~^l>Yq(e&9YOwi>A-M{i}kJpLq9j`9$SVb+^idH88&jW zF0o~J#l!l=o?#3Dzfe3^OEHw>mK_mSBBg%kWDAB;Fy(`oorCswC?bTZXxk!Y6DQZcDMYIx#fM zu>N#p*eJvL#+IR9mUXTZ!vZA&hDX}0XY3f(>azAa zGR)9tJ?Y5MZvd7xV14Mw@Y|4ei37u8Bap~L6V^NS45v+5FW57DH??|U&v4NkB;IJj zI>VM>mIZ5%1H&f^))@{A?=3+he=S)L*fDfjv9{PTOtoU2V8`&r3MBr^igk`1L%TKW z3Oj~=>t&2v>=@45u!6j81M=Q;8<2;8+pxZ{2W0?(MW8fujgj>>Bf}R^5`kn(^$1Y!gOTBG(>TX=LbN5k7(&@me5co9UuD@?yD7X7sr9-Xd` z29!tV`+XS<3=FV=B~Uf((QOVI(%=DG0ByIz#za8!pz)9|5Zk^7L+X^?Pyz5>r1u`3 zp$wkAA}l_=sjy-lvRe<-I0pF{)QCI`GR3p=$ZH`G!=v-CPv>*b&N~pJpp_Y{tpw7; zz`&54mp%&BpwH?{$cPq?hb0yfM@}bDIS)G z`P;#Z!dq{b6nJ#r2XCB%jR~(RtX{@_C5`sGaK33mR!DW$@?@ ztz;wZ!0 z9>?9m&Ut+k+7$zb79{+Rzm|qDj=m0pGC=(Xux+s5wESEW?AcwW;MrRT95jt9{A!3_ID{Ou;-)rOZnS}*apfOal=bYA!D{Nm9G zj{;Dql*6-=-Lo@Zz}NB%f6H(1aM)qcZbbo)P8OBd+VJr@N7yJ>^HBxR&R37-!wTTt zub!6g_*?qG%P4ahe7aLPJbJ4IJUXp?I$!uOJ}BYzZGFq%G7%)-nW7>9-cTzH+D%)s z7PK{X!)s;8xSdD0i3(`WAG+BEx zg`>pAr@KUj1JU96;L&^lyup*>^*yjM&u)9q?s6g$z(p7DAO*+b;?$C2g^>LG9EPCO zvdrSl{5%B{hLr50_(ZT&d`W(OPJD4{Nl9j2da+(saef{{X>q)vo&iHrVsUCwer~Zo z14OAlLn>svShp;-NS`4yFFB_)B^4x_tItqel&sH?lbNKSSey%CfJIUgOA_@Nl1ejk zQuG=0k`t3NQuRUW>59QRKpJ4?z^!8la&>g^b=AvFVF+?}ax^ppQ^rONo)!$ACJde+ z5l=@822V#524_zYwqOVea`X!ha13(w3t{jNa10D}MHY%Tf(phPF*xTW<`yu77bO-j zKs+lQZD?(5oXY?m`_9ZuSAdR(Gw3B{<}swCCY7e^m!wvdloq8HGw2oMr89Vfrh64q zGE=}q>cxp=sfvn*FvK&!W{1J$pHDZtZ|i{)5s&V20iVv}KAOj% zCA$j)!(p&n409P=gM$2ntP~ieqYZLF2^5M!>BTY3v-2OQ*!=1k66(?T2DD2PDJw(f znhg*5^romNcz`ww!^&=WXYf5Z8G$>6;E@tA*QXOcoC#X84Ba}8sRyjsqw}dpZwY9R z2-K|Z5ETwkWP_7HHgqC{O@FYE5{pAMDY28I%f`(MIc6FoSm`gI2pU zF))BOE`zsPbsqQWtWj|Q7t-K3fzDKcmP3OUuq*)WYUl=!#bH z@PJ5xRx(t8R!oA5cF+PmB=!U(_6#KU0vNlqhXrCB*cOmc8lW*HAbne(@VAt*ffk5CT6#X6&wM}=QHLPbf$B{?@D?s;&IK*M{qE5T zkwzXvht)vffl6q;fQfl@8+&vIbAYP!0*~Grl?2f4cn|Q-O&1jjP~u8}Sl2rTyz$ki zcL`*z1L(Yp7!}A!8ML8n_zmQl7m!XG187Vfv_{wPKw4*u3V7>dH@J@tQuG6+sJr3? zNFivJzyl!-+DZuu5Rg(1XdwGAf_FoMcAbKyU^BST#`|%|_%m3lcMW*d4Q_Dr0Syov z3{(}!B{49UK(?xbc5Z{lHbLPBYSV*!0vZYi z4UmEsQGsYs>IRF0w&Gu5W?%sAwgGLY^aTk>g9I!O@V5(r3aaiN@SaOZS@zyj^90yI zpyl2m(?LsyKqev*F=X(_1Gef4>=gK_D`*PohVBsut>pscLOiJgvGouX7l@8xcMYf} zhQ=_`Y!NK!f=0zWAf*;4?jfn#;RUF;0<)nm0qufigl>ih4K5~t&he0doa0e|WLpbl zEoQgF3yQ43S`ULJ9Y6&YC|ba?GRGl~ z1qXlU9B>Xk2F)A(jG%KR4)C`ZgL(V72py&W~DUqTB zoQbfke*%qfgS`xk60kF{LN ztVYEEDT9O5LemXIe>bRHMyXpshvj&{t1+l5NNon%;|s2JAn^xw2egFhY=KszASq}a zh=^LS>yNjn!0JM%6IxV26*+twh`;qUC=oUu*}=@ffYj@N_fHPIZ2bq?YXv?~g2A)% zz{_WU5PVq6%A?yAc6J5$cpeYPVLkjUFF_-@o$tYC^}M|E7rvgY8+H zJszEhUzflb#xO<}!bi|(09XFtm)@WFPd zTVOW8TBEPe!z^!xFpj=H1!I`Q7zOaW4R;SXsY2ZYW+O#5$O#-sX%LhcAZ~*?0%Y#% zWgya{^XThEAjZpA;7w_Azd$0qFxS1b{tudsgjVj|pr#&lY7~@mJ?S7Oz#n<0;+7pfRZck8VE;!%Lo> zcRV^zcziGA@U*;IYVFba*~ju@>21&Ma1IaaV1d$$pi{5}Ks*0EyY0c=YCTZ82Q;?g z)A;}?5vNUXHGJ~=Il_71{t|e=!lUzVut(=-@W4>>KSutRQ=r)G{NUMn1#*_sB~bIR zSLZ88GpxVh)A0=r;4{cC_&L z{@Jsa<%&nQ1!%pwwMVzON2eg@w3ki}kJfLcSHP>9x=T5HEU%YvdK`Sl4EB>pXDkQk zP$Q7PAf7rr!K1rYz@yXBqtjQwr<22@*^;4z$Gel~h-c@8*B$)w3?RCJU!K9IH{HPF zxVr(!^}d~tUWS2(AsiSy4!*X99uoq#0~BAdUK8lREssuD4I~N3reIitWq|gV!ola~ zKn|ty?EDf69@%VuBjM3q#^Kp*qk`0f0-sq1HV`~&0$N-2y_mzN^QC9!H6PGyICP76 z>wyvzk8Tanx-A`#URMndQ2#H*Lt6xV_8EWc7f|dp!xl4v$_336D-!4iCmp@Q%Q7SI~iK3?ALi8laK7ouEdbM|ZFUC_#A~ zcLfI;Xj}>GZja7uEeA^VJ-Us3I&&?&dU?KibTfjMPT7DX(3Jti?bPsSc9vj#=?D&H z7tn5?nFXr&KcR=H+;$UI$GBh$WGBz?XGBq+YGB>g?vNSd@HZ(ReHa0dfHZ?Xg zHaE5~wlpy?F*GqUF*Y$VF*PwWF*mU=u{1R>H8eFcH8wRdH8nLeH8-^|wKOv@Gc+?Y zGd43ZGc_|aGdHs^votp_H#9dgH#RphH#IjiH#fI1x3n;@FtjkTFt#wUFtsqVFt@O< zu(UL=G_*9bG`2LcG_^FdG`F;{1RXbs6dZn_WeZ@wep*ptZmMo#N?BrFa;k2Mep(J_ zJ62*|Nv3XMPG%yMU!0nosasN%mGjf(-!??#|9u3L2qFrFkW#3WkPy zCVB?ChNWPxVV#kYo`H!bR2Zb10W?AaDw05Tn7dyns3UU#BnCsdUpF%T>JD&kl z92cL0BcFsLpMVn|hbuSuT*y5j4Gatn6(Aa{#}TThkPEET6|9s2WIi~pGcYg^Yd+{q zNf}Uiz`(!&4tzJbn;b!IVshu=lW>Q+2JSG(S(G7AeYGHWq3er;>+|MD(g!-PvInYf zKS-YwpFl5@8=piEvm>8E8;c{KMl-7mp951m7oUbBI4qpNwmWh&fWq_yR4*u=LE2$) z$5<8M1CCkt*&tzQSp0&{sRW(32@(XAd!RJI;KnD=&*a1>(Z}q>r_jsd#HZ22>d0r% z#^%Up(ai3`w}6qko{@{s!jaFwkx#>kPr->#0`3Y12GGh~a9lvo^aPv9w}7#ky^XDh zwU?!jxt|G?HcFs9XmIB6;S*?P$_J+nkQ}H14RVtohybUXTCg0*k87a%Btdcv3=E)i zKwmWZs(~dhRo}ekgiI2mP8+2wT=)^6M_B=+Y`T$fvyQ2CzfX{)c6RVG% zxWQ+Df)-AJ%=-^B4;+S`pfGg98ionX-nfDg6eplDSCDx=Y*6<(!QJNxGS3s_J`Yfw zc!1)>i*Erl^JG>oJ_|35IB^AS!UM$#4>a61!orAe0W)%(fWnpo99awupz~Nk_JhLK z1*-2KOrIN{Kp&GUpF}USE1yCSC{4Dpy7N5%l_j9G1dG>qNa}k*>Y-`ao$mrO$d7ZN z<~ngf{Rj>-v~=eJ@}mpHk002XKd@ts1rLxPJs21mPC(s1736qq<{_tJ2c|qOJ_{F& z5Od~c0G$zQ1M(2)tXQNt?FHovs6Sjlc@b17EkVnR&@@p4)&CSpe?OBuC`};p71)2^ zeC5s;z?6*DcW&I^^JLFJ&0D8PD7?VtdGS49W&SFO%S1>%Re*-q6K1HHd=FTW(*&qq zkO6NYU|;~PZ3G1?J`5^;SQtM3$EJpv0hVJ?WtkaZr4+ij9I616#|$oEpd2KM8J=p9 z1Q{3@n8BwCql$re%#d0M#6-c&;1h>Ygcv~Kz=Y&}aQ(r+z|hRVzyK15@nPlOQK&fR z1P+i%FnJK0nE`Z)F^GkVnZYF)su+mJ%%BINP_Qv0$X^4Kx-yJ<(R>_56VHJm>EE)H6sZyFfhCWyHgKRpM!d6(6p+>1o1EE9668)i3#3F3Dh^_UFigD%3n*V0fL79hgc(3}9hdvMTmh|%nYEDzdeM zaWz=Nhe{|w#r4p{)u7^zXyTxyiwq173~p%RMo{$~XyTydfgts5XySHI^`U6uE@1I! zsOu1v7g#(7Apm6sK*d3A8>kSN3WJKn(kobyfq@|gEbhP{ie_&TR9qTO9CR`V149f( ziJJ#iABCpA1S(#LCSC;=*TgWV0W1zaDFo(3Fx?6khvf>e5SZwKilh6tA1W>lR)rv@ zK*iBZ;+ar!bQ|VD#X)D_BTQjnSPT^pLKb9TU|0zik4F<<4;2TkMMIX_3Kd6QlK_(6 z4HYi}aggvqsCYG!7>IcsDh?T?28lrMS*UmygbODxL&ZTWe&B)(3=B7+;xmy285kJu zL&fK#i9dykFGdr84HaLGCjJpBz8+2dJ5(Gt=?9bk3l%>E6M)jp;Cj!20dy1+R0vFQ zLd9VdgJ40>vByyH%P;{bEeaLC2Ia#jX{h*Zm;jVkgo@vX@?n%ZRQxea07~mZ#gWHg zK~lz0anR%gh!4Y-Q1S0D0Vr(`6$kZ6ph95E6)MhymcP8g;?`g_$V32G+! z0ph~36Ick{l?)8i!Qz-L_Df)K&@BpZBftzbuo0kM6qpMqCW6IbBR_CqhK(Gc`#KQq zbC`;=U~xpL3bqckxdbc@>s2x^z{ZF`oeD(;(2W=nv%v$g3=9mSoDAUc42UR#)Zhf! zi)oGnSR8bF2t+M-ya{yA1`cx)!0KVD5Mxjaaj0L8L;N)k@lQC!`MI$BO96+t4i0fE z9OBV9#EZE=;fCmUfXA{J7#I%X5a;IxsR#A`A>j!g!(w1yaO1}A{w^Hq58_aNf}4Rs z2-Kf~jsd`O!UG)QKcM0QQ1zg(Dv-;pco-NInLxLufOrfH;N%LrYlR29J7aK&*WeIu z!XbVNhqyd1c6)7bh&$piClrVJG92Q&aEPDe1;rzxzXq$%+4!)#(+P)oJ`V8)KJ4c2 z1&bs4gWz#I1_p*-U~xo$5H=#<&kr&OQ+x?n9ML)fjqibC`aVB)_j3qf7q=7unU85s z30NF7+5<9`fdMog2x6VUVa`_^;=+R1?N!AgZi++PSrFt-O!rI&izE8Kpm9c!JDG$) z>M_N0g%}uMc?F~nhO0p0Fb)zu35WO!9O4IXh@ZtF&MpjcC!+raE5X%qh`WQu5&be) zJ)a|tJ)GCz5PyP0{4Wl1TM_K$yWO&<#>Jj~YTWCA9KnlD1avb8bafok`0-28(Hvo+- zgW~afmOLWnfsy0J?n*;V2IE&vA&G$YHlPP7Y)~=$1E#`LO=kG#u*h;t&sz z$8LTD4)MJ>#F-SZn-hmaya9*!103R(irCE$!y#UPL;RQ`XbuW=YaS%rVB>qY6|tvV z5haj%&~1AV^`N6RK`c!r?CuG|Ar9Mr0^OgXmt0W55Fh0iTw)#{pIlJ^T8Myr1d?ZR zaEYN|az3W&PMTvR_4DnIHB_^qPDLL2-cMS?IF*JraA-}k!C^a$HGbBF5 zAl^0DEFNJ36&wt8uQ?I!CBrsnBhO&tcvsf|@8lrwVB>f_@HtWiMfnBb5b!aw2yu-F z2@P_Mck>VObqtC3^b3g(@sAG<3G(!F2StgY33NLRG^&hD;?q;}K*5>at z6lP|S-GiPP!HJ$3uCBRy$@w`c4DnGWhVk*mC5a`O$?=(anI)NtIhj?7C7Jno@rijU z@hPd0v#mgUgUn0}M;f`fx;cjWgv2`r2fKy@#|MWx1vrLyFvLgs7#h2H2RVkshq(p? zd;0rF(ZQ@ z*8uc9ziud(*aRuojJ7vL=rXP9= zcQ$ejGBkI|E`sd13x;l}3o<^<2Yw0x*;cOQQzN1yok;?kse&-nN#@(g3p^Kmu= z5hkW!(hN+RgGmc8X$c}t!Q!T1HKt(oreHOuU^S*-HD(4Nl_thu(gZ}BK~x%n*rs3+ zQ?ME^0pWwBz-EJu1Dggm%n+=`5Nv=U*Z@PY!G>UMhG2&nf;Ad~bsB=T8iMs2f%O`J z^%{Zo8iDm1f%O`J^%{Zo8iDm1f%O`J^%{fq8iVy3gY_DN^%{fq8iVy3gY_DN^+F`U zT1~)OO~6`Bj6ek#`cgU3Gc-uc%t@+ke&C4t-O^q)oDf09SF2QNBX}nKn zafxZXXKq1`t6#8jyrD6e9iNh#lUkBmgzOQVhB%vgI-0~M2OGw_x(0cN#QOys#+#+( z7v(0FfC^B*;1Z+|#c2vW44h3}gG&s}K;<;JK1eN!&&ez<@eDSKcLi5g)QcsYR+)mW zGK+^;WoQ&1mI~Va9uL|u3#-In!R?Knl1$1o5=$V7$ve2jG`Xa*Ak{P3)gmQ7zC1G} zHP1B}W-RhjP8TDvmXI)X;~spez?+lyPES zrJ;GeZ(?3zdTLQTcyVK1Vvc8$t7Uv}d@fkn)h{^SINra&HNZPKKEN+H-Xz|!C><1? zA)ZMPW8f*&2swq~PM(&a78&?J0oS11T!!4#+~k5vaK&tB86RJgQIuaEpOc@SnH-;5 zRFq#7;GN6>ZX6_M$0uiG$EPJ`=725EH!dhGfreqeXCtj}a*k_&U$9X; zv@8IJG->%3oB)eUigHr(K)TVZPngRv#GxKV7bmSj$>0*MSCpEj7ayNqQ4wE|T2!2$ zmza}TQW;+cYSQN=g44c*pP31GXSbm#=u(#WvecrI%;dzJoJw#4$ty=yq~k<>$HvWT3j-5}c_)E0#eX zi%+gdgk~^Mx=$=BO00~}OD&JjNzF?y$p9G}OnMK?Al^4VC9}97zc>|SNoZbqW?o8s zP-<~$ZYr9QB-CM$OcWA^9O}et2NzJF5)`2&H8B@QtqD>L%B?y1$%#3s;N*+i*F+eS znU{{k5NOp4O~gpSNP=ca2@NW_saS7A0+Pyx!o7*J8h17#)EL026;dua6Sl+9B;Gf^ zxF9F9BtAK}prja-{6K>QI8AmoB;+WP3R!0(qFN|8odfr1kaw^VsEq*{lYrGskUWW8 z2ZC~MQfhi;UVL(5Npc1QXecBxJ~b}|gk2LQX66GBvGs&*iaE2UegNrIw z;qn#2s`!-R{P>K-yp$Yhfn|}IUkq;JnRw=9mOxS>v@7TD<`(Q45+CB|mOx^H)S!YG15VA@Tb+n}ja?p^eGCmYfx}L#6jL<6`;n&B}L#eAh^UNIlmMX@{qP3bcikp;5lH}^jGZA#3)BO#grtVd{9HxY11eYN7fZ=tyVLZqX)K&sHZZHGIX-+CMJ)`;w>ON2!0v((L z8SKT9gdi;dO!ttkA2~#c>{JmM$ZZ0T;L&_a^tisye1OwbOIVUx-2vijq z#e3!#gK$Y=3AAK{r)eVH1Y>$smNi9jt%rP{G4^GWVO)fDk zE^!Smu}Cc}P0Wce$@c^e^8}ZeWF!`6fZ2Y*PVt5o@xJ*f@kNPw>8bG`nasR&SCE8} zLA*<9T4HHV2}CjlEDMtgD9X%DjW0?C>4-1L&&f=#1WOs3BfJQk;P6Q@boEIxa0St> zuC9ilfKCH7ypvMX@{3aA^YT+tU2}ti&Ep|m?A!uKdN4FVm^E^P3lv(AaCXfN@&<=c zaVn&~FtUKPz_9g^K;s0#C5GlGYCtstNCG*%SjPJ%7J%Cj6o#@Ha-wtuCCYf*Y0)em zl$=57$1~Urq858njK`T0K{D7AVm#q=2u_We6|OByTYOSwNosL`cUdmD zf9f4vVgbuoMh5X%tOGag^HNh&pxMDS7ornokloNMJ+&l0zqBMCRL_A1P@PP{vxA`d zELd^}NnsgkO$h@PNQNL+hIp1S6qghwL$U~}4W=L)Ku6of=clC=r$UGG42@l~i=dMghP{$I!sNDzgC6Ofxi1Nrm3uS{$EVm0194 zoxs|{I88MInF{i4USe)4T0j^YxMk*~LQOY^3>YM3<|P(Yf`bl=`9a=z8xWv@jVM2q z_6NvUu4S$knR&$}pk37veJts2h zBNNamhM*wE*)IjPVf;{%j3LNn@u?M=#U;fM2jbUEdN6@XWXL&+pv(&{B`^cY&;S%l zkSP#|Ge{1nU~^EG_k)Lqp#dnBKxQeBQ-~iH+s#0>CxK4U%uI_fDJo4R(+!}^gT;JH zknw3b`H3ZDnwyddifBxSLt-41?y=YkYgA!sGY7dRGml)?fE*J7>K39*Pk>#Bwr0TD zkcb&oP%kSO%bZ9^n4h5mXegv2F)6dm(8wS@zBn^JIVZ8WI36_P5)bMXfl@TcE%4bB z(4rL3el92t+I|b#i}D9@BJTf1NaEcL3=A;wO;B;r@@LTMP?-33s5r=+9wha!GZ8@I zy-4DqGmt=9K;od&Z(-)JL)WQ+#6hQ&!NkR(;vjn)k<0-d(hD;Ov}XpU{v=dA$Q)#U zJwg&k_SYwNtWPgFKork$+4w5@z`#C}8%taDE4zdusKfN7E z9JKEeWDZCgv@{O3Gg$`2fvTT}q~07!9JCh*77js3;-Ec{F!4kr@r6j{R3nLl(f~~T zS|o8~|4M*71m0uJzyP{r2c}*HDh{GRr@q3(>p%if_isV6w+~7D6_WT0ByrH1N0>S1 zki?P0jTgFrA0&-zzBp7I6rP|}$}n@}ki_kg>{W(}gUq>rByNc$j_jUrBynW-96}O* zhGfniByrH5C764@A&EalQV-cz1=>@}zyLa%1g4%JxuhJ(BuHBynVO<|BzCo3jZ? z98^}o%vXkPtN^(m*_{qJ#1o+6pzs0hIe?jy0TlJ96pzk z#F5p1MiNI>&k6N7$ol_bMlbHk&#F5=;jwJpK$vu5Y z;>hth4@n$39=9NgBZto=BynVW-$BJe;Q-o20(0j#s5r>|$m!V!x*-lEj%iBW!y(>+B#s>Zi;%>T&AEdl zj_j|ONaD!p=L?efFC=$zK{tki{Do|<29h|ky^%=b$o8foi6h&aha?WV_5c>nrBHED zI3wrN8mKtPJ;?cPK9V@HJNF`qBfIkok~p&ZFG%9Z>UE$CutD}Br-#2#agaMfyKZ6b z2km15#XLy;AEfY15CVxp(i^h)OQ<-=9MCQym^mMz;^^iahHf|oi6f^s(7qm!4Ipu3 z_n!tG_yTP&{Y7%mOC)h*_3YqNI3eyt78gen2kl{kxibez9NGLXBynVOK>KvCx$`Pi zJt!PNhYhBZ(uc7ZgX>i>y8qDh_g| zD^hqCL&ZVikKA8qhKhsKgLXf`+;agc4pI*~qXZ`Y4oMu@URmhI0g!rR^L3%(AoJak z+*1h^2dPK)*K{OtWb-c|i6fi;0xAwNAG9kR=1ybihDUVs1Chj$&EJe9j_jU`NaD!q z??S~v_JVeY!R&p3Bn~>e0Ve(jDh_hbbfj>olS0HJa{8HvB#vzF9vtE)pyKH6xr`)^ z?4IXPadh`&LJzJ0i6gtG6GgBO{`}&kQ~C17t6+NgP?dJCZmPlKCk};>hY7 zafr`G5=XXoACfq-IY!W<0YL6&MzS{mNgP@I93*jM_4|;-k=36-5=ZXuJU|jh?(h6X z5=ZXuOqGYEb5Oh^*CUId;vn}Ux9eUbi6ht7&d?(dKdzsGBinl$NgTPI@C->Dxqb2nNgUZ;Dd>h=ko%GC^+pm$wl@Mv9NFFkByr^SNjg*< z6wb))lRT(6$X?|3Ne_}ZvO8BHi6gu7Ad)z;`VUCr$m;(<#X;@?od*fa?~Krc&Oq)t zk5nGAA&Dc8!$?EL(alkSildvO4iyKf2kjDt*{cH;2dUqRWUnz)99_KyR2*HsJ5(H` z9<=8kX1)(p9HjmTlKG%A3X}st;{8bCb|3?w<4d3>8_b-YphgCgICMCU;V7Cow0Y0q z1s%r#83!__5vm~^hj;|koiO#FF(8opQqaW9q2?5ziJygv*Pw|%gNk>ciCcm!VqjpH zf+qe0s(t~QIOv=>kbBnP5Z{4A{0N$OGt}M-XyQpw@jGbZd!X)lfkXTYn)p$udf3s2 zAY(z{4>N}cdQ=L!xCELw%p4Uo@kt9 z6NiO=4w^X3{0cPjET}mxXyPZK;uFxsrJ&(92TlAMRQ(Dx@i$QMEokCDq2dS7#I2#` zpFtC6gXW(bXyUR^@h52Fuz2}^Caws|$e?_TCO#1=&I&r96)FF&hq^})P23A=uPmB4 zZ2VdiOG;!FufK_PX^PuXX!`R^CHbJK)!0In#anRYV z&|x}b%LafH-EhZ8W=Lz@*~apd*}%pOp%fQEiy<|l(Z4b6|B`2v_YR2b}j z&`>w*9CfJo;NmGzg&;K`Cdhmc8`S3n@saHXiG#*mK;qD08@M?JAVCHO1~VuPvIp7y zu#*+h#bGDVg2a*AT`>DW;>hOY;V>U`&N@g6q#n5+3YzXugBBM?m2W5|05fK<5NP%>i*i zbFVOS9wLc@)Wgoa=7gFDvUe}2yoS#Ig6@m~X#t(o1v=9gW{xaWJ;;2JIW-^#=zMjk zILI8(8LTk%I#6+tGSFGuFmYJ@12X?0lD)9=I?>GuKr#n(Dk;pIWT-g0`Yfn8$X<{; zZ9ohL1_s!9mmn_aj7XR{?NIgT=JY|uLFz%~$bc9O3=C6|#DkICzZxozZq6pCI7mCl z9N7FZ?EEm0IOx;}n0wAc)uWqp4Jr;&4?2|srv5!t99=!=1}soKg4BcTg|)l>Le+!B z!;suB3=)8jHzLQQ6jU5Ufy|i$)vpK=fTm~A>3J~sm_x}FZ18Zl2q(SDyK+VYn2|(QgI_(5zPCZl{-92qkaS#PE#|COnFGv7t4(L=C zm^q7~;^^jp&Q(SZXV_g08=>k!6zH^Am^sMv{>b5c4x|ujFUUQhv1X9DSCPa)WgyI) z*HCeE_k4nigD8+WcR+?PFfhQ{gCKFxX>~Aj_(6)WgtHh_9Hbt^1eGZuqhRepka!$Y z`Y{G6!eWjUR2-xp#00I40GZd9$5Pe-CwYFAIzK@kRc2V4E0cR(AD=r z#X;&pXF9{op9~cTsRylTfr&4Hii6ZABKd12R2*GB=yo!Y6F};dz-K#ycnl1%b{t3? zgkk1CL^20?9_=NPIPyFitlbAP15`(Y><8H(17(23K^SH}^12IT^L3!=K@_t2#vlP` z_=D-W^FCbY?NkU(rb7nMmpjki@f)#LJPy zLH>dc|1xwSiG%LLftf!CNjwM1oE1poptF);>W@OjLE!*u+rY%HAc-T#<145*D10U( zng10k4l)NhJpVw&LFz$mIhgqZNaH#ANan~Ri5DP=t09Sl!U1NEIg&W&tVfu5AXFUW z9%O$dAc-UUYYvh)ayxK3k~p%zRzSr;{sQ%npu@!sThPR^$bfw>>lb_A)1R;%Ft$P%RR zhmFsH!V|fD4xQEmt49t`Sa^WcFGDg%7i0;v+(1?j3nz5-pfO317LYiydRX{@#F5R1 z`5PpTTrPp~2sU$I;SExcYz{1(K;p>ew1N!5;(k~>fYc+K16rF0(gG4kHfI$`5Q{mm zcm}CQHU}0zAaP`KVEqn|ICA)a#-c%1fW(o_f%VHl;>hMa0V&4f9$3F0q#oIP*f;^Y zIBXmOT^u$Jfi4akKSLK+fhI(dII=ro;~yY#WcR@ODIjs=c`FYjb3kXH!^#KPcmPN} zvUn1bdSrX^k;IYhg^eqN%s~$4dK~Jzk;G3U<%>yBaZr8)r7@U0XCjHSAkB*{MiNIJ zmq6~hZmKmh=CC$jml@jP_(k~q}E#uw4m>)=ptf+UXY9%mflu<>Se^I_v*=;E+`5J()^ zU$F6JkT|lvusg9p;>hajaJUE74+5!2HfI(N^{{bwboD!t)Faz_5J?=_eAu`+$QhWp4sk|MBLJFCkk#`ci6fgYfh3NsUL8psSv_og5#%pq^|m}Ov^F2K76{}dkiE$6gf2$~w@Z=7nW4-5z~ac`#;|rN zsJH=PnEPQT(u2%L?ni_6P{8a(?ni^hYGC5X;ScIF!o-ooAJi9vi6fVvps_5NIP(4x z&>kF+ILM743>yan-_i+9&&ca8VE3|s)PnB9f%yw|FAKha;f%cB2RUBsk=hBMwl2&Z*xjcfbCA`;#tT8>$l;TSWDe-g8<;uB z;fWk>TuADX=LL}4naJ}3Wl;5?a08`nnEBOEagckE$NypXtAWHpeF2zyW0}1 zDjPxKAoD>t!^6ZuWd%$eIUYe{6fkk*egSCh4M-eh{uv~DFM$N1?m=$ngVt7oq(Jr} zn-ALS0TVxmWDaPp7fc*EJs{7oA;&N5MkJ7XkmDCNPYALXIle$^mO$o%)Pv#z77nm@ zM^}$rej=L#8uNsigB*{bF)olex;Y@bK;j^KK^PW~u=oY3M~+8W{DRaX$0O_>FOYiV zcm(am1DOvJM-J!JAVFxnAjc!9Oa@7T%tww#P~Q_I4l)Nh9+CU$$mTx+DTbPl9FNHH zjvSAmxonUYkogyp;vF=X1QG|i2b7jz^*(4!5+;5bseXrr8%RA!9J;KX0XEJ66Ni}t zyRQpm?-e9_L2D_I&4-O=3PQ^zm^sj82@H}@addNF_YuO>gXBTxszcSo#9=oQSs{sE z1>I{1Qp~`>P=X{5%Cj){pM#2n%mvkBVo^1KyD92Wk_{VC+|^nvylK*rrbibvRfSdch! zJRhNwBZ(u|%aD5{A?py3!)GE?Jt%yT{kst=4zd^7oV`$Skb30sJOvd8sYh<-UxbQ- z)Pv#?BoB(;yJ+ID`2B$-j+{Z6dvk=Lmn zKoUm|=j%{$ko%F#|2t4|kiE#^kG$U&**%QV4iCs29So~f_ z5=V~TH&Ahq`;g<;1+>@*nvamr6Yz(MgZzbjoILQ6T`9cLv92RaaNaD!h76=sw`4>6d z;*i9V+X)#+;>hiU0wi(dc0vV`II=knNaA;q>X)@page`2=?&)oEokDfbn*a69NAxQ zq2lQN`idlu>`pnPeZk1?)J76V4u5l~ILw_OdqDZZ1}YBX-$U{jtlbC_2i;u_i$~=7 zDdc`7^7sR&Z3a^h%Htq=K;|IlYvgk?KzE(O)Whx{1*r$k#lXZRpzRHiIC6hb6-gYq zzlJkk35;t(AhgANkw^&>THX96207bE6<}P&k7yY+M4?-UGQG z)Fy=aOCQNSpfztWaoD;qkb30&1-l0tB#s;ou=QOaapZ8Gg=9W*`0PLuM@~P;^B~CP zAkTv!hucjgbCAOsc^(8=Jt%BI7^Drfb`*C1Hb@MFLE@ma0b6GYEoMMl78%$;k|0G4 zh`WhELL49hDvqokHdX_Yf|&kiS^|*7VR->0 z9*HClQV%;XsRBtHHs%ac--sj*Qf~@PPiK(CVP!Z-y#zF~f!vR{9hHFrdHoW|oCQ#G zB9PQufDC}*L?m&Ldf0kYO)WhOK z0a_@4#6j^3FDLbiD|1T{lNj`hONtmdnvoy`2H;c80JZ|E0_zM#G;bY0%X^g=H+B&r{+{L=%ptoLr=$!2cPVStcvWL6|i{$e)=DY zmn@(M1vT$U!sbq#;fwc{1X#iV2N~@6PrT^CcgGvyUFN4QrM`b06r&gn01nPB00*_^1%f!&4z43U1F8 zrRL}r<%5)Ap4f`1418MxNHOS&C6qQGl7-}*u?%Wu>cvM9I$Ii6EG8G1fNC*Fv7KC8 z0=jMz-0pi;8>bd)c>K2zICTBzW>3OAkpc`>hi%Ke? z0i2o~Eol4z+D!qk9{}mW zr5|*r21p*(#|P;LjrS6(AG9YAq#rik2-05;9ghWx!_2{DKWL8zNFB0%(D|J(eJ~oA ze%N{fWdDQ4E@1j#G%o!hyFm6M>#roi{jm9KWcOE*pdU6~iEMv03Ho94+sOJsVFL3v zjK<}ESU(jvjt>B)A_mSB9>?o&^1%F?G%o$Hu|#D3pmATAJ{XNlzX-IykE|aw zt_#x#qjBkn&F3TQ2c4@6(+8t*>4)uKMlL@<wax_p>E7>!H64>bIc-48m~6Q&PFU9-z%+3=9kjAO+C$ z4;nv&`3E-ksK&qm9-D>^-@&vqyaP$Vc?bs7S#SZ+{3pmvbo~tK5G4yi15Xepm<0J3 z%zzSxQ2UX`2EkHL{m5g;AaR)eFdDR16~tykvqu1`9~S-~y&#MpexPx3aQLC=UjbTd z%D}(?3nx(d0osEF@+-(3m^dg+VzXZXYCrPWJ4he8{h+yMZ2AqL`axrVAbl{5t{=2s z4x9TAK-~{JR|4dI(AgO1?gy3g*z6C0+K-m}7|`tptqsIx{|Bi3u=xp){h%Xp(Cr7E z9f!^S2B`h8eP+1)4_c>%&3+5$K@`aT2l)lve$YNAko~ZIGBA7IK<$Us|1fcoT`)F? zHe-aG@#%n;elno;gW4=0bs+zPj6}D;g%OhfFw#GC!8mL^9>@$3hUo{n8N{Cf)sLS3 z3!wU8>!d+yK^Q&$Kj&t(J;;8Lk?8h^LhVOOeheni zNe@;u`_Z@zIZ*xR>Bj-OAQ`=0K@Y!lnETNjumH5k6;%H~JqvO_Xr2e%{abL@-vG5A zwqF%$3`Y609*6x5pvA5X3=GKm4-_Qm_W!|Q{{^W1pgI#~H;6{}KWH5uC`{4wPX*L| zSULsyA2ff2Zhs6jH2tE5-v_Aupgq_idtn&ee$aUl*zBJGwI9|G0oe~S65W2#JRhhm zK`(zYpbIoW^)t+F5Dn80(gWgy(ie!0o_-cU_2+>kK?TqkQM0R#}87>z`!sOBnh(|+SUPaVZtwQxPJlYQVs?N22h<1QV+xE;r9fG`wxH? z-J!K#K=(SJyPuyG5`O6JKM1uSd9EAe2AI2HvIa><4blh0=#9I%K^Q&!K=Z-a@=pV3@jK{zNTm7$bRIRj z`$6Y`g4~2|zX5ar3A6_ZWG@V(+YeeVip~BFpvA#x=?`?SGrIlV?AZN(0cyW3$Z;^s zk=E4xBQ2j9bz=|0d z7+`!DeSs6|ewYF%%>i1>ixz*NJti=Hu=4jI%>C#d03CY9fH}5_9)8SR5dSly>6d`& zhuH&l7ToL`=P}!%vgB+3rhz#q59F?-vHGQvj=7XI{yle@IL_!e^~kfg+FL7 z6ih!%oRu4r{y=SOm>nRx18P60&jI4YFf9MUXg;WZm^_T$0@V-W!)Ta37+;Q?fdSM- zK}$XiJD~c};~VCFn0_;;{pk8{K=m7-b&SyU8*)R_FU&wF{Qw$%8KA-)I(`J&D+tpM z3qO#5(Cr2p!2vqV4s`AgR3WGz3Yxz_*AJ?m(9156{s+*xl_b~#Gms!s`w7Yg&z)e? X?*Uqb%)r3l4(-3e)Pvj$V}ob_ZPdGJ literal 0 HcmV?d00001 diff --git a/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/extractor.o b/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/extractor.o new file mode 100644 index 0000000000000000000000000000000000000000..acb6b5f503eaeb8c089ddd251e98af538b172b88 GIT binary patch literal 276920 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

gZm8{fPD)mT$iKyB4*7U1crXr>%R0fU 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 literal 0 HcmV?d00001 diff --git a/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/rom.o b/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/rom.o new file mode 100644 index 0000000000000000000000000000000000000000..aec95a7479a92affd81fd0fb0c8f80cf9fb303f3 GIT binary patch literal 47264 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 QA3ARWQ4J|;U~CW#0OK>wTmS$7 literal 0 HcmV?d00001 diff --git a/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/asmHeader.o b/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/asmHeader.o new file mode 100644 index 0000000000000000000000000000000000000000..b727be1ea7f18c43a4a574b162e915a7269690f1 GIT binary patch literal 14160 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 literal 0 HcmV?d00001 diff --git a/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/c/cEnumsHelper.o b/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/c/cEnumsHelper.o new file mode 100644 index 0000000000000000000000000000000000000000..951f0a93a3be9b6a9d9b6e323be29fca31cdc8fc GIT binary patch literal 66560 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∋|j z3=Dt%Lx3Js9Hbu9#(=fx!9%&=J^`fd0g?kLoeLtM{U^`>AfTfc~AOWbqKz72!*CUC8W?f+7dy&ME)jvTJS3?S)KS<)B@d21Q zJkWMGNE(z!VB%I#aZosFBAMfeB(8-d4(eCH`~~VW!^|l{QjhG;W+ZWBe@#RZM^--< zDh_fdACkRGq2eHSBCEfGB#s;ocaX$Ec^~FZUXTIM@JCj!f+UU{ZYEH1kb98BEd(kK zqL9_6fCQlF5Lx{ss5pp14(B-_0jPVB!}$`DII=t6Ac-T}`v)qH?oJVCe+VRvY<@VB zIC6NlAc-T}y97xb+1@QsaddmnK*iDR)rSt@fW$%5XRvs&M-n$giuW)iapZEN14-Nn zNqs+(xG|FWG^BC{|AMRsDM?g14EF!Ny}Um){Av%)ZOP@M%b3Y1sOk=zNJP6wF-n(l?E2gLHZump_>3OAk1x5Jguocx|KXsyKL!S*nGLWq1_`LfE(jM+qFKWb1g#U$!_NVlkwHrvK$=0}2l6Kf zgZQxU1J!pR_oJJ;2x`9-NHG!ysYT*~=iNYJuyOzI|4Lc-<6;1JVPcdvN$4 zHlYHW{{g85Vf658$KihiP$dbQ7i3^y0Qn!(k3jc7X#NP)PDYP^1E@kM1+p59VSE@p z3y1wHp!UPU8Du}m9+*Cu_y(x|nb9J^0;&*7f$atn=={|%`_c3tz+yir>|pv~_TPcp z4{A$-%!gqIs6tTwfQf-^eHVGt9Hc^M&V@zC{8fGSi#lYk0?^@0cv=sY=k{<#4SzZp;mgW?a=e~0OZg&#;7 z%?gmQ3>%*oBMVML;jjkU6SArzz literal 0 HcmV?d00001 diff --git a/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/c/cStructGltfHelper.o b/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/c/cStructGltfHelper.o new file mode 100644 index 0000000000000000000000000000000000000000..471a934dab63b16b466a7a8d69b60e535dac9113 GIT binary patch literal 50944 zcmb<-^>JfjWMpQ50!9Wq21Y0wnQGXA;5mSq4h&ulo?x}23=Cjef`NfS63UihU|^7j zvSk<;7-XSrIR*v>c_>?ffq_90%2sAzU{GOTU{Hnf)fgBU)EO8UG#D5dG#MBev=|r| zw4rkP3=9kgP__{R1A{S?ZNk97U!lJ-kJfMeEe#9|44#^Ad^%NBJe&XUm%Dg$TYEPDVJtP~ z-{#8D!S2(oqT zzLuHb(Rtsa^O@l#u)91unLRp>dvvp?cyu}o_;fz<=zIs3fExXJG1MnuK``NA`H#P4 zKLZ1UW2j>Yl0P^+y2Chpy7fG|?LE4S1w1>i_-elK(ER6V`K8?0r`wyuxATOj<_}-X zBmC_h3=AOm@V71p`H=As$Oj(HM>s%^b&NgCFYf}8Z#mAuz`);el7WH2r}H_)`p%;u zpYZu~KJw{&=h1l_BHC>YveZNKpGWKe5>~L7C*vEBPHmsgWC1ke)4=8*=9dSBFN5I$ z-_`@AmY%&OtPCESpZHsH{{R2)(|I0jh7Ysy%lQBQ|MSZ;Kr94{dURXAbOVdJfE;$n z2OenN93CK-gmUu5KEt;!6aN4IKLKn4QhM-c{mMj#_asL1R|GwR8R3?DJt$U3MC?Gv8-6ZN`i;w@e)4IZV(G*6G&14BxwMbG=Mu}-wmV)_ig>g-}?IB|NoH0;TU)L z@Psr(cADTA?idCNHP6mJkkr`xhNGM96Tg5PM<;u?8;eJGnZPH0L3fT$cNULcR|Svm zdI1m1WBe`3ObiU3y&)p z?0~SjTEL^%SpgIsydK@o3h>x~r-r+wn|)iqmGJp={`2Yl?xXn)9?bMrW4~otV z&*LsC1t3>|+*;w;*`fkY6WyT&p2u6j=@ldiD&wNMeKR~eLsSYJJAG6#Ji2`=Kp|e? z(cKHu;n~>((b?(5;nCd+PUxKw13Y?NGdzyFf^G5Wbgl5{Yz67?I1W|?GM;~1D=3FJ zcC>(V3ZiInjB|`X49O>uh=#;*r~=3#3Lc%V0v?^mUn>6l{~r;4y`cgip9y$a9x8G0 z=njA%>1LSO zzODZerG-!De;=eWf&9`UN5#Oy@;#&|L6jCA-N70j-8Cv4o}D?M%v`MC!T9OL)F1!< zgG2>9dW#*v(bUcC+nJ-n0ZO2d06XrY0?xr6-PIC~oh&M#JR#uI`N^mA*^9J)|Nnzh zu!Kiuvs)`=An{JCDPo^(}u(FQ_!=cIEKwbmQ;(+* zAcf9eP#F%643Az{aI8qYVEpy}zfbpCP*U~j-U~|NzLtMWqM+#$6fgIGg0dAw@!|`L z7nt#_|4W2Cy0?Pk3lS?G-L>FI;rHm?3eHK;*z)ME4e;o71()Bv9^I}9h%%wOR>7w? z*TBc}eF;bgGd2W#I&&4kwGQK_7aZRqks*N;86L-7!O;LKM>}01?H7;E3;~Z$R}N6D zfMSH-r}Go2RdVIe|NkDHuHXpqXuVw$?g5TXXk@e&|NH-cKd9aS$F)c2QJ>xn1&>|_ z190-_1eN>63O=3hL20A%8>loacJSz}g(Quax!~Fy*OZDX8@le~ZXJkSCoaJUhcc$)Q9H5|198hdjC+Bs^LVlzstA zbvp@wQ_B-jk=g0S0WK&IKy`L^u!d*n5f7+mKuHpmygfSKzu5d0;tS8-8WpHF zBtgaeaVD@k-~7hm&da|^bLV1E*#L6qtl$6tf999_<hTcz_ixJK{%3a+#|V^jn@I&D-yIgJBcXDUI$D zIPT5?a<+Q&2a|b)&nJ;9-wyS@fTsg zK&kH#zdVCS=S7e1AOVloOQl~tI=v-4IuC){lMr!G@b`0v^3l0vovOZ*2gyQSm|!l$*9Wzwm^#JRLh+UwAgZXDprR+xl$>sF?EP_dn*rc+|sE zM}@!TC^#-_3tk-m0!qWN0Y2Ti9zK?@OQI3^$FsY(;KlMUpmG!1{`Ksxh1F-JNcCB* zfG4OqXnDMZ*R$Idxjq9of_*Gsmu?1`@7wyegx{mPG{UFzy$`h2>j5*;qZ?r)sMZG; z_8=oYkd5?!_zvueR%=ijp4mjjx3ffr!=w3#1X5AMFV6sK@3wd`F)(=SIPo70>cR2k z!vyMUeD~-KQGxU+J-S0wAd%UvqvFwd+0*iBi9*^0kIs9b(gB>*A?;^P!5+!C zJR09bFfuS870oRw9*hhOh6lhVHveGdZ>eKoU}*lqS>oILgOR^w2O|SR=P~3Vg|rDf zL4!v=ov(a4zroXOca2H_sP5YnpnmHSkb_Y3 z6F7%V$M5Ubw#d|KB6? z_61M_ka-T+q~_f}7#JAX`CA@>a_eyy6>$H~@V2Yr6OevrFV95<(#`9JT5nyW!cig! z@&U*d@D`O%Z;48PPv>`t|Bkz;;Bb(qlu*m`sdcr+j20QoTjmM}nid%(>U7nKNb*fv`;mLC1YuM^CHq`CC4Pv3NqtWhcO>D>bEo%wXa0>!7ZM5O@KxRQDM|Gy_%2(`vDGBEh`E(XO8xc3Mh z%jxX~kC|B>YkqzYP;|QqU^0jyr{;kM1oh9H4OMeD0(94DP@Opi-vwe~AD{{sV{uZ+-7kIRN7Kwy0bH(U!*{ z=?2V!4W#%aKYq;)az7~5fyQEdEWbmPfm*Zh7icK5(?vxB8a6G^h}r^0oVP&j;!YP80gwPV zkNIkT;cp2CWk#f`^9X;t9oPZTG}n0;6c&&q05ut8h$rJ6kIons15jVj!Lt+0vGB1j zQ4uIn1?MlH&Tp_WNY6%a6ni!v1I4tDWr>PF=>rdFVgngq@j~qlD5-6M`d|;(2fmj7 zO2Q!hZT2^yWJXba>TCHARG&hP2KBc=2?&zFkm}VvDx@SZ{+1AM?*N+OV2SLd-S7YZ zeIUc!;4BCmANA<=QQ-h}eFH$fGidhf6$RyDkK^Ff0A_ZAnI6ptJfLO2M{mK5V_-oB zWOYbdC}v_e0O}Gbg-`=^3^?UMJ&NMTm-)Z{|2Mq-^6FnuK!9ED108z?d0zlj%MKgw zqj>M7$sbT-;R$kM0US&(n4ZJ>gODx?sHNc1NemmgnE_Fc)V>M_4TQtT!#q0wf_uc^ z?hV*pP`2-lQ1I+#^X)BBG4SZT4{Av(cytGFcyt?ps-T(A{{J^T0PYv>6b6-?owq)F ztoH4#QAvQb**tq&R91kyJ2ff+pfSoFpz-w17I1kBw#1|JuxIC0&`6)TN3So(eo!L? z)F^Bb1()EjKx0JUq}}YQ!3b)^qYfGH%QG1Mf1&sS`)GY6sJsRZy1e-R9MnI8_EX4i z1eb26bd=umKV(!5F~S3?4i!8t|3SnN<2yc`&%wj-S=CU%!9fJ+dtW@z!zdAwBCNAt7ce~-rB|NsB5 z=kK2dYNRy&W?*1wsNw3ofAGCLxaAIxhL^SfVCfE$j*w;p_~jWusSwmP{_hy(2pU!e zHCfLx(;}UPR{+Q0q+qoWx)JdIstY z?@<9&$}iSF1##x6IDmZGy+*|XL|eWtiG`0JfcnSnAXSL@A!z>?+{A;oK57LBbY@?d zZuWrL0Gb^F)jyy%21@@6(gFiD=D`gd1CVpzRzRC#mj59w76FhXtj+<|r{I>3wT()N z6sXPyS7b10#Q1!7iwY>-kXkkh{NTO-D6&!d0-zQV10;}pOH>@dZ5_~@=W$pY{kV$? zbVdc%{_ZSMu>eOOC|W#xx>HmfJdV4lK>7y9T~so_g#c{M1Jp_Lv3$Va63qvi3T{yW zwdV}K8Quo9!Ua4)b77!v2-u&UE-DH>y=zoJkqashJiA#`()iyWI1bST8pQMIgapth zeysx@$6LUyN05ETT2w$rFo48B?OTu-h^+xCr9kD~@fHnl z@fNTvKunM^pmYRc`*f~R$p9C3Yg7tAQFFXSr2=Zju@;pE5VNyI>^_)gNyGXEPWZWDl4P zY7u}Y2fBN};p)-pTwwUW(>ueXy9XSg9-ZD5AT~HqJG(*2(xVepdqKk2qq7+_7XY#f zWF^Q*d{M!_4H6g7PF@FSXf8%2*oi*fTfilOkLA~rXh?s~v%9X~Mg2oi zJG2hg+o=P0c6dCy%aHmybpoEfZs48{uV=R#az_W+{QU}QheFH;%@2Y*I-oE@nj{2e zW>7GbQ4V-EAK~z^R8iq?$pWR9?h=)Pmlr_24d{9b&@h+)C{x2G;~)j0M|X@$#>?;E z$_W&}3?9dwAv1>E5CzAbA$hkmxWc1zGDwNXad5bU!u#cN_&8A-e|`@*yYUNpE4+*W z&D}x!1J8DWa)3|gf8S(CcMddP=Gh(Y;hXscRC9oOr{EH-^DwA~11`Q8KY_{!P+<;{ z0gY(9x(kY^R`4_s}a>S$R26zw3rNF@rsqzf-a z=738PP}hkAQIvq@*f=;D7<{_dfIGmTL=2kYc`XPkFFm?*CBV~g)!>=FSPf8H12ip# zQujg@DYPCamGja33~J>ycvv2;74_Hws)0eHs~(nz>$Y^>XgyG|&a?B4M|ZBk>y_a6 z_2|w~NdR>Ok3*)gLEZud2`FpA*q|r_u{|~4@VCgZp^n*t*12$idcKg3r)TF;PsSrY zolC%DN4}kJKmh|vb|4yLsE6fi$oTC$SU(dwCg=(2ZhBb0E`0<~NWFU?VbZw-JeiA< zsz8$r9-W|}i|zskkL~~uP@}lz_W%DL$vG-I;6|56=38(Q?QR75!GrMyQnC}^Z;1ts zxb*G;r+ZjR16d7nuSYMmRRK*ypx%N<=P^*Ne;iT?fPw^;1VKRtOI@%e3KFAoDgzk_ zO6m}+3D;Yo?8Wh71Gwenq9Wkay#SOeJbG7v3<1q7N`NQd_p)J0e*EC{;oF^}0#Z~G zf@u2HsGv3dh)RB2!O3sEPv=vRnF7A8PfFK#Sm&rnlsI{GL(_FBn!zNsDFr|U1iVe@ z(fJO&P1*4YG`n>aG#~2Gy9L~8d9maUs8oWKl`q0UiKiR0RT-W(0o;!<2gwhi_9S@x z6bppKS+NB0g;G2_Gd+@tY0$SW`0Zh_Q6Q`gTMAP#0r1>8>t zw^Od)81(HFP!k8V#^Z%H*f%aJ96rnoz`pKGQIU8V^5g%1SHmZ+hHqc~_zCLtL(gpErxWQY$_4MZH|U?dDu*7@NuLvnszafw1nW?p4_PDz@T zRajz9X{s8!fR&YdYKaC!ZE;CaW?s6QrUIA?GcqN+C_b^cIJKlWz9c_CC%(8SSwAN; zsaPLmbUesxJ#a@LDX};+IUZt$l~ufNJlK??(&Q3_ywaQ;g}nR{g|ft)%oM1>8qUEb zAX)dEk~ELhoPyLME31Oi5|9a{$tCfrc_l@a@tJug`CvQZ^YT+t<5Me2iV`&yLMjVV z!RBS=7UZPnrskETrdTO3cozF7Wu+#UXn>ZlLv3LIk7xOGvx63+hwnm?5v1uD@Xx&u;R%?j(_F z=%OM3nmvOUXX&D%z~8zEG>Zc6ymW*6zu(Q9Scg2NbBawi7ijdH=uFR zY)CwLbQdGXlSg+oINWe9y%q#5nFI}5dNdzn1ZQ#(2jLqc$^+?WLu+HhTn5*mApamM z1qSJ8gItimpcot;u&oA;onJyd8sC7{WuOd%uK*8(`}Beq)b{3pW<}paq7Aye1v;h; ziV%nhSQdE+N9S>uPROVTY)cGW&ry$V29Ius7e3ufSV04%;GWie(2kOZ8WjtMk`zb& zeI+W+@YNvDc{Y#Eryji}Di&~Y@cO526BX#3BG?Hq$^9%03=Ciq!%I*H90!d-GI&5u zgY~gN!>%5X8OwcKpvHE$gMo+Tg_1@v&!_YG{|o&4KD^9FUX$n9dE_-eC>%jkQBZHe zhWTOU{{PP?ZNbXG;NHZzpNZinBkKt!h9)N4{Y(sxm_R*dXly{@6H@*nF91I-;L-d> z!UMXI!4tIVywm*yXhapXm*EF^QDJu(WT_+LC$L97yK^l(wQ~(Tjypr=$(_N|^$hfc-EuS+rXnU+rjXyN2j-iXLqTAXSb_`hvo^5XSM>nqWDku4->JY(bQb3PcVX#9)rE<)0E| zpU(f#1z}*Z*RLRk9esTo#(-3q2vc9LfXRS7_kXq{qlF7A149MtM;3;6jI6U+80Imt zE@5GO!^HZFg`tN9Br=f&Bs&evzR1GLz|hRfI)xRK4&VtL%5Vhl)`3jOb^Zp=?SdT! zD)>NawL$B)LHP=_ber*$Pv?8^nrDcT-eL#Hlo!aXZf4LDam?lXpr!nvtpK3qza_k& ziP}!k5<$?y63}9P(Ax1TpU$UXn>{<>~=nP~VXyrO+d<3k#n;FaM zbkAMD zED1v-85kJ;&-P_>6lP^$Fk_v<#OT7>&BR=!yq<}16C>+fCdU1Ytjm~~-!ihUXJWj{ z#QKMc;X4!S8fNBM%&c3P8J07%GB6wg5sVBBwV)to0ME?{KwW_3OB6p~4F?nz5XT-y zF$cwuFx9XCzzj-=5vcw}WDwHyVKWON26y7i2++PLEu#V&8x8>N z+=Q&?1*>}f3QYM}+NhLBgB3wjhDYZO4_0v7s*^?KH6$D%7NU9xtR0(#N3)Fz188TU zjfzhvWS19CwG-f}4zW5DS_YvQjgalGfv)g^FI(-cQ3(KB0E-y74AdmBq^ISb5<%=? z0G1~%7AJtB5t_!jkq7#q)4Z@Sgw7IyO@=uOG;jy%-a`a?AtP}RPB&;G2b73G#zV#t zU(W|i`C2~ZZ@CH{x_b{>^$Sw?`WdLp4;pR;D+8Gg8d`vJa9IRd@d#B0nVJCC#xE;C zMGcCxd-s4R{h(?gGx2Z^sBDICpc_n~9JoiIVGnW`sFenmeklyLq(%i2g0C-tMIjLl zP0hV~z$-(+5-(@|`~M$SPF!PRJ;urSgo*VVC-YQh)_a_ck6Bs!xEMdOvaaJ~Ue2a> zkCX8e8|yAk#{X=ruQ-{faejX8<+ zDkDP+BWouk!wg1N28KP1tOpqxE`XR%Km?M$|BP&{jI6&I8UFugWZ?m~!~W0KWR#iD z_=<^vVHpeSbq>b)?8XcX(>Pckb1ArY*$8G6D+?$huUS;Svk$4kdW(r4r+GA=V2@468+0k0>#07Gs^M%lyyf7G>mC>}O(NILE|#nF%fqvJ-?si2>4{bqw+8P3Hjb-;wa?u7_-+^95~p2F-o? zbnE$amvQU`t$=wgj9CBW+g&dK+9KfN*&Pp>(?eQIBjDLxuK?R@-Fl!@(ns^NhvjSZ z>Abz*`IPOxoqv40>jivU|CeroEYfj@&D0>7DF|7x15NC$2TG-UIzM`7-t>Sj(h>H6 zF4B<)tUe3TS%+XaJJ&glD%8Xg`&JM{j_FM`wTlc)#=~enAHg z56g@EEq)-wIz0qH$`m|0J;2*&!MmpoKtd9Z$3PZ&bOsoJc2rwIM&Hx9HhzCdn+*|SJ4DbMn1b{>!{g}>x0FX!oNCeWu=?sVfi4=fDz+Ddz z1Kbw@F(93j)=T^?HLMH_j@>mXAe#$3drMR@Ix8|j>(MGaIx8wbn`Xhih0Yxi%8SFZ zdkT136=V!#)j;P2P`e+rX}H3(6SDXnc|)@!|F$XMiQSF~phhz&C;Wi%-ClGGJ9dXX0k4PY3}*4@4OZ~z3>NV04*TF^`H8>fGq}eD5)kv~ z3|8>$4*TKTS@yxB*E_@WxEp8|g~6jUSi-YAOu+FN8;EV-*&Qa~dE5=WtIeY`*ut|r zOu_TG8#IW69Xz|kG(3;Hf#cqzGuXqkJIuiIxEpx4n@4AGfM<7@h39cMXy67%cy@;c zcpi6y1V1Ps)j{VJbk})!bOslA_Lg~cR%dv2*F|`AR#$j-*Clv#?goXR;eU@#P#A`R z914yOXt&9;vn;~1vn;{$xEpxP)scT&SV6~RP>6x+3*YWE1K;jC4N%7=0y-`O-k%K0 zIG#l8PYze`u)Gf1&xN@^+1K(<>1MFupn*Bh?lKFMeaUqKpdKP<=?mzb1h8v7yX!uH zR@3u%cC*13(tGy0Re1DvgEEe1?=%qQVR^J9%CqyDN9XC6@>tfJfEN2eI*^{-b?{Cq zqG$T@8%lrhvm<{#A9$?^7f5`9N8@48$_pRRek}vg9<9nfybcAgaA9#EZWH@Xb7BnD*I1PjNbd*;CU9kmCN1$^&f;>B~y;K6lJA8Zq zHmU(zzJy3l$m^AUfb@Xp13>9Vj9)NV;iV8rYyzYxYCTXQ16ue28AJ6H@aQ}Tty+$O z(>h3%1V{mgM<)k}R`BSI;PB}5fR468daRD|hdp+~b|r$E;+;M!8c_W{DjFV)hrvxz z&_)UckKP%e-0^bR&;S3AJAkvh$8iT}Vd_!g(b)kiDm;!ifXY=+{(iaR*Z=<@*T<+R z@C!yLyj%~OCq=IBJow!YdGv}L@aUBZ@HqIG`DG=jH3~Uu2kZ)vF_8Mzqw}K2F3|d( z|NsBZ*)?R`2Q_-OtB*Q%g;R0)(vp!KLHXd~KRP(5n+&4clRPv<8G z{z=DtG=G84fq}vBwyWV=-_8df-Hg7yKB64HnjbtnT|^oDdsP@c zS})aW`?emaj{~(poP9b$2g0Oscyz{sf)shvCuF_@yf5m#4`_PLr;`UVn&Shik$t*( zR6yp4d32WwAeC9K*MQ^Or}GeaYYODR8c@q=%ImA3@w44OApWn1Mihrfr-%wTm^`{g zR6ude;n{iAgYoc7tN+O7UF?Hs`_J!T`N4zV{g_9u3~1ji!|UzH1FfK-24hHgqXu!g z0I2=K;n8WL0^ZIFvK6!y)1zC$r#pk=wFtjFgJ-v!z&=p(6|^Bc%CqwrsBHG^&QtKU z{0nNj@w+_*O|uGt7U+Tw`hoOgTMv}V`*gn832HThBGB?gtuQ#E>p`yeu)I*Wy!AlE zV$W_j3BzxoJ@?CeJ3lzId@IcX8RiT&475Mir;`N|7Czl9Dy;`fGz~Ac9`ND!_~gUy zc?dL~=hOKi+Nbjnbg0HL{xEF)w6ErS&qk1C_4O&9jiBC5Lrt6z z96pu>5+#Q4?lCA9J3shzS7>;2XDE1f9`otW(F2aZ^#6V7h4|VZ;1vi+3il^ z@afLe@aX*P)6L}5?Wf>t`Np^NoiD%J7jTTs19wQzfhH3{2VVH7aG->U4|HEoYadwM z10T&79=4z*bM=BApp&f{YN}cfRFr`xi==!ykAV-(IFDiiq$T~rNAm$xqX3rqUT@4CpPky&6Ad5Lc37-LC=^M|+KcEog?+5iJJsbakEoFD{bV29M5nvCz2`uyG(IxUsvlvz3BIXi{ljNvVRNp`MAJfv#aG zm}^*PWTaohJv92Cb$7(Vzw~xRDDzKaRnXPr#9nBaTl1a!#BNND%`A187wigA<=X z50eX@L>sdUpF%T>JD&kl92cL0BcFsLpMVn|hbuP&sP6%)%|O~*L1mgZpFl5@6Q4v6 zvm>8E8;c8{Ml&l&qcazuh9g+76IibsH&ZaGi2LDVXU=-?88oxDvGg$aGJ)NH2V^kx z>^l$>}FtKxDHxq@5U$44{}2vvlE{}FN+hOMh~kapFta& zBcDYxy9-|d^AaX5J_|=a14lj$S3U(NJ_(4UT)ACf!cIuS3=9mQo*8JJB*;EvkX_z< z0)0%bd=kANJ9=0g`83))GB7ZJ>lHUp_&S2Z z*AW!HOl!DcA?wKv4`c=gP;c%DRNpp`|D3S+&jsW^7l{8Hn1vDkL-vR}Hz@o-ZE27{ zVBrT#BaBr6KHwC@J{u%04NFHl(DMdCg6WJ544|~f;D+jd7m)wm`5u7MBq$AqfD|(@ zFwA8_s7H!J z!-OxPnZ1pzhqafbkGY?T0TgaA(0F5qx!aLXppD6qPokOGh0lTMHYCO!!FdUkH+!J! z1sR}jpmgBMCxM*K!RY{+&I6dYVh>XnZsrU|J`Qlg zJnz95fZ}Whkl#c=>5PGaVKLktsER;ovI6XB1_n?|0F)k(;}@LgTtR6P<`$-lScB4q z8=St6K+TE)6;#;ruOE_G1$++R-@dx z!C@`~O3rtv8)zVYbHeAhqmVFnLAB76o1un*fx!ZNtP=x6IVi5d z{_@0P7T8}dd;v_muzJgbo9Po5pM@KiJi-*t#b@D;A>j$jkFfM(1S=zO=0{IRxfZ}Q z8{!{FRR6eegTwCxIM5(xpMsfa2^%yX^9C%zz_3veIX=O8$dwOPS0Liko$mrO^IPnh z$OGgLP+oC>#z`S8kMmtXi8oOBx&)N2q35zPxPr=nC_eC+N1zOi1A~eJ7KV@D?1ip` znE_Nnpo=mvFf+hf1E_M$45Fw43=9n73=9lRNam*#r`sY4K$*-8piqHwpcKfXAbTA^=@E2REhqq>a?A{%({Q02 zD7AqR;{FC`z5&;bP&sCBihy#EC}sxG>A6S(P$o0@G+ihMiDG5|ovw={z`($85o|AF zsUoOOf~jBzpTY~{A!ugs$-D?YjKvH-sTamW(9Gc41HlKewlhKe>j2HSpn41>4#La~ zdLRk~FJlI&2h~ClVNg86$fD$n192aOf8?l1Kbr}AE6frQsQ^t9)xFACT z4@3e~|A1JmY!LMVQ2n5~0wfN?%nbS<3Ij7UfKDOC5N2Qow~kQ7LH-2QqFbQmgUUsi z3T6h-sl_lJf@Wp_57{CF7#J89fZZv`5CA%GnSp@;RNjCT>|=+x-vXN6KxZa{#2<1% z#8aT+pnMGy2VrIgD-eZ(y*WYZ5#lg&_H%-!q!9TL>J5f-oFMIDAOZznhKhsAd1Q$j zU~y1xMHXdXxC<5+V*rmVAxS-gii37vAPFLgDLI^7DtrZ;Jy|E149lD@#$c3M7a&_^Dr2EV3!W&2xB*Y3J&oVAaTs%pJ6LV9AqFGK7>R3nlLCF z5cNB_ufxE=P$z=jJ?lh3>JjxmxIe?dz)&rUUHxht;!&KCaGn6VjDZ2tM*unbEe`b- zV%W`3#UWmcLwqt0afakzw0$;u$pr-r@lk%>7N9LWpdCD>;LSnC?x`iNLEe7BCFb$* z$rTlbhK5GSyLvp6gG&qzlQR;F;!BDWGfRp+lU;)oJ(FEsUG)kQi%RqiK&Fze+t3Jk zw~%K*va4%ZNPMt)d~k`8L0W!Md16sYd}c{%QDRAcQG7{ax?W~+Q6kJXGsub&&y3(i z&kR@B#9-GT?_k4t6g3v{K}qo?MX9NtJkT-VwZD2eenq)fJaVgMH#bK>&{va1g{N zB^IX!g$w~-8X3d~rIr?_#^)EsL)IsadN&muhu~yPRP5>{=jWtA3JZ8L7`UtnDKgv# zT?RvQ7gC_X$~=tHC^*qG*f1Ve3L2w&iBw&13k}UN_G%iNgZ65I>JD(!Lw06DwrduH zs~gA$PS*fKBdA_i(1y++3($5?x6GW>%zzBI`N1WFAQc#aYN6EJf}F(U)cB0dyps6R zyv)MVR8OxU@8A+6!-CAzf*g>dVDora*I=J`PcK&x2re-+ zhZpj&$_tW1N{kT2KX{WYymAA}yA=3`phnzi=zyz!jL?B6Ae;#lIW0m`Ct8xlNT7!1 z;YFDxsfkHBshCOC-N)a_(I-B>xHKu=Gd@1bkLDIL#76~}_*lfpXXa<-WtK4L`8XSZ z2tyEI1R{(YZq_;yYK@FOs)Wnih*Pz^7hTPQLNlea;PtM4OS)5m%%Mc%xk`qt{HX=8_EEQsgIn0ct#1u%& z0ekpE8?r7&IN}E;Z-_%4cl_Zp5w{Mw9fV^XZa873P*c%j8RlVhVW?`HX$EdFjx+_; zZ)oU}npBz&IcmTZ9D|--0p7`es5O+Kk!M~>YEfQd4(OBtP)T0qQV=P5nqs6RGgoen3Gvj8D9p?W$-?e1#+LMxTGjGF&B5w$r<9h;F6qTPt4wxYY?cf z05LBgW>iSLYp`iNIQ2#O1?T4!yJmvZd%kf&X$dGNfJ9Bxa!QLcASuKfDJz&l41*lg zkW`w6+hxYZB}HKU!6hci`K2Y0L~Irx4|NE1Sw1!cusJ&D9OyvV~CFm@yuiZbz&1C`4$vF$R&rN zal9|2=!gdut01$Yf=dj|kh5rVVsQyHhmse!F5tKg%`4B$ONkFkEiTOkl?3RS&DjW1 zxS=I|XG6GDaEXxxvf~nqiV`d1^HR&>b5irtOESu!zD>e0*MhQEp-mqOlebY#1MG9PjE1Zn1&$hmip+ zk|5E7R8vIxAzTBk?y%aO;`LA88Y5F#W(;z3;&qj*=> zfQ%%D_$c=7}57t;FQQ(#)b%hWPlD;{5oG#JrRo5C>ecm84c=mY}FEO3g`4EC!b&gQM4E67L%i zNfV$=TF^dId_jIOBrk%RuZHmAAwDHFxhNHMU=NNFAW(`M9R328bV&X}>JWlG7fhfN z2QG-vJfE3I(DT71MwWiNj_pLE@lQ3NUfl zJS1pl7&NO669+AQ2U!FXw`O2qfQerM2}0MY*&vBOf{KI82QAu#secX?2blv}y$ch6 zgCq``C4q@&LnrP*>Or$4F!4qtab$a^B8h`$Az|u4mn4F$0GZ>6XF6SK@Nxd z3t8L{N!$s^oOwv%pfvG@*53qSckiE$6uZB+ify9yBGZlyUejMW0afpA!A=eq+);>ha5!0SLD<|C_bM-oR?9}Zp51PTY_{4M~#)Er_?8d7-9 zLlQ?0&&^2U$o@KuLmaeD09Fnlt7qc_i9+l}7FWO_UWz1+>|fA20gy=`eO44pNUC{x^`s zk=^+oNgO#Gc%Vz-K;|HeTi_56#UWmeLwpeq@xMso$o}PpE{z5G7dd=%q2eHSBCEHC zii6Z6hffGp9HbsOd_e0BKrsUnN6x43aj3V0E)4{!M-ICJu@V5cWe8hZYwMk!a%JLjo8W7*f#0Ve6yw(ZpdZQL50y zL2(AMw-rqs6vrU(325S=_39w;S!m**{Z1h9rD)=yJt83S4QS%9130#$iG%h4fYk3p z6Nl~RI)NtM4N}a&z;F&K4vKe>*|75ADpVX4@5t%oE>s+(z7#3GzCy*()>xgVZCZ zD;{Wv0i+%jzp!*Aj3kbnuB4E}LF!@YN)=5UmaYtt#F5jL6_Pl}99X(?LKBAu4}&k7 zI4oU7pozoMRWh15EM4WHiNn%WC7L)aUA3Tz!_rkhnm8<7%|sK2rK=@q;;?kJ9!(q+ z_aHxSLlcLktG#IAuyl1CO&pf4&O*gO@eVQ@maeWq#X<3ooUZOb#X;(k)75Jvapd;E z2PARi_P|#papZPjE_A&($b95-`x26P1yXwcg(O~uB<==XN((Xv6elo$MI(uW;t(cY zibH%M4)NVM#4qCze~m-@Hx6+NXo3g1ACwkg?!1g7j@*v=4iyK*7jir54^$jv4stt6 z1)7mT;>hOjLlQ?0x64T4$l>-Dhq$CHD3xNiZ_RLshu{z|#v%R~NgR~+Vc~NOx|A8@ zFJ$-MMiNJM|5qI1iqHWOkU7Ze?Qn?4;1KUd63;|RpX|^r0U+~1JG5c$UjSWN4H8F= z7Zvc8%8>9x&KKcG;>hhEdFaw!baN_ji1Vo<;tM(4l##@d!@(AZcqR_e%&v1ydfClNXjJK=+4bnly zk=?T&NgUZdcW{VvfClxT<{+zA#UbvDLwp^QIC6Qu8A%+uJl}yNj$EF9gN_4$$|X?K z6_(DKp!=X;;!y7}@S%w>gCt7^DKv3V-w!0Eh9({e5(MoxLKBB(a|Sy!@tIKdUTEUU zQ1LJ{ap*7zLo&1h19Sf`sQUBJh6hZX2RhDp8%-Q^ECoo*U8Md|AyWCk2Cdg%=79Fy zfz%73iGPBcFNY@10@BF9z@UXD{tBwz3{4!i_t*(d`~g&b9kd<+84HR>6A*)ef#C== z-a%ZDcmjyQz`$?;O}qpueg{pw4J!T>O?*F8oDnpL4Bi9DzyLD;G*p}yO&oMv8z_7v z(ZoRqErP^V(Zp?`-)SD<1u=O7OC*Kmk`z#*;!3S2DZq#q9PA{^pJaEL>*JLudH zFowk=G+BYgKw4qqu$>p6@IfyBy+MJ1#hs}*#5-|_gHGT9NrB8qj>kP9K`iFuO3#)^ z>iv<*E0CEWDUhE)yLDjYJjgE~age>BJ`hYi2qXwi&!D~+OgtPaj;8%#Yce}U8oBl#D$uMQ**I(Gx6 z9(43B$S9D#p-Ad)fdrxEhari>=F33lfcy?K2YFr$blwY0{43NPkol2F=75f?1xbO- z0hKK<_1sA5KN?BB7*rf&4k%7x>aC&TAai1n)CVJpBfArH{1eRHSS0nyNb2K|#9cv( zq45r~8(Qo$R6@l;_9C}$-{TOMM=~F|-J6Rf4jQtB`3qL>fy_sq*W(2_0va!%GzL>I zgd~pK&Jo8Uu7@NJYCFKpf$eh!*$eVJOxzJky)#nycp-@+hjS2;IC6M~BZ-6V3WAvr zx;h6GbRc_?$5mR8)Pu?pnEE~>aZsLxi9?$w;Q9_ZUd%y;V~IzQA3;(edy(U1B1jM# z&dBC$hKhr%2Vq!xfSrGUZjKF7{33^s3z9f;I0PbzgUTqFzrv8jk;5SlNgUbyG$e6k z^NW$hkXFk)ACfq-`O~1{ps)d9SbZ@YDvoac0wi%{^I_-MfYc+W zpS?KLA4L*JRu7$S1*Zq(@PSTqfyI&C4{bJr#gW4Y)*c7B2RVFT<8vT!Wb;9F1SqM1 z#F5PhttEhoBbyJ(voLXF^Zh`A&~%6#KA9R*+(-JCV&t&PO0Oz|u3U9|JN6vw|O52{mO<|EhR$ngd12ZPijr}IBZ_9D9n);|WRM|KYnC^13P zGqO3b{xQ0GNhI~i;jfD%j_giYzZql>a{O8%sYf=)4M`k19=(yok_rwoiKHIc{0m6p$l?3~NgO#GzC*=96bQrI&jK9}0NIOdz95n~vis$b z#F5>p4HXBO4Z<+N(!L&eeUO+gYzwzm*T9NFGFs5r<@5Qfjuchuaz);+v7gk<;ydByr?)dj?4yxf}q+9jyF89w$d$uZS!z0W}BYR}hBz z*A$1i9aJ3TFXZ?QMiNKPkGVL+C*lwXof8FfKe9Qyai~v#u9pM39fV=-uf-wW1{Ftl z|7;|2WP7*b5Wk5-{2dN)W@rNuWG}M$lW>S%LJ~*r7X(As*Ma;BI?V%C{zpK?LFQ*6 z^_yTfS%bup`*+Cg3S{@d#%n?9k=Gw0_bZXz1M3%{y9c?Si|if{8y3IF>2Nnl5L)gb zi-V3Q21$Y3Q;y^>P@ftmj;tPZfgv_=Sic_K9808n5ZRn{IK=-UiG%v)u<%y|1ppTJ zM<9upA-NyAED=231xng5b713RAa~XwsfUd_fu>17ZDW{v=yVy_98g;tCJvq60rxLJ zV?Ho(P}qPl$Qv*7APhSh1|$x`ATbaIjb(vokQfNV z`X{jS(m-M$3_G_Ebo)C@JuFN>{4XE^+K-0KEr5hzx2=QBfKH)+gc))`4u`4-$-&O; zgUt_s#Gq3XVD&H1)Wgp0gSA6I>S291kcME80MvX~UkN0hfg}!HLI@IOC`1y6#VJT) z29h{*2_8t8VIh(@bg3Fx99I8=q+w$YAc>D40jPVROSeG63_7611QiD<0i9b1l0Yuc zp-T)v!VEP?>Ou1eU_k~3hE^nTka}3WE|F4pI-hPT&HPILLh1d44yM z#6jvOK`nlRBn~nkcFx~dByo`XIZ*Wx&_oGR3o>5-8n1~+;vn^~aL0|V^5 zPLMhBP_sdl2(&y0iNpHlAaV412X-D(CX#xPy|D4hGf3hfcf!sQyow|aQf~rv{|6*- zSRM!2YXhwpK<!l|r$EQ|+_Tt8ufX-0>#RsKkqC_rQ@WFS`Vzn8kViY3>#ildR zR@CHtTAiqbHFQRTzY!5#nwOKAotjh0fDsmG#fSHx2p6P1&9K5Q9(fxv&VmZ-#$xc6 zVZvLBQ8qPWFCY-xcWLhew1`1i4J{C{dX?lo)aZpee8=j*ol0dyU}x=MbTTzI%_8}$ zxFoTtq_hB<1V9HhKsK&|+Y5R$-YgDkljzZO$2i2N;3iE`YK~q`esW@t9=>x%^pf*) zL7S%;^z!mcQuW;ZLUqB%&p`R!-u|tf24%t&fK3gVDJ3PXSrZzyLo{AEY0&R{*9DM&r`I0jeL_{h<9$ zFnur@mwwo~9c2BW^~ErKFdCPBSU(Y2KWOd}rVmEr(hs_i4&()7{h)Clm_8VdOFwKp z1X({QPGS0BG%o$H{w8w%0qs+O>4VX@^uxwokoAKyJWL;q#-$&0pBB3RLE|MbeJ~o- zmj-qHpxslD7BGhO-yLBK!oZ@KXWN42&p~Fv$_uD61_jWd90LPG0d&9&l>R{DEHM9o z`kWxOpyl2m`=P@MAR#ag1Z@%kvrq|;T4WK>dJK@6xb&l|N9TjqUV+5eK%HqMgA<_k zL%YLp8CZUV34qpOf%JpMfMH@FIs>X7bfp@I55pk0g4iHEAR4p=1;j?z9|c;Z#=yV; z9o7LU1!Is}5CcYo_PBu9=W41x2WbIgboay36l|OhtcZbu0eo*S0|Wd94^aGp z;tb|~5F4Zxbe{k=`xg*tKj>B|aQZER}trO7we*kL#50K%Y^W&jqDZ2f_jG+4*7#PsQe*-i^Ve9Zfc7rgw{d~~-VbJa0 z0Ud~gtuq3JKWLl`-F{OX_BVhkTckVEKz4&Ly8WPa1lYpAVlqfIYW#!B3UvEH>+3*4 z1obXN69WUoLa6=7W1=8QkXmGVBM$c;fa-^x-w)CQ!szY?-JOQb{S%<>hlMLB{6OP$ z=9 zpvD3N0|W9sHXwcI?q7hz{SDJWsu>srpy3K~KWNJdy8A)%kD%~FcRvs4kQW992H1Ev z#5BnMA{ZM)_pw0yk6wSpK=ofms~Dip0ci!}PUyX9==IkG=z^sVsDnZ7ht)M8jj-}> zF4TT>b4@^-Oc)p#V0ZL^^nfsW_-}#gM-P7msDohl34rv1Fnai}hq)ik0TPQqsv-9` zf>oUjur%Aha4_0ND@f zf1umH35Wdxpv4BD_75zeK%Qs7Y(K5VVgC-O{ZMa!?FaQg(CtrU$L{|I(Bc;c=sj*w zyFnCs_=C=s0i{WF|1&HFsfOP939bJ?MFP70wj5CVA<7XXsIdvV+YBKJzP}TR%U}V$ zLl2tV;Zg^n_Ji8oAVE<0gR(Tb{Q(>d450Zzv~12`0JR^c9%Kdx!}u`T8;AWC(2ZTN zd=9eTh5>PJ3`{(R10u$Zmj5gW*bj0G2p_frmN7#Ps) zhv|p;6Q&-Wuf&Nx{Rd$2KPZl1`eFVLhT0FCUxwM^0d+s9%!G-7XjpcD(J@f{AUR}Q z0@aT!24chXf!H9N!^yw^YNMkCKSKpnKYDn<+z-+V!Yxqy(e=-O>OTN79HbD6(e>BE z!VfABqcWi3*8s{~(EI~h9|Y463qO#5(Cr495dmHBD*^3*g31BV_zSvz(40Ja+6U<` oNCJ@z468wteh?;@1lb2>KnYNv44eKJs~`%df-HbA!6dqV0Nb4hxBvhE literal 0 HcmV?d00001 diff --git a/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/c/cStructHelper.o b/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/c/cStructHelper.o new file mode 100644 index 0000000000000000000000000000000000000000..f08d64678b693c234a1284edf7e6a524c637cf60 GIT binary patch literal 70184 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 literal 0 HcmV?d00001 diff --git a/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/c/cTypes.o b/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/c/cTypes.o new file mode 100644 index 0000000000000000000000000000000000000000..fc8622348d0a1d7f5ba3d542e5dc21e56c0a813d GIT binary patch literal 23768 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 aAeQzMD4Su^-vL@&z`(%Z3oVCn=?4HHFu4Q( literal 0 HcmV?d00001 diff --git a/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/dataHelper.o b/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/dataHelper.o new file mode 100644 index 0000000000000000000000000000000000000000..7875b8385f65fec96f46399e60e5a268b3a2a8d7 GIT binary patch literal 1576 zcmb<-^>JfjWMqH=Mg}_u1P><4z@Wj5U^{@B4h%dD+zg-j<$ihey7PN9KlpHXLfQl< zpWUPR!4D)pvq$rTKQO-Gf!6;e9KG)UTYvCRIdGW4-PzenK_fJ&G_Ryo!O&38M9)Ci zuoTQStTQswGceJF3NtXUFfcF(FfcH%GB7Z>`-L(vF)$neiNTyF0(Kh%17lSX17n2% zqcjgY#{@=*9vP?{FO&wEV*q6%i@9JCi-3v=Lup(TDC}4mKK{oh&x|ExL2eL25{J1% zi-CawBo2}XnFSMfhKehI1Q{3@VB#@QahQML?o3H6N%Tm~DM&5SOD-s2h>!9!G;o27 znJ4CCrso-&x#ptFn1N+1a7mb8N*J1E7RMLlm!}rR=cmP&l;^u1jRNoqw2gB~aV81#~g ziy8Ei^K)}k^GX=>^72bk_1yhJb&E?9le3}x^t@8Nf};F_)S{9~2EC%xoJ76UjQF&o z#N1Sn&6Htj1_p2}v!NLS$x93jpm;@=f`tc6OcAOdmd;_~%`gTU4N8Z|Lh1|*3>*v$ z4CLz9f!Yrbcc|eo`$6(hAut8AA4Z!(^@Ammi1kQpWF|}>Ow5&mfq@+@4T0n~fCvUe zI)ie-euc3?bS%_j#;O9(N!u51{(%K^!Cu6^4rlLd}H> QKp6+1j!K8}VHCQ40EY0Di~s-t literal 0 HcmV?d00001 diff --git a/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/debugHelper.o b/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/debugHelper.o new file mode 100644 index 0000000000000000000000000000000000000000..4b3cb8e6fe6c31118dab00455e8cde5f4b3ee760 GIT binary patch literal 8464 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 literal 0 HcmV?d00001 diff --git a/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/fileHelper.o b/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/fileHelper.o new file mode 100644 index 0000000000000000000000000000000000000000..27d1516a7b3020da493e815658238782367656c2 GIT binary patch literal 79912 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 I!@$4*0Gd+qR{#J2 literal 0 HcmV?d00001 diff --git a/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/gltf/gltfDkrTriangle.o b/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/gltf/gltfDkrTriangle.o new file mode 100644 index 0000000000000000000000000000000000000000..7a2322c880be10dd6c1c324147396f2c921fccc0 GIT binary patch literal 2224 zcmb<-^>JfjWMqH=Mg}_u1P><4z_5W8!FB*M9T<2RxEVh4%l+ct=Ej)T$nDPvGC~$C760&s6$_ zf4dt~nx#7n|C9rV)Aab|TfnwJ)U&5`vhi+mWLcWFSzjgA8_eBaCkx*!Z3b$uzUEo!`1sBsrSL99%2)NyR);Ef<|ak zXQJROHV*(>Yj|@}}MuW^TfQo_GASQ@*0WlaD7}TINNGt-%R)EqV zu^cE{5lVx^8lY^L7|1G60v9pK#0o33W6#vKt>j4R;9X@L4z3{UrY=PpgaTSMG!gz#wtmzC}Ge`Ni0cZ&`T;V zX3$H{&&^HED`C*f%P&dQbN36?EiOq+&W7^S^Gfv!it-Cmi%KdP^omk*67^Cu;?s%} zb5o&~Q$R^GFo1I*sPIHK22!RoFuXz*gqC5*LZJKr%KNZ#3?`=q5`=M(Xmnw91_lNW z1_lOl_3J?04~tirRWSQO@-Q(F4YMCcn?m)2WU69dr|Q2i@F93+gcKLT2}z~T$0bOESxVPIf@>F0#H6Q*AR zst{xiy4@ft1*o6`NC5)_1E_oh#SyxGkhvgnkRD|002Pdc>W9gpaTx@$#63u@2dJWC NU|>iGagZ>&egN`z8Os0w literal 0 HcmV?d00001 diff --git a/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/gltf/gltfDkrVertex.o b/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/gltf/gltfDkrVertex.o new file mode 100644 index 0000000000000000000000000000000000000000..a3ed1a5100d05bb0dbe8c766d867b0a9ba0cbb39 GIT binary patch literal 3976 zcmb<-^>JfjWMqH=Mg}_u1P><4z`((SU^{@B4h(z@ybPcD<$if|{_yC$&c9tOjsN|D z&-?RB*rq1&{19uZ(aGffx_ul8vpwz zY5eamb=Rn9@NWxI5%}!Lul2&EJ48hS9&(QSS`WK@R1`k*YhC)xA9><4f8>YH{ERjnDjX7h3<9)OUxd7_?q0DR+f9@c_te{QFOSc7et_$f`r1 z`L)h}cH{>|XB;f{PJ#qZrn!RR(uH5kN5$Z?BY)h<&-{W0pZNtVSU$TzVpcGN=QF=x zg1~2f!3dGh{DJ`z;D7~1Gc^48HBP)fF(Hj#-h}}iULd=n$w4q4q&Xer;m8A@`33Vu zK(>O?NVx=vb>TC=V7<&|enIxn`~og29H03G{aHTq3x{MYQ{_|Y1>y+s>$wS3*_YaaI3oOd zZX#7ir3N651izk}M3ri(GKeF?ujeLHB~dB{;wbRzxhd=d#XbM*1N^Rs4o@&VaCkx* zB1OR6vjdd>KJyE*fwX~K?8X9Oft>BeaTuWi>V9{g9RduX(1Br`Ntg; ztZqCgwn5V$$Y7Zr97y^VKJyE@u^gU|26hkFEr$`|54H-K57LUvS7BgaILyG1FVt+s zz)ni!Oel>&K-h2i6WY?91aN_b(gLQv>}8E`@Z%wh$HKbQ$6Abw(H07W%a z2uvw~Nmd3>as@M?ggOHQgAkIvu(*iCA>IuY4*+?Dfq?-QPit_9pM{DyFhMMY#o-$q z;@pf7_gsLghsCcdR6GHiuwZfQ4HcgN6^F%h9#s4SR2&j63=F+c@efdOSln)dio*gF zCVmGhE&xi@3=9k~@qbWp1vGJn^qi73m+Ydj)S{Bq3ccil0tP)FXG0KS1R{(=8JIt)qHVdPp|T%3`Skx`7(NCFCs zT+?6xyOUtDX;`FF3tfY}gX6Kt7@Cw9WtODI7vvXbmSpDVxdvdVWKhe+a}QUE5t1)Bdr*#y~~t4QL==J0|PLhVI1rxQt>je&sy zX1)TFy-+1!5fd;8aX&~LRt|WeiNo@H44ODBUl*W>!}2wx!G$m%mak`^sfXojP`Lw= z0=Wf*Vfp$1ND%5@kT@(~UqKUxpjTW{1fervtfJJMM7@&K ziV_CBl*E!m2EC->Vg|jUd=N)3xwyoHK`%K!H#aq}gh4Maza&-9-7i$PxFj(-8_G}5 zE7dC~$}dPQDyd}90~?o`5ua9+n41c94#gBG9zjV06t~ERLHY^|3|gQ>f+PW|_mH>@ z(hLmXpo6K0$=%?DuweBjHv7J=0}kot*%0aQ+d><6V$hzj#;M9`_*qJ3xvV7#L*G42K#AQUb<;3=H6M7R*5+IzSF)U|^_35(6>O^#cHvpY|32 literal 0 HcmV?d00001 diff --git a/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/gltf/gltfHelper.o b/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/gltf/gltfHelper.o new file mode 100644 index 0000000000000000000000000000000000000000..816d306243fe1b2a4225cb79cba7b8a2a94fceb4 GIT binary patch literal 956632 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%0AZ*wY5RdM?1t7WJ)&>v- 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

N646vGh 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 z z1}je>`JC}TzHDAnh2cd0*4dzJ-CeBV)9r2Gsrj)a)9{kxuGOnnt%CT|g@2oi7$g5S z7BP>`i=Yh5>~Zm>3*!N>IFm>6Nss13ERG#DJd7@k2R!-LAM!Z(Lea5k6CcY%MN3}>|0g|BL((&-TC?!zF6Tfm(LGwfm4tb8{`Kg# z-^HHEe;n*z!%NUC;?a4~<2$%!@aVke(fJB2>(P3k#KfbU0YvL`J7{=xhk#Rx2)Gqg zD&o<6!~)c6ftmr<118ANkKrD@?h=lj*B!%LJCA{CYoFe9j!=)zzrmfKeR^{>9QoJZ z2eoQC%{#+cJh}rpJUZPuJh}}*wFu*<7argK|MxiV3TmV=fP{{_8i0%Ey|$9ctjw?W*CCeA}b*qKD=|56jc# zip4x0j5j8`~XJEYjvikr3|Dfo@D4#;XRdn-l4v?R_^M8Pi276!z!~^^- z%NQ6KS`YBI^ntRiGfVRi#<~hu!;^+5U3y*rgVM9%CC}uat#9kOUi*UEMIN1>G*9?+ zM{D@>iikJAVB}wa)R*y=BmXud#tR-Z9Qn7gFgtcIb)N9)4%Ya7f!UdbfBjLgOos`R zM{f~hw=;{6<)P9Yorge0H{;8LujCmIUHoNvs(vcO(}x+~zAXCx|9|HTkcVGf{Ly*z zWzzru{|`Q8dKvZq|NjY)d=B<7sDavioCEAH#~q-uulWUI^AF~7ZfGg)(#_K3(s=-6 zGM4sWXy@19&fgxL*ZJ4q1qBhRLeE%MW#LvrQ9=Bma~Ga5ux7 zups@8;f`UTRE-?38em65jNxy81}YpOt!$TWohHZTzY6@V7K{uG`$1)~<33QE3#?%m zD6kxNfkZ+55s7YQ{`H`^IyBSq`#;CdBdrJc`)+``I-M_EI#GO zvWkI$VdnQ56`mE0B^N97M8 z!;T$13?9t~7&~~xJS>lwUVS~8U!Gw<$OB-nfE*yvEzG|@n8k4)$U}~ML2`~@FLqu4 zMa_kaKM?-v*ZBYczejhCiiAh=5e-B(1lR5G`ib$t%aH&7|D#z0@=3{Lm(EvEo4|G) z{Kfoo&p%MgL_{~ZJ?$9o(_7C0i8JKhVB;H*!#jOI#UZ>?*rEaoZ^HwiA`DV28ToYn z_vjAd@L>G(V(mvz(c}y+nml@)HNeG_Go*New8=e=JA+FpP;eN4%m?M`R#9dKhGQ-& zdW;_3r3@b3p&TB)Eh-bhsbr4|s6*k=S)&57!2{fdXaS48um{=J>#E?>yG3OINO9*e zpU&?flLf#gBMfsptDS!&FP8XE~55`X(y)G&N$6Ztk^a}FQJ&wDmWPsx2 zn2SmY14yX^h;Vpu{R5~;>7tSV)_DvhXaTVR(jDz^QPBtUZ5T_r8){Va8TeZim>C#A zvFG4nU85pV!Ut-y1bFloFoG3=WD-C!3J{qBBpIk*TECTW_;h}UDu;%GwT()Nphq_> zY@nt!)Trn&cy!k?c=QIdcy!+5Z}nwlfYbx9An@!w3bK;}+_`4__@eZ#_^Vjv>U~dJo*8Ce>vx6aW8*^@lJGZMpIXlp4X!7=-owEqk#FPjOMv zd%64%!o1FZpmbmWtHHq~0>3;%Z;dX4NAmxdmH$9W9T?!%nn&`FmnmRDP&Q=fwOI>p zYb5`F=?5xHu!Vb>6h>gb>;oI&02^BYRd}y&di1VQ*#OG7-6bj<@X?vhcNk4AVibaE z9$3=?!afWxDk1Enpq!on&bdgUC@PS|Asr~FP7HDM@d!wL=h=A`JnRCh^*(zvzp?P> zHuLBX#%!W?KK1DZWw_oN6$MZc)cM}0(?sP((Hl^-7AwF))bJ!^cmx*59^EA>3ZV8a z2TX-Ww~dOA<#$L4B7jtaAa`|2g+L8hX!{@9kOL=XkncP@kHCEgVQ2E~crUIoIo&g_N;ct-um4c9hALb8GW@iKmcfR-OtyKWK1!^Lal2&I> zUhKRN4XPX!NL|tG&C)IG(HoHOyd z8~W>I1t;ImNEiNh4PLT9TAUuJ1q`%2??w&QR#36je53*qriVR*^8FJZ&%*Lf2mpHOs zWHzRHP(KaiK3I9;+4%)jSc0YV@;!P^ z?~YO7=+04Lft64E>+g2n0(HLvLESH#)&nIP9?6G50|%g-2^~0y@IXyIkaPy`AA8Jr zeGb$=e#GRFeCRcN{F?F7>n%RLDJl*=o!?;Aq2*z47=Xf&P&|WD6FLUz>-=z-At|vq zGdaGvq$o2l-O4K7H$FK(uehYBG`U0}uQVq|Auqo~p)4^cGX-jZhM$>heStV7L zq!!0#=EbLh4T39$xKAN9x1gjFG}}f{pJyJ}(FzcA6rlQ*7#RHXaw-)-jeLbnkS~fA z5{pt5ic1R$@{3ARQxp|o8o{y(1&JjYR-h?9WdFcIKvTgvzceQW97H+!i75~hA;rY8;00Uj?b36epy@Wy6pGq%2WBI&9FxunbGv-+6gc!(vP`P&)?mmxRcLDJD zlt<@hk4|<_?gO=M7@;#7y~PS1u&Nxa5tPb2JCDHJ2TRER|1vA z73@V&6%Xq7H2>f)clT)i!B}d@zb%xZBUr$r)0xBZ7z+#fR93J@^AQP<4;*8m<0GI^ z!Hcg|;QejzWR^$geW(S@AYa1gE1yGJY!JC_78Rdv<=0anJfvO~$Xjp>@}EyPyKn1( z5)qH?asi*t<35_lpdsPHz;IYP+R)nAFqgqKD9As^N`XN-+8`IM8=8K?JUjn6hJqWQ zpaS)?N8_6fj0_A&A=RR?f{}p%)N9XCQ2>=M2C%q6D_lU`E=YR~>~7>zs5_X$qubb{ z6Edjk(RthlIy;ML1XwR3r_lc?WC}%quXn{{Lr`vSDRl@J@Ki$grD{^%En*6GqmTj12uu ztPBi6?oN(|W?;(Lh`|%Y_H?vh@N_g`@U&p?G+|Iu$ShV!E-flb%`3^N1ZQ)2L7~T> z#Ng~{!Qkv^f|=FfrJx>C2>~hvASHwXgF-UA;7CeU0Li52VHyK28POGk3YyduMbLOJ zRzIVM0fPS?tR5CNFmcc3cN(zK1z*d5rSD-1CV2GjQMteX8$RfK@6mY|Y65hCpu0u| z+C}fKfi}zGJrY=}45t|o*MKTo$OsC|4ImMSsjpWcvF9MMC!pH`b27|NaDH!%N&?u; z9>~szSPi!j?o=#_UtjdVX2$DX*o7Cvn{XJ0!rTONJG%Ag{Qv(Mxf42B85n-Cvi@gf z`2U}gg`1TDL~|#cV_{&}&&qlPMOez1m4U&@?HD7&3`W-Tj0^`ES&uO?ykvxGYGjmP zU|7Y-x}Fha2Fxr@XI2J=E*|v7^X0>zF}k7%fxzujqwQ+>ti;C zkIcuJZm}`$W8=EW#?ZpfI)|NMIy>u9c7|i@tdNy55C^(1V`5;K!_4}D8Elsb$k_jk z20cuytGF0$F|+>XVED*9kFkT3;Uz2UTMmXltgJsd7*BBXoLOtc{$I8I4hmmy-7sCxk))p>?B}}Z3I2m>_iB8~R zxXr9Nhl`?lN!weSIQ=AOXSsGa8a5409vQFS)n8V5XgOgz!CrIKbC+js%uv6_J zPUZ7tWnc&eg@@mXJOsL&d|Zi%D^z0mGuNW!)#W=4eSheSy>;jGfZP+ZQ)>8!^S#? zgJBOF$f#>*ksYLeH9PAScCgPhq9E?a8=&&`8Vn41tXG&A zs#s4jF&qGe^Li!_a~~7y117LRs^HEExV{EeHGe@1Z*W#Kpc+O2)M)`Ne1POcNTmYH zsufF_hZcK(NedPEoJ52Qx!JO`S&@#qH4^ z-#l6m@VCAKEyL=y(L2V@;L-e>k-rtx@JWNs2m5w|*3pEhaQJAx@@T!p-w&FH_HBL3 z-^v6snenb~r-_OW<5%C#8WjOg(2^d|ybz?x1D)gpx4({omO)i8f@~;N_5=^UHy`1^ zR0mt{k-xPGJ1$;E$!3xutejqKoAR+p{-ox^O2fy0|&(7;BB|x@; z7@(;x2FDoW_O1_TF!PqY$PJq#cC8?nTVEfo2-J*?qcI zK7bb3#d&tisCags^XUBR+4JZ=w$ae?#=<4V)Quf4h{>C#hJQLOMlMKtsBa*&a|++}f3+%m&od=WnS34dxwuVZ-0L zfr){^uUF?O$Vsro<>C52LnF{J{34n}L@UWIqDV2Q*nyCbbSF;5} ziK9pJVGR#U85RDPbD&h-UCiOpZH=!LQ=d(>w(gp`z>HC zE6>iOKD`wj9=#3{ptv~h01j4A&&sFszh|c_XtE0|)a|U`(H$zW6C6g}r5vCZk$_{T zs|I-XzSBiT0<6rVGem`>2n$Md7tHVnWiRTil~l z5VRbllLOQ#wD;)zXm|S@cjPKvzO(%N4JGX>;KX#9^JJ99-WpRoxTD-odO=s zmJIwYH4F?4-km(hJv%RWw0|Y#KHW7c8ZVz9=93P-uq|N)I}J>D9(;qs2jwG=&f~8Y zK@3noC=$c~iKu}XAdwUhUdXPp=7(*7K2wEA! zYExLH2$qDEy(kvEJ_E{HU>pi9Ry{hOg6cq@-n|L`{{Q#sEj{5F>eH(WQUjVuSQ`KD z|Nmf*-q-~mjc+L)dpc4ol-QdN(piVWUQ2=$pBY1}sGHeH0DBQcZ0~Avbb;ny9 z{{8-YGNVSWX&e8GP-^E>ZDJ$>AD2HatwCWUY31H+RZy{)m}Udf508qJC<8^8-|nbnE$ar*U|6 z+Nhw6QM`bTQMf=R>N!9Ku>p96@&o7!Wj+=L2A|Fp6%Eh|bpG~v%nS^mCFuOEUlSQHq1I{$;(r3GMjdqAcu48M6CZ&BF+3Q6!)pC1$!3=9mQLK-A40df#1>3|GB0X5`U z3wU?{y1bybL`7{E$csLm&yTsNs3}1_*&U-|;M1L>VgVYp*YIS#>tp%4RP%M_1c!#d zF(sOyro1{#n?pyAiaJDF^I=9$%ey5`{M)o08vZJkUWBRv4TT?bQPGG2D|>waQD1=O z#aiEhW6DK^<0Tt-ni;hIskcN$6{;KLFjc6-dSg@)j=88LFo1d|0iZPipnw9+G6jH^ ze?)*h39d4mLDd>`p@lDK&Qb{^V0nPQT@q|tj|wQX4KIP}x%Zx$C%`TP4RJ+)<`n`! zbF)yP8kGR}>|p|Y02dk!9^HFXz#-g;FAac~kbu{HfMN+@26$!?l9EC3RROgTk}kV> zL7oA{GuZ5IhZi25J}d<=i=k;9s-;H70JI#115~+zvJhgSN{b38Tf)l){#NkR7--D1 z@dzk0qqG?qJUb7(ybq29$o>e>fQbPpx;5Z?JX}-^Ky5eBf?SZJ9YDn|bR^NIJ4HnU zR7n}Uv;nVKVDRYO0u3KXkL=}4P%#Y}f_e=dheR4#1r2!mNE0l5*GPVmU+(_$mBW6ZB(Fb#3?nN|_2crKC>0djBJ9d5t1;RDZ z$irF35Kx!;w@2d}Dg}f`=RG9vx^zM}?|{Mt+H?moAv=+vwJ?%;Xe3fQcsx3f!pFK% zhA|l)ATFrxV{qaV=wWi<8b8$@1ul`x>bNQ zg7r8;^%Qb}mAZnJg7;E_){cUd%>@x|aPu8O<}=lD@kzLXP4?u5TLRhZ2~y5j72pH* z1v_Z)j6oXa7aax$2GIUakQ!eG1_qG-8Ng<{Lfz5Kk_>T)6CZ~oH^|=-ptccoUnYYq zpFlHH78f5!Ah#nQ2e_F9TJ#Ju4_sG6n_fOpJyIYEs8|A245khgekD+`%OG`bd;+~p zPJ9wQ%pQCSZ7eQ)223ejd8;BdT@j71636u<*>K_#m^q7IiR!xk^_msTC||O zuplwexWyBwIyC!SLH0TFX*9FC@HsFga`9<6g5wTiuRFwE1yFAbx@Q(-9?1O#Q1e6> z5nZ=Ee7b8M2>s2~-a^GeS=flLsjLT|sf{#TQVI zoOC?6nSvm}07**j+>m$%H5ozf0QnUhk9+~mEN#p^AZHdZFfj0d7z_*y7nq2(rxMv( zZ*C?ZWWEP?8Zy_9o9Q^Rs~~Bm0cs~UH-XaK0;v2uq_o!y3a=h!M^GHN^Ic#rVPIhB zfo96npstXF>>0|C^g6wl<0S6=lLnSC+!TAE5ry+SR0-Qrb z_&6Zl3j?TH$f^zo1`p6Ge5e?Bv!NRncRRw}4N7TwTznQT818oFW&q{WGte;DjTBZr zOwjTofGHa(n=*ig8~;GnBZWOUHGs+-38=fckLUyAqN}CPzHv@ptOfS4!!vjnC%&{28bUw zXm9!is2$Id@_Ij$8z|fnX&Ia*z~S!2SHRql-8>I&(Ej=dQ1kx4;?WTleqOw6F8$1X zEWW+0o;_?H&FswijCul0UR*rv9Io7;c#(km2~-w>wI z!3L@ZG#d+6gWvD&d>dGp&oX26ybCu212_#&fSUOaDGg(kkM7{2kpbj}15ouQtcWrT zBfP+Q9~xc@n3%sYVReHW$PFOBi$E)iSui*7Enq^<`Ji~RfT{uQWX9%qSJX1cov(nY z2W#GSgye$`sCl6D4mOXk0NF}#{k{gOMgbO=;P7?@r43g;gVpJq1_J|w1hiuGVL=X8Cy-r;bO_G>-k|*N#kYZxxfzrYF-s>eZe|CN3}$%? z^?M7{F3>C*#P1szkv$J8+g3o;5R)!I@pA*JJ_p6mXzmB63vgJu^KD>cx{ftjxP$Y9 z1}7wsgU+MC=0;E%DgZi2fq{VmsuZFD3kfPFSQtKn2UF3dnHfaUg}{7faET3Oq7cjs zpd5-K#30DPz`%rL4!FI^z`#%s6^HS`ZAz$CW(Ls7A5abw#moRY1q4X|%47zg3IgRI zQOw{{9Z3MnWM%-J7y{)WQOxkxC6XWm0|PSy=p+$TF%XX#e6k3Lg^HOOv{411JZ1*) z_&bybp$>w>0ihlgcOV&1ua=2H8{B3D@nPa1HZue0Bohz|6*Dt{PBlRl1M!#{Kqs7l zSg4qp0ldx&RS@i7(8(vL!n};2c+`f6D9k-sP;pRu5~KrEcY^5cjG&b%o**U|!_HPOM&Ycm>7tzhKhp+mO%ng+z1ti%>h7# z8QQ_(S{Ny!7c4Htumh$LN>2uhYhlFLOsF_|ikJ@;mtp{&k^?mYOf7|qYe3@{EXcsX zuo^6`#ZV0sfYKYG;;?=;RG48qR6H3b0HwiuT^XbpBGAk~3{{VwQcgm}VN(}SV;IhZ z#noV3IDG{w4z23o;y0n<$oU^6c@HcOD>XnO5c~uz4((_`gurAHxa|n-B!ERA1Zb%q zv{e8RfRgvX>cIq51VX8R+h||{A^;^_z(TOzJyei^fuW6^fk6qWUW4U>h3t@i6hbA0 z^%RHr8yw=C(Eb=iH-ePHA+Cl)+ysYsC=T&l4v@bPxeh!|!@$7s8i)GNIK+S9FsFhO zWIm$4294K%d^ewyfkBZ8bov#D$G`wfFS|Lhhvy3%;yPT|)i1-L-kJ-$dy=>q7=#!^ z862Sb0(5>C$YsSi#9N@^ps_WOI#`NX2o+xdH3wG0?u3eiCNq)MpM{FU#(BVFIt&a9 z@1f$LH8UXfu=K{k4RPlIXx4y*n=&`ZU!a}>NHqgIrB-lb51&0a)C=-}%t5q^VD1U$ z!ER0*4)sgG;-JwIh3Z&DX7rVXnIK;Q(5NGAXZjLJsaeo}* z892oAaEMpo5Z}cIiAT`57RaBVaWoKp2Zwrje(dhoz#*=OLp+BcVlS)@4zs@phx*Al z#Aot@(g~vd2^tFnxqmNM9MS#+k9{#PFg(X$&U+lF3xMoJv}3_zTnr2hN`fG9 zL^~Fi-kgL$;)r%Ecub3dfgw#8dwAvwL&9eRG-H9rtw8=dibMS!VFm_4q<#=+d={ks z2h^MbXvYgQW(5*=5W#M5lnBILboGm%;tkM#9C*A5)EW* zIK)-Ov8(sQA)bUoyab1M6Atl7;@I7PMS_7r09vMk`~$-eLEBFIZArA55IKhxj`j;$Lux|CYh-uQ*wVxC68U1{xCt`Q)rDD0~pT5zx3DNL)w`dpO9* zfz%`Vt)THbkop8Ui1`Yj0dCOg8sPRi1H%Ly<~+tB{sxD*raX4{7|4U%gXkB-;@(V68kB?8Ts4z4%G(z5&>zN!}VrZD0 zkysR8Qk0lkQtX-R8l32v?CNT0guG+dGa%X3wJan)*gQVC#K<5mzoMcWAM8bn6mxMI4% z*~m3BlPt56Aci>yhleCCdX&yWtLV+=Og7_1U33=sus zH#7s~eNaJCnwMXcl3J9S5}%t`;7LwG$P6wq$w(~D@C-JMcMUGFNG&W)%!x0_hwu|U zgG)>b5;KcDy@O5TGhJO>T})leptj@62F|9gLEgcJ@i1kjd6|W!sqqCRMIaaA%sr;@ zKAFWOrtzM+1v##M!N&21#$a}QN@`AONoo$f>KSYt@9G-hogCyHYz%Xn zQG6J9_gQ>WVsWZxMsT8M2C^-N2Js$=#Tg}uNja$?r;}={D{9~cCwc~3#DlVkMSOfp zYDr>dj-f$(aB5C!a*1Ja31;Xc#f)FDW4xh7yl;L=d{JUvdTKl<&NB1TT|p8?2JtS? zt#e?>6tFBzDxfGcH#NQ}6{I7+AU`KFxe_d8XpZn5tn%|oGIaGxGH?aauCA`mrk(-b zAUC^)#0Lk&=LUHPyTu222fKg>%lP0DL-WkMlGOB~#2m=s7KwQ!o=ITMpvdNzurz zH8hU*g*X>n{eTq&ml&GCEJ{jDiBC=}E`enQ;{nKsMqpQ^O!+~&& zA=okaDo1A{XsO^5u2+j4#P|4ah(dHvw0t;PeGoYiIy!OlBzK|$K=nJgsP{&SbW>z+B$cLN zGZxbCGcGPE0_Tw65|iZo(h>$xzcDdBF()TKIk6-)KD8n_wE)x;VTg|k@yvuugX7NHVJJ#0Hv%0h#SkBrmk2J5kiv;b10iLw z2{^GJ${5T(DA=;hL}mc|17#CFg?2)=)d$xKen$*F{-KZLw7s7;rYSrVU;S^#U; zp$54D(f|yZV{oWWGRZ8CHvw4*X=|dn$P(1&E6Pbs1~;IiQW68e%~Vjk4IE!1xW8;f zX@40$GGJs7kEP>o2r9DjQY%X0ld?-73DP^bgpekac;EQE)YKH{Ab@KwI3op@7+JvT zOHh9{v8X7qGCnW0JRVYef+7{v!$(mAY6X=++dN6B>6v-)$%!S&8Bmd;RA@UWKDi<> zJ~a>2Ne0V~R==Rp6hjJ9M|?_getbq^UP=zA#p4%TVv(6&3?8>K@yyFCfwa7#gQWg$ zZo#f0@ga^*KCa*<8oFvoV-p-ni6yBOnXr)qEFIsRVr)%iS8Q#0=sbo+e2}+aut7Xz zNE}qKAX)DW>D+{b1(#Stn&g@J*lhqcuS1agGEnuP?m=c=I-#zJE5u@`CR~=7faVBX z1A86dNEMLNbRSBM@NcM3&4eYZf<~gGPu%%y9$zUK)D&7{9xlBq<11ft&7Cs;>`3s z(0~r4Gl66ZH0p?qZembqGF<`tJD<|Tu3G>XFwjZ2F&^FZhSg8IOqCTT%lx)G=& zm7bJnRFqiG0OEstahYIlCPWlvUc?YI)Qoeuoy^H9P_{yAeb92A3Su2n&>; z6CJI=`8ma|nfQ#uYZTf53A}Yi#H<@%28jnDiL*o3hl0dIki^BI;vjoLYh_{Pn?S`u z>O+y#MDmB0#I{6XM@4SU7<_4LH?>ka=#B$9Hb4jTLz{+94Zb{k8DmJk~p%zW<$k6=73f! z!pvC=6-PJcGgKU;9&|@AO#N@DIJ){skO0(Q$l;I-6$hCETHOvaCmSjbqLAGWSsxGC zz5!Z22~+=1QiFVZ$?sYjwFs8Zmvk;$l>4v6$hCQS|toKKMYA6w5As(9t{--*^3+wSCGVe zklgbbNgT9C2WE~HbUiP~9MB0(F!8BK;>hOYa)Uw%l8=zZo1o$#_k(tA!OYnT6$hD* ztX>wn&KF(W2r7=7rIUpWIl2_uZN0* z%t6j~H<83+kiy@J9}#Zbki;FK;vn-ubvi8EyrAMB^Fe#OVB*C{;>h)EFAniVNa9&Y z_8vqMM>gjUlK4&}^}NsxQy}*s`%45Wj_!U*s5nSHviq%(#F5<-g(Qybo(v>$l7BTp8-=0u9cb-6Ec~sZ;vjR7%X4R_ILI92 z^xy{-2dPJ{FT$YW=<3su#F5=!4HXBOgY5nZP;rnsptc{(or|I3Aoa-Q|7xf>NIkMU zcR|HL>OrgOVdflyileK)2o(pZ2krfYslN#oM_2y`NgTPHaS=k~3uON$BZ==tikD)j zILKb)aOi`IgX~Q}Qa=MK4pI-=%?oqqT&Orm{T3wki;%>T%kAw*;>hM7go=aAw?Q)J z7*rhH{Atj2&>(T-e6$Qnd>@iIJCMYY^UHZ8ape5+4M`l?{pQg1(I9ss$8R`P9ONG4 z^pFM>2dPJn-#n-|y80$0@gqp??}Unj%t20v6QSbh=B!2%2kkM1#n%xeanRAiF!9$& z;>h9o2`Ub<7r9*h2Neg|i(D?rLyr~!i6e)zIg&VXI7cCgBioyVBz_Dj96JILKef_0emnILLhDcw`j=*$SzzL3@i~;UpT38R zgWM0=Xy z$b97X=OQF=DdrT9JyXwfFzC_4$Gn9Aoqaw{KDdE zJyaZIFX+TwnD`bXapZ7@9h?GEAB+?Zu(RPn;>hlti8OA5-0$0lL);K){Gk@f{Od^l zZcq~v=1xbXer_X@`ZgTm50S({XHdY*5r+0RLGDKuUjyy0fx-=BFSOaukPhwdz{Ejk z?}19fa%jH>CJrh?LE@W{+W*s$+<6IFkHgfLffO?^Fx*2EkAsSTK@$h%ZLk!yUWSE28=#550VxKZ@2e}i3Vd_C`Hkf+k@)OzKSfu>o2~rI0 zH-Yj5%p7R;0*`wmm!F_94UiU)J3;r@!PJ8;v4M#rj~j0V2|~?BF0Wwspn%LlE)PL< z0Z0qTPsroR=Rtx{bCAcAp~(~MPULU~wHZKKK;{=A`PT&`2+C&+4B%6BVD1NI zT|Fr8gTz7M2Ew4eC5XQqL_ot0xII{WRt7V|#RY>N;%0G~Mkkc)Q z53(9WBbx)OXF%e}>Y>FdIQ<~2ht)sm>R~5SfW(p2!|ElFII{W3hZ=L4we51F>QDg5nw^1#%}yFH9UX<^~f-Ru8MM(A7@@ zDTbPl>@V0kSLo_t^(ROi*`4c=%t5vnR)2!jBfAq;KckDEK{5wf{S_o}Wb^MKi6g5A z-OdG)LO1^#ND%5@WcA4D7TJ8{bc?JWSGt9rGmLI8tX>6)BZr$7w4MQpBijqBKSAQi z_QL8tkT|k>S0r2dPIk2X?kHNE})H5hQbv)x+8aAoa-hUcsRr zbp1OlJdxESmmA3S7idfjq#jhRf_B%#@-K)D5(n9fTz`S)f3=&6I z5Aq8(anL!sAaRg6$n{YUND!JYknIK49Uv)?dJu-yE1(i6hrX z$mIq~JR-$Aa=XqQNgQ+`2h9D*`3t!{Q-P$u4XGZSha`?{{$8j!$iHq#>Otorg1i6< zH&7b`W-oGjL$(*W-H0p>@*~U~WP6e8O=R_;xPz(hMsiO&NDvy%pty#)2bLZ{?nL%4 za=atk3%1zSk~pZ10dvoOByrH%8<_ZUBymvMgNeh=2?xas zviYEMEkQ{OB#xYaA0nB9>|c;Nka|$`fRw=UgFHwOS}uXo9?V|Y`JfNj>s95Cf<K#M=n=EeM6Y}pfUs`4^j_0vlG@|g4K^8anKE`AbUXSVC`p^ zI7~h0oL`VUNZl%=^a(qc52PMcN5lGEu=_JW;%h+nHh?rUFfjBX`D-nbIa8tHAoc5z z)Zd1RquYyIK7;BYn13}v20+s-vUmUv@opUAuaLw+eHobff04wI%@+k_eyF|3<&O+h z9Hb37d~A@!k^LJ96$kkj*_>3UILI92@XUvbgVclaILw`8P;roYWhu;^ptIXSNdqJeT4M*A2dks#*+L*~~&eQKCFQ=sO6!T~v)cS6NM6teq|f&`%DIdV8d&bNh_j~vd| zkkliG^IbG?SU7(|5=Rba(ADFxa6k@c9_V;JNE>o_0=mQe}VEENE~E7az6z$#|jchHy_p?0jURJSU&~1oJ8)Yfa-LRIUu#j{S;7~g2X}Q zgWLe~7buQk;>hs=TB8CJNA9P<#@RsTBllA-ffPg2IdVS*x!-|o{wE~$$o-UGNaD!x z3!1|MNrBvt9KW#fVUT-};}?|IVCs?M1vV}UQjZ+Jpt&<_>Op;KY~rA>g^7dO9c?To~QjeS-VB^>zwIDac z+zFcdgQ-VO56JB$ay*08)<}FR*+KQjeS-KywoybI{cz_Xm;90l5LD z9yxwNbDA)5WcA4T8suhJydb9&Wc9H84ss_5!{Qy5-$Cv~j(6no1mt)Jt-*u22RYtB zX&5Gs951Iqg3x@89PhAkOORWT;~jbY0Xg20^EI;hOi1yI9PeC6;>htn7|MC%_(d+~ zk>d*#wxFN`g%5K4j+XO~4Jyd#0Xcp_VFtpW=m(G0fC3OC0L38jcqki0A=bHC>zsRy|SHm`gH zNgU)~SiU-oBo0y!%L5OP#6jl6&i8(aBo0y!yQjkg+HMD_1(^>T69Kt15J?=Q9yWfI zgCq{p13M>t2AVkRobU~3;;?hVzo3c3&I#v%t_uR04Z^T8PJ1ZWfJ`qVAq@EdC?!fLs1DOxPuydp*qN#_CXWc;(2e}{C{{h_# z0N%-f`OqDO??PR0RscW0wi&e5bRv&l}O?s^NT=|3=9k(kiXoEclrZR} zB$gyH=p_{wGk^v3;-f%^31K}5Q?Do=q#9(Np`HbU9^4d=rU5$N6?8xYhC{F%3;{mg z0e+~XUV3se^k}qr@cA!L9}w1v?q>t)o&AT+E2N%?fN=~UM%ds!#19s|;G>R8m@irA)&-V~64+q>${zUzOrMF$Jl}hqcr|Efidp7x72SP{D0T^*LI2 zVs#$g167cZWq~*ibi!3U_-r=@Xmtl}oa)6#5jvCzq95EqElSPN1D{K!hwt=mz2yAd z+|;}h2EDxel2ko+zfj%clEma}C_g=~R1b7XM`}??CDfy-8S!aFiMgo^dg(>^rLc}K zsI5%_j^PH~+l6TWY#t2S&0zq|bAiUhq1|=x`eKkST>4@CRM;2~NWVLDTo|MeW)3d> zptE2=>Og%B5Dn4~G83i`M&r^CTi=IlKWOd;rVmEr(hmz>Wc{F9kYM^?G%o$Haa&~l zpj#ec`d~CJ{h&2OAb%tKAGFU6rVmEr(mw;F8EHKMDEvU@L%{UGXk7YX^90E52hBmi z^ucIc`ayHWASWQ}2l)x64@TqC51X$*)(=`g1=9zkap{N6S0U>Mt(Sx8gVDJ3!{#fH z^@GN~VESM*F8#25RLJ^4^8he?FdCPB*myCre$X5ZOdpKKr60D>3RypB>>8#IM&r`Y z0v*pl)(=`c1Jehiap{Mxb3)b+iW8VV7>!FmZ2TL!`~mIpfa!zLxb(xuQIPEijYY!r z!D!GJ8OW>9;WSW^1!LH{t2@yBP+&m@%)7WiV}2mBVC5xD-2~7i8Uq7^1$6Kgl>b2E zvoQZaw`(zg#)CojLx*=^+8KC22E%y>21qS}$G`wu8wWBIUB3cUKWzRBrU&F-7#l=` z*2;m*WP^>{fCL#B7-0IL!*@_oO#g%Y1=0^%LkCv`x(6I;e-lU&Ndn|n5Emv4+Ft}> zquaj$Jeb7509um?QV+wh@({*Pgw`nzXzo7&ofw79(}UazauUpbSoptZ0Nu;Zz<_Rl z0Q9O}P@M;}3q+&a4_dDPj(;@!H9(7Y85kIl?FSi&Za*lUgZvL$UkkDWgy(`3V@Yoy zwIF#IjsoBNj_LjlQ2l7hmjT`Vp^T8VJ?P=r0d+qtoIv3RN;~N8--W~e3sCzn!yF2w z(e2-g!~O+O`(f)nLH2`g<3+chn+bdTZGc{sjy$Ffass;jpm@g?e+HmMj|>d(8%;s> zgT{-|?KgzlkDmT7LhT3Td62y@42wS)y#T5oY7#LvpZo}+{8VB3v#UQ`}iGOtW7eMvH?k$GtM|VFr z3-y%|D><2en1e?PueJ+7Gh; zN;iNu2{14)a62N_*Ws}L0(3zN>|R$~_JijAKvtla zA2XmEB4Fhw$p4`8P0;N>h0A_WVg9|F;6*Nf zK;thkeK7HZQ2(O^AA0IGe7~VA7&rSY3Tf~Q2WW%{{iNIH2W*C z_#ZU>0<$0He?@Lc`h%@6fw@xy>V8oF3MK}kVc7vjYeDsc!Zh6t#BXfp_;6pUf+2XjE>3exU4U~SNi<>}a0fG8b==wp+3NX?>Xx#$zpo-V9 e4Qn7np?x(d6HI}Q^~0wB2Xp``8F}#;7X1KqGo)+) literal 0 HcmV?d00001 diff --git a/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/jsonHelper.o b/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/jsonHelper.o new file mode 100644 index 0000000000000000000000000000000000000000..7f456e035e3f1f4cd52943bf57afa3773d487293 GIT binary patch literal 488624 zcmb<-^>JfjWMpQ50!9Wq21Y0wnc8rW4bF7{vm6-CFr8)ssXfiW0M>Jcfq~&N0|Ubq zDE}-21H*X+28Ihz{y8Xpk%58X5|n+Ffq~%~lzp9nf#C*}eUpKK;TDvApMinl0hIla zfq~%>l>L~2f#C@Q1H)4&{}}@V!*eM61p@=aO9lppS5W?21_p+AQ1(X#28K^i_E!c5 zhHp^zcLoNAA5ivB1_p*-Q1%}N28O>-_CE#&hW}7DBO?O?C;&iVz|6?Nz`_U#2UbP~ z1~w?0gOP!O6Uyd-(mad|47^Y_A0q<;Ka?%N$iN^7Ws5K}Fo;6gVvGz7;!w6EBLjmJ zBLjmpBLjmBR7{qUf#EqL1H%g_UyhN1K_1FhWMp7ag0fW@85mTdY&Av(26ZS~laYZz z3(D4JWMI&NvUM3581$fQeMSZb11Q^&k%7So$~IwSU@(QU%^4XOEEpLWEEyRXte|2x zj0_C6P_{iI1A_yU?Zn8y;0$HEF)}c?L)o5;3=CdSwhto%gD;dFz{tQ5$jHDD#K^!9 z3>6DuWMBw|vcnk}7$TtTC`JZ`Xec{|k%1u=%8rB5@r(=%2~c)2BLhPUl%2-Nz>p4Q zXEHJ{WI@^4j0_ApP1U1H(ipdom*f!xSic8Y2V4bSQfkBLl;1D0?m=1H(KhdjTT@ z!$K%~F(U)R5-58aBLl;7D0?L%1H&pPdkrH4!&)eNJtG6d1}J+IBLl-`D0>Sd1H)D* zdmAGI!*)gnh8>Iy3_GD>yBHZ5b~7?C>|tbJ*b5cg&&a@V0LnhZ$iQ$I%09x#z;G1G zKE}wva2(1$!N|aH63RZs$iQ$K%0A1;z;F)AKF`R&Z~@A`$jHEO3Ch0A$iQ#~%D&3T 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�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�mub|a6Sn?E0&@pxfk6rK^h7Ueq zhArXr=#^muCwTt#hdeqD!l$41fiAk~wej@m4U_Qb{OED;IjaZbcX+yS6!2(0;KA>5 z5PUcG9Z<*C@-+XH1FkJ6OC=par!TjZgU-kVAIQ9ynSlX3-U~XkGXW%gj174Lk?`7F zPtf>NuZxNSIFno6fg|cy=D}=yd>}y~yF&>tNv7>7W2Q`5atkc!171-vw&0cLpecjyD(Z>QDT2XqUrV~2x-XSb__XQu&{4>|)Bd{CVOXva_ILmyCg4>G0V+3c>t z=+SMX;?aB*a;mcjXs!`_&?huxTAzVZ{x;C;;`K~p=3^x1jCL-PbYRW|=%f}FAH(fos%zvVf| z_~swbb5~tkPV%>|`TPGrIMKB(`uqQX+62dAY)l@#B`OA>>O=!n1{#3MKuD_-oR+$g z2Nd~RZ-C7_QsLA29Z`~irv4%678C#;-3DMv^8+Ltc>ezX-(bhg-^vVfd$*$oBnS>Q zSTL3Fdstrf=)A~3<-p6=f57LfI&h%sFTLAf$6R{DqubHJqqooiq8A)|E$yIgg5_tA z&W|Adt3mp~XUDog=d(bG5Ybr{03SgPiMbEp88{aPaJ$b%1=R3!FnH+%7KM~^mXG*b zK!=@rc2|H_-e`c*Du*X{@lO!6CEo3#!g270eCP3(eW0)e=UWfU)BG*=fBydmSHa*u zF4#tB)oTE5TR@i~!G{kZy)U26SNn89)n_N9riC{%x?$NB>wFqyT+yTRJlGykxiRPW z|NkD%2PKfjIxxjrU;q98|7AW%qVwa+1AqTR+DD)g6Er_31Y^MGgd{;Z0Bj4aQHS9~ z^x_=aoHGvf%>v@4)&u;l zk3h;gU+e>|wDHh<;bHlqR>1>wixhNC&k6p%`3wvUtq1r!rZX@wfEJqwflc`bb5!er zQe_YLYPuI5mM8do=YaaH`$5ZiK#SZwEPvE-fEGrzf`mI|RG=4SmjwEBXKQ$NzVqp> zR`9fZ>&x%<6}0B1H59af3Th3YZlK@re^uLL3^ z9p>-!01w7TOT4}TnrHFpE|&1=t_Cf3DarTT3v(!FO(7(mf)*V@7Q>YI`*!v$x5J3oNiL7ti~JS`8@^7vZ5sN3(-d7$+` z#SWj&-@e`T0=}*POSgJ--gx=(A7tSe=5l*nXM?L@*<6lGt(6sQv6Qwp&NI&OU9K04 z)}9FS?ED5E`~r=9fjsHaiE!x#Hn4$a2tXj76Yk0PL)64{H|{1^(7sV1=No9a^%PAhvmfly$qPM0i-bs95k% zIRILH!wwd#fv!+#uwdYCO$OBi-99P`pd~mh$;=E44VH`$6G0Bq@BrNd(aoaLV8O`W zst;-+b%VCO`+!=xprvDwGS9;rbQ!&miUjByoX*4iEj^&RyEm7^)AC4Z+)L1E8%X)) z0A33NKJUA^!h?aog+ugteHu?oF^I;u15Ad}UmUsAD zK!ehrpurbNUk$oMvJ*0G%fGF_!L#$YL&HDD(smD!b){3GLqof8tR;c3e{le-n^2?qvno^jj( zY9kt+1TDQiZg|O~6LJp`_!2ls_YIa(UPi$6g>raWUg2*|2e(~nA+2Jc&Qu9Vz(Ox# z^65-ffL+-GK2;sDzQBnCd^wMcior`~u%X~`8$1-+4LSc@uS3{aHuh&2t5{D7J zKVf*g0ddm>x&yFS)or5!Ta<*9z(H-S1dmR{g+7py1=N~CzB&ZSN@!4sg35Ggh`?;e zVk=}+2`$KwJqSK^8tTWFO8@`=2eDsrV=#U~hk{@OmAnUE`gEsr_;lO*bUpxW$2jL<)UuoM`YLF=efJND|Leh%8$K!=9-Sg8U}GVpKRzlPo}EWM7!SX+0&QG_mv{Rh z+Wzx0c8 z%mX^BoykMnodewOZQc)B6#zP~U4Xv@bSAY&=Wo!+CBH{+KWJzgbO%=Neo&zc>gNjh zbUuO)L>hQl7d!B`fG*PM_O@vLY0ux%16mpq$k-Wd0gg?N%a1&|`8+r;dVIg+p)A&N zz=PlQqDQ9~SQ30H%zdzHpaD}X0J@h0bk~Q3hjp<;Nufulm`C$54v)@a0gvXt|4Uds zS}&DWgDQ2z*c^W=XvZYZ@wqULpcI9cp1>CF-ETS`ZU$9IM+QS6i=mKdggHOVGTLNAo=hOM#2f8NNr_~~UGVI@;(7213uyfgXb&nRgg`g6gH8rxJo3^S)Pq7=PUX4h14#S- z|Mjm=GcYjF@7yaA@0|drmk`J_aPu1llqq-#P-W)cL3Jy>M#}|120si*4ak;GxOQ|ORHg^ul3Sp$?w;poy z8#+&9!&)lS?aJ}`5{%DY%JYd|$DQLf-JXWD=Z3+02Moyr>Mw)PhtUcL5azu^YF`Iwc-J^9}4QR*MwI*fKe@Ak7hwuv%?*%8kuW5FJUhQ5Po9si_XI6x z#Ja|ND6aRkIqsrj1B!ESQUNXb>@HEUfpQ>&cvx0^-T>9{*jIdFUDrLj-jjg=JeETL z^`4;~ogW-Qjm+jZ9Q@n(`L~H#oPykK*YK0ok$=jOhF|Os{8Ns(wmc~@b7=WiVh9@8 z0}bi9bENU>IdFhxxELJyXCHClcYWZ|e1rqO-tRE9z0&ZL-I0IFfreio^A5VU94Ik$ zZ8=$D05iw|WRN?iLD8`;oew~#B0$F>8-B9!PdNy3Lukv%l0eYKxS(yp9ZQ%%J9r@D zlZPCOQPK2V56yL3JP-$f5;?>Z`6;cvMF z+8TTfTpxfIiSdH76sY3`9`NZcbpV~s>;M)8&D(toG=#Jw6bw6DVpLl?l&~_VxceR50l$yUh zG(Uir@U&`y)={)xDnU3<0wmJyECJGH=_k|5#H3%ch#OTx$UF@K8_Xqa#U__Pkt3Ly=T?otI0>rf5; zmIwbp=e<06xfo>THa89nNT|M?44!fc=kVxu<8U>60y^T_qg%_PTLKjJpuNhPuRJtw zfPIhwveEKwspQMsAcx8`cr+gs0A0oIY5A7F#S3H*Xm1Ck%5&^I(sH2m?n`5kFlgHV zXpFntivzr~y<5nm+X5V+;MfFppcz2pp}5AoU!DieQ6b%bezExxbX@$U2j@jlCOQZj z7k}yg7c#>QDrkwvkop(Ye)jDA>KFp*bbzLuL3?aELsUeN`im_pplg0XYldA^5^V_yC%t?cD?3YXzId_vl^&=6kfhKud4~Kn@2nB0vnV zO7JXgvWtocXul^bXdRmbC|)4zY(dkN9Q#-q7#KRBi-JJMNVFU%b>QCy4x}3BRuv!6 z`4`Q{L9@554xmLRmN_a4ps7=5aKXgjal8fWe{ktg_3!_G@ZdBgy@M)mkcYt2$iCny zf5_T^^Pqd7L2Co%fuiwviweklAQL<+5A(McurM%y7bSwO7YDCXRAy#i@NE9i2wfGh z5;Rv2+6sWhnup-CH$a!gGV-@XGchngu8q|Nu|UgrL17PaGss3zP=U7GfVS5eo&@b} z0|h(S4WQ!;d^&Yh3~zga7UhOKf(6NvNHgV4pm1(H0?NHEs0VPs$LB$r33P9F zCuExaAKstx z=teddqQ|G(2$Y9F(=;!wz{Y~?hx(&?57?bMK?cGS1c?3e52#$70P%MZIAy|9Mz@eh zCq(Zup^i)V2cJIKq5`r9q84VzcaP4aU=g3r zPy0XT(R3(766CiIagycY&J}hYw+DXNx7vgW2>8}rghnip^19l&L zlAJOZzfAcLog4=pg$Z&B_)JU?12hWahnQ@la%jC2f?3Rf`+PEt`n4lOMSOVIuaN8s zu3sTlEpq*80OEk_^G;}G3#(r>K#QmG)UW$NmoPB#w}8rcAL|-$8B5#x6*M~`4ys>S z!1Zf~iwbh}%7R(FIzp@0T4?nOI+n;2TD>}gs#ohAaI@g03%Gi97zXt#q$~v0uaMFS zTr(iouV;NgGb^5**HG)%_n>+crG7n%rG70@;Q*<_s9(Wt6e8Mug8XY{R+v1 zuzD6$1%meefvP~t>Q_j7gDNIayK1z4g*5KL^%<<5L|uCTs{x_)5oB8@sG>zWSp!m6 zj@GZBp)5$70~A_B)UTeM*BnE^RV?V-E>IUX0{x^A&;bIV?rRHl`~GpzSzMj49XOz) zwcuS?&??mckIrMTC~K%u31H%HEd_V^_JDhD@O7)*klvgJsQ2m53R+za?pPT^dY`R_ zK}~Yda0s*q3(72@9xQl|d?(~kJy7=(#PV&jseL9zbmv4bK7ejW?gAPPF z?xF(S``4lZ8h!$GT{A!q1?LlROYoSBN&<8nDdcQ4f6s2nX$zp!R6Nj+Mymkp1Z^bB z0ByPluQh-+K0$*Ly(KCMU={nA!D~eScetoP&T0nL;qom9O8wx0TL7(`K?wu2N?8Eh z`(*)F&nb}VnFm}wgT|YYdao~SK#g$tIW6yC10SG%FxWkyQ|j%J`oZ>~rPZK*a2zN+ zk3)h2R04Zi9_4TS3tHO_I=k=}OxY8VvgR5U0a#CXJ1EFOdm$mq$x$r22<{0>H2h}d zZ)pRW@SBOhC6tMQq2)Gzi!8__sD+?l2UP>0*l{)d59;lJLJI7L`%Ivf8gE}Kg4$C8 z{8J9KT;gwa2X)^;rs+cm2RxgPGJ@@4gUFO#^sz2c;ozTg==FK%I4vj~IRrp!mpMRb z23$QKN9xbQiZ;*ABRAt)G?$9xSk}{~Vh@R*{p$JM;0$>Ix z(Z6H^b?jjMUC>zoa6R2zp!Ck+(Fw^wATwcYPJx%_LEX#=FfoumkYWL!?j#A2AlULw zXpRHhGY`BU%<_4O5-1oMJUWkq2L~bJz@YyB%QOG}|A+JoVFd|jJO(ym)}jJRcu2i> z@FAFuM?eJ^YVRF1K8V!s23ZG=HBi~&WBCZw?*{c#A^meuUp0sW)PV&>G+5niQ1Y<` zt+|+T;3a5>9%6h0mLOoM0n|PKWmHgbLfZ$ok;4Y)BTNG-Jg4YKa#I&fTq z`riQ@FtcImJi4nSKz(MA`(L(#JJwUc=jptR2d%E@o&q-Yr50>C1xOuaD?g~W2wH%G z){h2tdBMB5AXNqael)nSff)og8qw{9E&GOblwqk9dqobD1yxO;`dbpl(1P{o;rieU zN8sn?z{;xL8tADpuW!-LW$iGRA@}7`+ZZn+pnX?R7ug1hZGqff1_eG(o!%u$Q`k_@DTr+&NzFnE;xLfUj5o?7^>f;PrBFzC#NK36j{@zpqVai5)1ei8KFT3%19={kIH*MKCgun>I-JLZIzRuJ zU%*Ah#;5cBXVBfU;KYk4@IY6~c0&%`L#nv0g8Dv?sd~_gJopt4pmtL?`uS@tDlc2W zgT$aY9JF(pvY`ztP;Cw#X@NDZM$ctJR4tHMHCV`i3PeyP1V4od`?*XEPykYnwjSy; z=zJj1+*oIbiUcU26`0V@Se(JkzyRqv34q#@o!}$vpv@TAVDo<;(0OR!DAcdfb0*`LE^aq$U zsGSUD`!GHS=>+YGgcuLKu@_=DND9o(uJ}TCojgD0qT&l})ON?H1c1(DiST5+ z>tp%4Bp!5LlK*S?e6&NuU!@XFkZwPiZqWK)KZrY<4>NjN-YwDM-=^)*@HeLPB2>*c zpH7e^{xM)>uMZ&Fqac%fpsGMhd|>Wqf%Lk2p>w^*T~sPSo&fdK3qZZWf@6?=J?H`) z{+5}bsn>2u(E5V9V+|ky%LDxF<>0gdnanl31e#%e@2PnL><-AHtL_q&0??c)RH#O! zzytfacaTT`HJrhnKIloI_|k!Ojfw!|ggj6j!S@h@It3hPX$ERLB$0OWg1icfZkQ$A z4lg`9dsx6J8S0MC7NjYl?i!T<59=Bgg%Uo{qP_$qyGlSiq+usMbc4^e$X%mLx%od@`6Shpoek1G=a<>&$@#y1<^d_(fPpxwi%8ce0;R!2mY3spn|;hfJY}Jt9f?* z^#E-Z{O`ed!K3q)1OFs&*)8Fr9iqbF(fXgi^)skM2dx>B0qKMdANh3Gs0i?HGxY4d z=F9lcvBL~>qdC}fu&#{{Xmf;*<=4`zm!J+StiRpxlZn5zp8+(FUkAET;uYkKA<&2x zKkP>IhM$c5EuTT>Y=9Kc0xPZuDc%ce3-;D=7=8nFpFNw8Lw0!hSbpVi`3<_-ntvOg zXLlKgV+X%yXE{g1PsY-IkJfLc^PoLHT)XG_tdtf6K~AerfjeJehAJr&d_&{bkD-Twdo4>pJ6 z|Ns9`iNByFUE2`lAtWN?89;#nTKyaG@)zi=X?XeD@QbOm8hk_osDwMl%;0g{8GN`s zXhB8mHbmHh4hsV9+cW$IUbX}aTTjqw1)%e)`L_vsbbE6+c8Gg+`g1h=Vk}((Hg@4Z zsN0atF5ULB3*3YQt%qYSRR$|u_3!_GBsF0Fl=i-y3|0tUH`f{q3Z&MPkcDgLYWcy^ z;43>o@%4+jWKY8{j*`dVV1ma7D7%9aZV3ZiZCjn|O3ix)`a(Enkz~b3i z%HYBH!L!p9wDrdVsaXn%Kac&e{X3vj03|>}JsO~WmC#Ly-JtU_xQq%!A+U7-*@D1js_rYL1<-bckbnJ#wiD%INR|0zhMZ45hrVyamo^5L-a` z(Bt4U$X=S)&mg)Wv-+@N5mYzOZ~qbI0V3f{?vbAQrXP(uc>KMAz4475MV z3RIax_9ub54E)>7JUgFw^wy|=Z_WV+BdpQ@?dTLN2ekEDA2k4?_o>gUM~Ur9hMv^-H$Z7U!B2&w)@q= zc^E{1GdSqfDbVghc6dtw>2LsZpU$T~nqNH*{$=s7Jj>rw1**4O-$J%vc7BG`_(wq} z=rbPWpL76p+8T$C=4a5k^Pp<}HMqWi%isDR#DHCi0y;aVS4RST3|;4YlzpSHV#e3< zJAX?oD8qHjsQ7e#eVqUr_k!2=9?i9&D*P-H0|Uqu{%zbaQ^3_dXuk|tEhOJmgVZhr zxd5_J6}p-hoN7HS-}ASCW}x`D`7(fRUG3lo?VSPD_7g$1{Q_9B#&K2-zq|_rq`rr^ ziS+v3qZ#DB)`b86|6|nmP&0|G@1aJC{{R0Uyw(F;--8x=LnZ#8)%PCVGAf{O1y$0% zmd{JWUxJP=LzFKzOrNW**gx@iC22bb(;Gm1Owu8$gklR~aK~pxp_28z|aqvoI zaM=1<{^4%{bzL3#x3PP6`*UYaAtM5VgUcsyT%h=RHjxU1M_cqKWdu=#Mp1uTK83{TEto2(7Kd6fL z>HO}a`3>xN(Cs=LpmWVUJ7YOK4nAc89rEnKc+|5q7gWik9a;fdKZ#t=`#{f^0u4XB z>;UDm|NsB9gX;hf%R?UgZihfsI=Br1s?yKF5*ra!I)VHf0cykhblZc*J2*gX z4b+P%LDx#bj{RT(ogLS50i3g8$9{YT9W=r3dI8iSV7$OT3G7Y*U(LV#+b)5&Ftj>C zl=HWO7Ei-2JMv-HQ2}kcc4c7j?5*YSL_S~A@t7+EGk9Pc9K4>L$3WvT`XK)sc=o!1 z?y&WQY%Y}mE#0vIpPLxK;lcO`tlqb?6tr@|w-a*U2Yi64TSvvm@^5MK%K*?U;V&ls zR?vBQkalv*T||E%lmXr$0L^}a(mA-%IuqPz1(zo4(K-Z2kvaq*^^W}8#5}wGI2=1d z89Y0E!OhlQkJgi=b70Yiql|#JCmVh-mpVh-)(Toa2-An-IIRgF_0gW-vaU4=R6d-8 z)YqVWA>{Q3Kpt%s2bB+?llj2raDw{-V2OWdI@eZ2_K{`fPhE0i3()y`QQT<55^B3 zorXT0nH(OSj*!cfkjAX*!DZ!<2&A3?xZFkR7x=)A`Rrs-dAS*_3jkgeanOU`?I0+> z2*A1kq?8xnC;(UZorfVq0-zFy7u0@*tq_OK_cz<9fV&5f@e;5;Q1?IpG){%+9e^)H zg01<5RokFKiGhIuv)P_flAjo#nOl%!Wd**UC$T6qwHV8phe+y@^K%PIOH$(z>NVVQ z@)Ju!DhpCI6{5>COEMJT0t&VYDfy*IIjP{Y4U0<>OEQ!38=sO{nN~oA5-Y2`{Gwd& zk<9TW`5NfwDyF2CBxdGVSs^(bY_ggT=>8#1NPuW)ROqEC*w`qfq~??)YAV>-!C1Do z3Ke>348dEp8fs*fA7XKzyJUD>y;7k@8yy9>wer8Ts3K z85kHEUz)NoF!*#{@PxJ~?HQWiF?ujws{En(v7*?w^OWc1N4}kxJukoZwLHz=S_{e( zpwUv$x!{m;t@%Bp2jhXtAD*2IKAi^~J1aPRI|Bq9I}0Q{I|CFPI}0>GdznC+>mc>5 zPcIL{{&TAdm!Gpu;6u>ozKF$MVvxl;_2uEj15N%)YB zce|!wR|7L*GIr^*{LB>mNi4l6v$)hqBRM0nNDG`|An8U;2a&W1q;-(5D6t1`UIiy* z9sFJ(T8$?Dav?b}IU_YCz97FmwFtkB>8U00$g1Ph@{8h=GV>CPD&tct3i9((^GY-_ z^Gcw(kAVSF9>gan7MIw7vl{5^r1%m$jZDy;V44ax3fazJ+XFzB7wdtfH8dG=;|p?1 zi}g|!Y;6^C<8w3fKpX~S(K5YMhE!0-)HO6UFknbku(4GDv%m&}Bn%j`9dimY5GB1j#k9PECRa8T}su0jCy%qn0x9G2rjO*{$Ez!K_!Muy=5 zNErY+c|DCERtDsO8g9KcDh8gNS0G8e+egKrJ4eOCr#nQ&pc{0fLU)NufOU>a1b?d{ zGXsO=3;tHnYB5`tU;qE}_gr9NV6eRdT6@?J+KRLP@c;k+HIKVw9(OchWN>Xg;MhCi z|9@r%M}E%>2Y(5*{&(P?f82q8+keJij-3~JcY#Jx92*aSPBV1m_xy42KXc=+W1xDt z#}d>-OTO;W{L7EOofpJ8_=p9XVLceHyL6XxbjR~}bc?$%e&~!*(P{qC!rya@k%6K4 z$3p&I(5^3+&dZLS7d#HWQgGZ08u10K)dG)CdUoFSJork%lYjjUAO7{Xd^<1t@~=PP zaqzW*5C8g0E}i#15589LV7%|rdD`>fO9das_r8obJs9u%GM@4{_+G)QS4P|ev=IQb zB+zThX><9*IpMr2bazZ9{lS+f&6873FJx-#^WxXC%k$~#QsA);lp^& zgYh_6u9wB!qw|_i=OZM4DE{-{{M=olqVxTpW2cEqaKQf(6$uaqRrd~{!B6O1NAnQ{ zkZ%#Eyp@7ZeW^fd&AN7x^GfpLK~lxA`T^4T010W4R6*n<7MCdKDx_r=6_CehLK@ub^^O0=-;C+AalJe+(^6 zL5EkR@dq66=={5ak-rsm4OJSy9=L&3#m3(P>Q90?&6=-0ntu!M_kmZdbUp)}WXR&t z`TjWM2&m&ODxmpG$ZUAGiAwW7LH>U5j@{KoYn~)jfNj}Rmu)BHaZq^a5OAcGdSSQu9EnrmGMh!^kp!|bKC3uC&&Cei3u0i%R8X{4Kn@ki(UH1#$*FlM8k&%9M_y`0iAJU-sF8z5 zDJX3*fbt8)M;rJU^9od-R-TQis#7{L1)z(*a#VOgjRVLS7id}=eCN7>N9SqCi56Qytu?5ReJnrlw+cXg3>q|qo&^p* z`hp#F5VtkxRQpz4sFHn33=EJW1$4l3Z;6V6OXn*{)eF<&zyUV&F*nqkpnVI_U<504 z0Uv_j`QEd)M8(0i^M_04%Uz&VN?=Kd3&D{AHl-D63aGgt0lGN{VmWB?tNAeGR8P;& zBcS5T0J4(XNdtVVnB@)rc0SPTY;P0?_%w|#e4vgabg3C=xBd}6ko#&GJi3v?19Z;6 z0Do%$FG#YU12sgTfea2h2C(yFpz0980tFFr-ZYofQH~zug5K9^L#NmInMS2e}|A*buZk zsM`@U1s{Z(1C9^ms0F29w_XzqXae@_{OW0WjK94S>{n+FpKb+kF6#~W06HQbJPrWO z9-z%EJfN1Y0%+!1qVq5$A%H!C>Ir73pM5$ZqqZKM?_E1zx_18Pya`T5uqi``0pOGb z_5Mb1js!(&i3(C$0wo>=&*mcn&;-Qc(d+TS$MPY6YXv9)b;qbE_;f3IS{~tVF$Q}C zN1D0F1&Iu}!@8Y0__z6hG9%Q55cffHD){V_=68_sU$|Q#(OL~PiO6Vmg(?R}E1FTR z(9qfkDz0CLf#Ta9GZ{~Zh72MZ^KT1*9@_?6gal4lpb`O`@OzPUU@0BbVC!c*y6qe4 zI2d3%2O;Gwe@iK-?*%GtuRsk#E^S}-f_j0_^Ch~=K&QBRAUXoz(ih2mLh|;|BnC=Y z0?@PsDxiZvrKjZy{?;6r6EF&7&?(-Kve>QH#1fpACxZhNM-q^LnuJIKAce?ja6daF zk?aEHSmdnZ(H+bIy5qp7Tgk`r0e?#Z_;i_o|KN<`4jT0Wt(@@b)dkg(uZ@xXU(W%~ zhd$7~cOKo&9G=Zb7@;}sKWINq3mXe~51xq%Y!nrqOhBdekCL4*BmQ4_y${^J1C!x^qAW$V1Bwm(GWv%Qx;}%it`a5bQ<`BhW_0 z=EF$kS-}Sn%X_8kJ-UTJ-f!_`2eqLs|qqiUey735LS2>8nwaB&LB zpZwbj{$nWwph3J98bBDW5{UU&s$(~UF5mI%tR_PppoOu(NF=phPNH;Txbx& zn=7+n8j%{}P>r>)#0f6X!GYfL`P={h;2QJ)g_mEyfr}&;P&&uwUuUqz^&GoE=anLd zG^iAXxNS2iVZ$mvxZ8waZUd!wsK%GqKL7s@$=8rh1*m>I3bO&Ja(TJ-GbodR`wz(V z9%?-b>dJufA*`|T|H8{aa2W&E=hOM=|Am+T;r@gcaxeeE^KXF!N<1SaGX`)ea0j#v za>71P3c<7(yogNW|Am*Iz)nSTN9`Ac`;pqO|1Z3h2g|rHFo2W({|hg#LiNMk*A3qO z>cD`Uw*OyvX$cla()SkX512XGV6Qtc>_SRKFHeI8bs_Bpu)3F^d!ZonJRabNDWGQo!KRdDH{EIuJB!;L+)d*lOa+0BfCr zmPz-z3V`k%<8N8P$iQ&il><})gSNhc21g(lSMzIvZuQf2Q856q96$tQua@B@@VRiE zppzk6PnIzAZxieYQOWS=7BD;jI+>K2e;ZSWi%KSFX+weGft~iCO5(VSN*2h0E}g&j zfi_x!wnZg@ECo%od8~Hn*rJjJ3XtACDg~ee=6biNG=S*NEnq%4$sTV}nE=%SE4@Ko zF?LtOla8G?K-LKuojw{D~@Eizo0|!dq&%nd-LdhPmivJf}`1k#A?fmz84Prguhh|p}MzmAs zKxqzir44w~w`b>(*QTINO5iXg%IEMdY>f(XfIx*|EqzebF`$k=dVtTs1KlAC9=-SJ z&WBuP^#XL6mE{Zm7Ish{5_xyZH}LM1Zyue$J<#s5Dorzd3p(_*^+2h&Z|4jCZJ;}> zL>PTFKR9-EppI)N=JiuYJQ$CHt~PREU;y8L^&J2GSH%LL^H8AckzN*n&!fe-|BAmQ9JFlg zB6JoNoYo*g2_`{t7YqsxjLSL<4|p`YD=>P1u9|MBmtZIf>2?=6<}Sg|{NsO#R)>p< zxJP%fgNJpoM@dQtn@6*=17o+dNb?V_QeKZ{X9Gr$%zBPuMP^JQ44#@;LJifT3C^a!RJ`v&pYYH5U6Kj7N^=^ zcea9^l@-E_Scc5Jvcw$F5*hFXfz}GC6$PouC8;S2;K@gY#I%ysA_a9_b!c=Esa}t; zdUb7e9gx8~3i(ASmcf>fKx`z+eK0Kwps5>(zSO*wf|4T8j0(iJNu_CNsYQAzi6w~| zpeaujQRre5kWNs3gkHo8-l2lJW|zb8fJe7`fX8w72$14qpwXUk3lHmZhY}W#&T@xt zXA#iG63b!_{uU!<1_oHZEEZ}0XTaYAI!7Eb$=Li)m%sH8sFT#29k35HXa%dzVEeqA ze;Dw$%wu9;XntYX{DXtP9kl*~e_yc(XwGpD8+@1ndcH{W4@>@j&~>)WKlJ(g#X$Og z=<&CL_Hgp=+YH{w2rbXy7Q8TM{=v!L20D-d+AMI~!v`uHI-LtZgT9CfPySXjkW-tF zNMM}P-s^TA?7DB@nmaqdaSynSi*DBsOa4C4^4aDG_nUvX^0!<9+0*T;;nAF}zj*JA>|I=Wm?^T2@jm^1npPqubfR!`j(`zhw)^mgX0X9-Yn(uochnLpHjr z1CE1Y1=Ij?Z2rT_-*O+cX1@6k8-I%`xDJP$zU9&F9O1$29Po)>uo-kTt%oIx3V$o; zs3ylf>S_C7{K(@(v8pm_$_yR#Wx_>Wn-8{{NrQ{6o967?0xZ7*Y4q0kT*Z>V8OQX}sJB za-TeQdqJ^t&hAJn^s1Wno1m!OllJUgF)>KGsBtl7(h;EpfozFkndVnA|FB-lOR-X@~K zR~_Kd9UK8_Ok0Ym@VA0iQg-_?w4UT|{RdkA-`NZr9C#@QKC}qLWN7}8%HIMy#Q0?! zDA*?8Gq1F|JCvdI5`XI^uvyL(FRy}oMUcMFd0DJ|A8-tV2@mMvo9A*^6~d&C;g`OK zT^clnjjKK&qA~@|K*xh7=;Jf<;)@dV(o;3SD>^`{VWAW1@j02rB{rb?HZL(Z6|!ao zv<@b|q$m-zdIc_nURPULL6lV%q}o|oW#*NDD{VW{rqd~^ZsAS?`w8M2vK*~o3tARn ztpGO=k6#sR6+kwDCYBf&7{Fl)Th<7wmW&i?Y7{U;O|XiZF~IBH;*z4wymTvt%$ywE zwEUvn)D(r#5I0>51yJOHI#T>{zfjf(SRnN{L3ez2Uhrss@Y|#L2NUSt1&`)mEc{ar zIC31}Z>azkuD$L7o}Je{y2Ar}dh-)NJ7+w)-6KE^)XuLi-SHxxo!@+V0~mcQU-7qq zJ8|9q37(dx_}e#wdZisQOdj3A0e-zTdl`H>gCmZ)FfoF!%2o$;DkXd@|MIu20u}wu z&Y+g9vj$^BwFCoy%P|H9hVE>UW6lx`pj%B1Ku1cbgPNb9<}H8AEd~Y#hYmeR8#h~| z`7e4K*U?gszn>FS+FRza@b~-&Sph2LyMqIKdLtM;EwA#oK#no=PVlrm&ELKhY@!a> zwVut#ID9&zA&v#@dIN7vhK_52DnbpUKA|6|ifTS$0j~%h;~e7;Bl>3^-PIi6Yxb<& zCHR})flB*r8XnCD7(F`O1v<0AZEA?`tcyMPTh+i*s39t#D^?*5>zC4?egu5KH)zGb z;U$mGW3ao%eL7=Q1VEt)y{Zo6MbHXGkV83Mf^K`~2knQ0RtumWRi|^oOH=U9Q5Ob= zouJi9FMoi_I*7V%8x<7uT{>e_Bz!tU&@FN428nlr#6i>8F9ks5w>;FmU!bxWY96RR z(0R1^$AA7-&}oXGJM_BQJ(w%7^ax&p3SN}5ailoQdk2T+#ZG8 z4+!dG8=&T9!voFrBBlJT`#`C(^Ec>l6amoHxeB0o2jwxxec+M%9Uv044A-L>n&&_% zNC31rR{}IlS(4K249R^z{`0p4GcquAxTt_`*mMA8z><;f9crMr{?Ze!^j4{+Xq^fmdL4}tRr zmi{I`$j;Ip(0V<7P+I_;K%iaQR&dwWaSy0JiRj?Es32!i@X?sa5e$X4RzxfwyxkvL0bC5qDI5Hl2DGbg`(Dqd~D7}MIJLukOe5oD0 zC!^PKe)A93a+6-im2mSwTd82q>B8o3 zF3w3T1|JuU(cVeU&nqd)&q2}^stqn#HT*(-G$F1|N>xZLPEIUHO;ISxSBNPE$%7q% zB|LGMXQ-eN?C*iwJVO%AGg8n94vD~Ro)L-W87pYG;xo^fMDt7(G+g~daJ$chMDt7) zG+g}xahnI;0R}P?Jze044>JV~M`v%`=E2vI6KS5gf`*eTp7df4avKN}X`Y3GhEp(Z z=UIRTw_=irPk)vQ8XkC}!xC&>3GwDRDroq);dY-R*t|UA&2v)F2*cw(Ct~xhvx0^j z9(Or|-IYeXyId4BoP%)t(*263aP5 zQw0q_N8II-A&KRjp_zh4aHJn@_mNo68JdIY2`Ajxr82I)_%|#BYQy8ARrcOY`!;uvGLbe z1_p+53(sVcX+Dgf;P<+MdY|&}-skIiu>K%;JiE6VvJB$&wh11PadMAN=Yk#J$&>C7 z70{L1BC4RtSN_(wptXw4N08QML+*10oqMVPS?SbyA9Q9Dssr}v!&OazX@sw0f7u8U>b&1sq5?VMviV00e=8$+_!4sVP4kaZ{#NkP zDrf+M_S%Aj7&J-H+W`vC#-HF2ZU=4GJ@|+V6mq>&1Q=8n{Aqq*-+8h5L<1-gI}dbT zXntsa@C8rv$p**Hlc2r#|3NEM4!#ot@0N6EIQPK?6toWf`yeNdftIK=Kd^5;(a?De z7P_EwZ(p|l`~ScBp?&9v=93KvU+_3~o&-fC14I2Po(G_fmtbS~_kDPM5*%c((Y#04 zNAobU)UltS2t>;$8?gz_0Skg6m0?$uG>*Y?Py=NYkA}c#2#kgRnIQn{-#GdETEjSJ%=9^#Wk#!qq_*oPmbU z)%Ddu!!+tz>ab;J`s#3Vb23X(ixP7n>rbKA);GTqKf=BBm{uV8eWb-RVkIqny=30^e{4M(6?Mki=9@efF z{4MiAJn#}4R|k)7R|WoUz7imVJbGhPm|iQUP3XMP{NQ)<56%+K=3ff@t)NLQuslpH zc;?qt!K2rS(WBE@ut_F;TmtL=d&ac*TcyvSN(2BK?*K4|pfQ$eeWnJn~y3?b#*21In z7C0zgZ}Nc6Q@L-2bxa?xmKUQ)d93d zpxG5PdGD&h*iZ|aycc8!ooFEeI=a;XW<7t4CUp55+$a1k2S9C}Us|Q!u(fWj2l)Fz zTa222{I7WpuM}MoJt@!WPu>%`dngRgwsPG%1V1`qzl2a8vGbh~Q!fJ_Ik zmjy*A$QF>_K`~kqiyEIIAajx9GaDs7OXSc}%o9-av)fhU^-@Uuf@Ax@>*=umUpFGY z`J3B7DH>^wE?S&V1syH~Z8p8`M>g-JHF(a_fx!c8p1Xhtczwb&M$is00r>iaP)HgA z1(bEE2Y>5r@Wz}+u>SJPOGxVm;Pakkpgto}X^Ovf>)-$Xn}1o=NjATVZvLfIE(UEW zc_gz;gq%;&{Of+;7KT0rsA{6mYsbqS~w0$q9tYLm7&g4(3r zt{NWAxeAQn%nv#e8FX=jN4G0vnV}P?I|0u5X&~L*u$;dXoYFx{4P6~xdL!01fa1sF zxGSi4kF=Wtl4M_cAk=}w8JbU1apzP1*6X0oL@y}Fp)vRJ3`hi=Upo(hTE4B|&MUqU zei;FFJ2Xm4XXDM{FI_lo)BpYd|8nWi|NnP@w(7j(0+|ZhFZhxH z!~*SedHLOg25rzjqt9Kv+bspVdGr&dqJMhXLaO^`j)521c zPv{4 zo8i&Iuc4{R9lv$iwkXV#hl3&CC*{q?EUzS>wmXlwuP>@&zUT~ofIjogI z5p>dIYOx;d*eR$(aIB97=_YEoNpWIDJXmpjW?o5ZQC?z>MzCXq7Hkn~uww+)?H{1C zpyEM#Q}T1;lM{1tK&u=e1{LAlp<%5++!0e0tciuLN=1yvdv<;UCDKsvkbL7C&=o&O zNfUB)t>J-gcLmUzu>w$_f*6o1xsF3`;sUi~j<=|Q*3?53KyFF{u|aJr5oprwJm8Vc z(&oYV0W@9*O79LHy|6o_A*U=r6~fY^Pwx`&RaYLJFL!}I=#D+;P)&;p$arw#g}Vsa{(xmX&}C`` zpyPYweOupxjgzQNGDc}HIx&^%=7}n?oAEyGjA{bP4I>v&R zn}YTq_LivV8(#A1{C>Tz=r8%;eMgpTA`z6ZFWdPG^PYAH4i6cR)?5A6)#c@}Lt-IwAMZ zwjAJZc@Ao)TfXIQ(F1QMdCLKEQtL`kORE#&Y{xyIt)kFG1Y&|Oh=uxB59VJz$SGGZ z`N54^&>$`YXg0B$`tgHi-Y-T^M}05N33zyJR~@e4GAu8PKalv>j%&`}<}B`OAB?VtDsT~r_i z{L284`NxledR(xZfIy*i5Y$}it%l6;fWwrFzoi8fVxT*OK}$U$-tTr+c)0{Tx()IN zra6_2pc~$+HDCjoV57MCTQ0JKhHY8+Tg5>=s@~!XWXoMZnmQp34X_3t{?@f%bu}sl zhLBNGBm-Y6gB{?&Kw>@yEjdQd#L>iN;uw-Laf>y$>cOgS`ALHlU8_ z4{rX}ec(IfVF|Xx%E$6;NvuaRB%!v1gB#h_G(!Qnn&o)Q7L%I3A$sP zAJl*L03FT`DhV4rnqP6eJOBa$loQ=Ras+i@ii`SqJJYbi*PeZ33z81vS4h%l~3x-CIJcd;fu3 z^+@hT6lbjye*ORdQW)GtM#?ZO{H^-n%!-<^UjGH17J;OWhreYrD53P`sE|?tf>v^4 z20%5j0Z>C~0Q~&{I+_9&0O0rv@Mu1)0ju9Ybu73h?Yswzc~AJIlCWz17p@u|dg=3p;gG(Z707P8*~bW1F_KnA5*NN8fz+Bu+Vrt?4PbvCGS7kFv= z}cfan6T5J!GMauZlHQVSJk*Xubj173j`FLnR_{|{n#bRK@0h{Oin70 zFveXNgCE8KU4{u(ED19(A0`F5>I*ED1{0YFV|c?DpzCnJYWDpF?L`5#3dqJNJw+`n zTcl8Wpx_=X+TjXzR#q8_c_}%mkYk%Q!V+^zQ`OX9JzFqW!4|UL6EtL2P*N0MLTncm z-p{13JLBV%D=G{PVJ9{~Ha*yYwqx3>QlFm3>iHCzWe5bGgo3>QG=-@@TX8-d1f zf;}4FR4}4lA)mp>zyKXDK#T%_PW%CF4g;lj5F1pH!`Pr+7>o_-P=VN>Q3ElLURe+u zJZjMF!FU6FhBX6d)HuPXcMEu60A8{|7XQKOLXX}#;QqN!=SS$c!8_PYhDWz6Xxt#z z!?*K+N9Rq@xIqDQ+yF9|0czGbfI4E(JKXs-b6{m~FZ7=2-cr<|16NJQW3C$DafAQh zbC2=%5z+ z(1FNd+#?5%nHd<+M-JkdVIv2wkdcFKa7T=bzx65$=tk*W0S=J;Ezd#i>E_pv;eu!o zrxW5@_;3Npso>!P(4B6e{u0QaIuL*AK)TB>L51}M_~?LVx2u4swJQgIOA+`q)_@=U z+n8*a_*;zF7#M6A`CHF&GBEgdmn!(Se&cVs&k5>Fr>GRbqo?yb>?CEF(90d5%hS4D z1w497Drx5+7G03`PBxF`V;r8Hr2-zkwa|eKP!x0Vx2y(5 zU+*69AQ;kEhO5F$KJfX1y(KDo5cBmQ=@Vpr0K$CGGFT6U`98h1hyf0e72NzS9?Z}I zjO1T@A0%3SJ*C|L_0*VFd+vE(~e?G3q#n5b`+364>|! z{&5cI!Q#-DuD2ahbNs9{Tpf@Z-9*CNtbd4M?HDOX2S@KSB?R_5__G z-uVn{7OWzCnTf9I^$k*UJ7idfeo2S}ZD0d5E-*pGhVL+iyJ}3Urz;dL5ItL8B$R3mv9Em*q4GZDbV3+V6TFm z4bld3kTi(#@(px^#Iy6LN9TK=&bMGSVAVtyE?_M$Z$M1~nSBFfHi!ZCFNkpsB=WKp zs^%qVG7u~h1rvcYK&PgGrR-r+aK?O?h#8F0g3JKB8tfRbenFTV2aFMh!MObwI^+dn zfcm^tz#z*V!yP-ngSzaFpoOznp;P=fKpRW=x2*>i^e9vPCqUiaZg&CD1+y(VETG$K z-yZ{W6pzbnMxBy8Q)L#Y(gG_0FiXUrH=>Rc7VhcbF zko%9fsDKVm2B`&w!UT~2S`U<%f+}PX2O1=xk`xpYP~Ub!bb(GA2K%zJMFnJ{OUD|O z4WOyl-Zd(qUNXoKkdHw&g7~1dZlLbm@fMW>PzQk17PtomE34s#wjL@&)8>@y>gmofmh34$kuFJnz#9 zyC(cIf4;YeN4Il?Z|4tC((eY{U&@X zO<#=st$)C4As{=UphX_Y=uSv31A7Qmupo`}gT-Kd*#=l#wwQnyI6>kbPmWYQv}V z8EhH>Aw<8Z=5Kim%01m%RFI?l^1LrOlNUh{E~BqWbC)TmT4fFgjA zzttS%9Z)X`Y(G5Veg_ripmGN+3`=dGP=X|2Sh&6P`3GIw3R45Bwm>zt1dO2uWx%oy z+>YlUJ3zh#+kr3}#DX{!W(&NSL~ANtg&O@D+$;du3O-03#1MeF2a#jGgTf3{ra|oM zg_M3^4%~v?J>Y5%Eckj4)cBV*&?XSbU_q$h>nNBe#AM$d6;Sm7(L5jF4Y-eq4OP%- z_z_@ZV6KN*x(dcv4P$^?i6Dnj;|9=sf2b>e_kKF$8p5gGVQ*mGs%8@eQc0fzmnxm0E@e zjsU z3lKR#H7U18cPO;M1UlpqG?d)!`2tiLT7dGM0f-gh)4hiq6ssVU13*3jnd|^Ixt9sl zSj+cOQ2?z4b^t9JP5@~Hm!%Nrbe{9*d=GA#fb@f124a9qQxF5PqO;RSMFLcJfv z06EP?B?4qp1!!$>0EkuK(K!daxDc8yL8A>IXB~&kpMV_Z(+L^o1vPF!(>}*rROW!% zh5!HmKh^@Sdl^9O8_@6~NI8fN8k&Z&VIzqkaZqUo6F&iBfa;LrEh?ZbJ0LE|F`z00 zq!v^dfW(fqsDK>A04g9rZBmdNXzK?^4#ehwHl#poP$2~phiGU$z~52?F47pl;TjIw zCbN&hr*{q5$DNQ?tWW2A(47^ahAUWGC&cHF5NbV8!Vk)T4oEGf-W(Os0%~xZ4VEQA zEhMnRE$>6_r~ny-bVtP=NIL}9eggRyR)vAIg4WuC+D}5Di=Lnxx}HJD<-1)}3P6oE zNK+6z==mNJm7tw35a%f%Ij_3~TqVO>T&1}ljYmM~-=`D#@(b8}5wl0P!wX2-JMN+a zPKlrd1g^4uy7w@HJ#ySd1)Q{Cc>f=)U}o3KLvLB?L0oDmGkiyzW z2jy0e&cm;v1@z(9eu!|aQGqo0Jeq4%1Q<%BKy5bxk8VZ}W{(%$g$f>>=bPan16$4n z&$iI5H=rgqD3%~@fz}fqy)G)?WzV3s#|)sf&jAv00I?)qL;KW7Zjyl)0MZURWQ7;xjI_=c6$Ma<)b0ENloKRC+fJalO9P2*fW!tJUI5Yy zQV-e@2xfQ2s5p3Z`mi{FQh^6psJr@w43i4Ws3I}*sj!)+= zP>Tk8X$-X!vfLANjf?>QHdh9Z&i5UVYq=#lKsN<;yK;DRhH`*o8$|~wql0r2B!hu( z4Eg{60?enK&p}!oJdivIl>&)FmKcM&Q=noFY%WZ;cMrIfK~e>Z8c^_pl4mzK)*u0m zSWpCtQh2ySOzUn@0VNtlc2@CdJOWBrNDa=k3E*owAV)F0+yZNbff6O?9vNQ<FLa)z)5*HMMoB<6u&{_l!touozYC+U6R}T(1kIwht3xpt>X+XY4U;_T9 zntss!$bqyUbj1=a><=z6G>rExElI5a-?HNA<7XKkpPp9=UT|a-?~|XL9bb^2lbKxU zYUJvQ2zMAOxWv#hKDZ!0H!(XkzBnVXC^aR%BrzQ(%@AB-XagqhJGXC{L+$w(h}I^ zK=B1d`6c&6kONW#G-M#jkL5474ZGp`^gF*((f6uW~H zJ%f$oT}jOzNG=&=4#yB+L<5{?fSmx~;9$ZFxR{Xu3o|n}8yg!d2LdoKGBLAquro3; zvaq2!1;S+jQw)p{nvszS%x8kqU=AZp6vTtbBa47UnHiZu6eA;)M(0B%8KGTJL`)kP z7#JED85kRw7?>KE8JHVb7+4w_7#bQH85$d!7@8WI8JZhf7+M+`7#SKF85tXy7?~QG z8JQbd7+D${7#kWJ858NEnHZaxn3$TFnV6ecm{^(`m>QZI znHrm#n3|fJnVOqgm|B_{m>HTGnHigzn3ZfKnH!s%n46lLnVXwi zm|I#HSQuIuSr}WGSeROvS(sZ`SXf#bSQ=UySsGiKSejazS(;l~SXv@{gvuKA-)Q`e zrq6-Pf2WSkIxhaNVD+8f|Nme4_y52Dojv>hY%Kr(?f3uxpbN)%u4OyEpBT1J@X!DM zPyYS?Z}X>q!dm$Yy*hvX{|8OaH_r++)QAbZ?DpsX|1bak|KECY+1ma!g>w`C{QnO+ zR`hiDJLPhvIj^e!{QnQS&nq{$!eOH4nRV0t{QnQS4krBEw%AG`o2HF_{{IJU=r9la z?Q1qg;Lzzm|NqPU|Nq~AhKEJ|t7#LS{rUf2<^TWx$E})FPq&s_XZZX7zs~>v|G!M% zKmF|awgu9E|Nl4n|NsBfHCo~`xJ=%g{{8>o=KufyeVa_Rey3Y(3i$i~zsvvs|E=wh zUAlkeL`ybkTh#ym|973eET!&p_h{?i|Nle&|NlSjr0VW-^Rp)}`1}7qXlF~y(xh6I zoHe(1{r&$Rw3hhWt$5yuwAG8R{{8d8_xdx_y7Nq z|NsB5sjt3p?2-LUP*|V&|NlRmwYJs~ftV+tIi)NA|Np-{sW@|{ipna_|NsBr`Tzev z-zkRXPg~pnf;RCy0i7)?B{(UCPK8T?D$AhJk@$#o7}+7OD3( z>;>)YWnf^qow{18kK=eVXv{T)fq`L`Y@yRn+1MkW7#J8p$6H1`mtLlm={t!Rw4s54 zf#FqefmF&n##`!)3=BC83=Cf7?`O?ioVy5gY!K)i{?_c;E!7pApJEsp7-~Q#2}|6q zT=*npOF1J0189Znp`){-C$&Ylfo?PGVPIgejh%MlXt3#tHH-`lQ$YS*F#T7|7Oknr z85tNrgX53m7tGu{-|gN*Mg|7ZU4g1SmbXm~&0hM4k%3_i$c^)7EH0XL>>KEY$1MyD z4CnT}3<=(UXS*R21H&E$28KtDN}t3(|LO2yVqiGJz`(GyBIfe!a|&nDm>3w&FfcIO z4_2)H93?iRk%@uf3IhX!m4W>9J6jh#n$5((aEF0`VcO=$F~Jvat^loI1RYIfnpaY)U}&gkqGzCMSPJGE))^V;8JK87g~9qkc>*+!3_3u< z-7ge$h1vm-7$`r06oB#sh-Rz`VqmNgV3g)z=KxIyg7kp$2S^TdNhOE|iGgQz7#Ki@ zqk)7NKw>Un7OEI{Se}7_K@=(nQU^-UATH?KY7h+)gLxcT43thm^2lPaNgF|s1T^o0 z(jSN$2qJv>1bUc?x%fCdxIOqd!0rO2FOU>?1e1Y*L4tvS0kjAPBnCbk$B|FKk&h#e zPXHnZN-wzNK+|xzDC1u74^l#juMPaq5`2};`n(2N0|00irG;ge`%cHvWKW^v~; zV2b17Q*Z>kz=@B;m74)H?&t#51Dv4qYDdYkxb>-vm;$~m~nGY&=Ku#srd{CXU z1ZqCmKW-rZfZgN>aubs~7oUVXp8(i3aECE4fa^fEc|N%Szg@+q{j zIPz&Uv%2s(FeP&FX*h!Yivpb&xvl=5Lq@6&~Tmxr2a)Z(X$P0{B0Y2aoj(s+W zD-A2>Ky^GQy@3RM85kJAR)EcRg~nksOEQvqp!5T($3f~9Vd?|<1pN3o!0iR_>>~pM zgEveLY?dF$EN?!AKqQkG7(kO&4WNRVfq~&B$YM88n7Z;wAcv_VC`=teVd}z{z}$i> zOhIjlGf=bEfzr1dJiZ-~;@f~J0WH2=xUcWFE-N44_2Z#@qvPGFTpJ$8V4#aM&?* zbMbM24n_ip?*^zm=ptVRupeDPY1$p+N2UlaSR!)*r5TVN51{HLLFR$l3k(blA|T5c z7#PA(+zifBZXoBRp}E-ws$LqV9;68BW*Y_u23YyF8YT~R7dWqh-Q@zxYoNj-g^N$a z1u3sNa)bTU0OQ8808L&YN44_L^z)Zddre^jwwjS1A zmOkcwCXhcIz!D4$@0sv~iw8W9dhuOgW0X1Maf%3*Ms0WOEV_&zX$%kvjda~(iw4B9u5 zftDBlQOxoLl|OE%W`V;LRQ`B_f)uk%cjN}uZ8=c$K<#X>Gu`+E`atQj7gXo;fa;t! zR!2UAW;QRr2h0o%pg3p%Z8(G0FAP4Q_E8A94VTHq$KlTn@$(U=x$BVJ*#l}vwK0S1 zKo`CMP&J0Am)#-t@*SwzcR_vzhb5w1s)XlpPi{~-0ouI`QU+Q#1foG=GN23x>O+A9 zpmm`ER4fH525Q5&K*cISVoXt><|G3s&DKE69%~M0+5yLv6DWMKr`ZF{%q(nJ(=6Bu zkefC@?E=+3AnQQ&{1K?wJdgmQ{6H=DtI&#cM{Wkt+ExW<+4BIUEJ3&tT$X^-6EqDp zFfwlhl_i*oz=NAv0DJOq;|BM&d!TlK`o`e&;lU@6&c(;!$jtz5NA*BD>g`RNSQ zyb@N7{Nw{FufS;)+y(`wRZmbIumHP(;QRzKQvq5=1jEXAup7y$SG+;l5M*Wv)J#x4 z4UR*wnTWIkZYv|_sSS+G;vjco<|$W@nV|ml38rQ$j>BgP_!OF%dzkV;Mbu$F0jD#dQHv5j33n*R3nC8+-vv;!K&McE+PghW;4;dE zPl4H(iHlFd4cuvS=S~Hg1!jA3yTIAr+$C@|F5r6Z1JpcN{Q(MY79mi9%fJ90qky&z zETCnbKfZJV4sUS02J$5^XJZd4PjKGtfSQ-eMr8agU}ApHj5Xnb!yYsix(Dj+K2X?4 zg8EK~bPO&F5bgst5hAhmMx72HJ9GBjc@Mq-AY(-N9yEfSQ#K3KMX-&$KfpSSeXncLozThfX7zA^+GMEnF_9NB0$@d7#JA*FvGx=Pob9u5eDG&;l%jdd7rq3hShW6=8#lNvKLRy#Gt|$>Z9`B+ ze36S!!3|tnI)QtVpnN3(O85*642GEQM=MV}A$@NLP??IQyW`Ex0BTcbK+VfW@&j`D z><%gXt?IB;bQ8AS1wS z&JR#CRPePq5oy4k?*k+5K?UfXhYPgKfVbPgZ7ny@n1%SHfKYv(#~ zGl1$(4rp0%2uXh*lRG?Y5%s4#p951eX7%X>aYq2uoS(3^5V((n7Dw)U4UG8^cOb_Q zDBVrKq96M>8aR)7@m*kK+JiM<9JxX5w+B%39>LthcYzVPBm>#W0xc7GklGFyb|TUQ zxQ@Pt)lP448506EuNuibjI<8z=N({VKEcSvXW#}NWrT+Yyj`;ZY8L2(W?1_H!z^b| zzH#R(V5;ZhGjKsQ$q^F2FQ{aW0kkanhc6!!;hqYpIh6YA0Mwjp(EJuOA0dYiINjoN zj~gU>IG__Tl(+|!mI9#W{6Y#J>}d&H?t^jy(MPKgX9%=hD}b-0V+C!x%ebp zz%xn^@Hq#*n#jD$oxG}d2-GF1J#esd{Dbn20ADXy7CijKRA9}vDArPd<~4? z!5#F{*Avt&1DT%zH48rP!Pmgp%+|)*!_v##2ioq#z`&3LT66&&V+QqQu$LR)dJmK@ zjzX#+7u4w^Pi_X#Sj-NnS+F)=Ka(43I~N?^;4%ng)!w>xF@8Y zZzBas|5~v0k8{iiY>yA015-c5&1h3z9^Bxu&K{_F+OYJ(=YU*QgWF6Kp!@?Py4#90IS3U*kxG}ix>;g)M)}Z!;BStF# zGM@YaY8Gft51gja(jh2ciGT_f(ApDNJRsVVsQnG}nK5X-4T0)Mlt&5h@(5&p2~=JZ z$v@Ek402mFf$1%z+(j=Jwm|iRvMP%?tJqX5O9F;ICd{sf03c#hef52rupK=tGD=N!;AzMwTf zkSqc22V8*aL2iE|hb`RB3)sU}09tNfvlEoQ4WRPn1oI5Iobm#V5&g!VXW(^73)DghtKbb`VLf%Go8d*5xIl=j3Uso0~FpUC~X^%ofc3v z@c9w6{yTVl2W%%eAAs%riPcU>KeYpDo)J6`pxOzVXIKMOGaJdDXk$6dOpM3_4Ibe2 z9Z#V8KxHGuKLO1w(D`{#_vwimqyPbT4LtY+Joz}lV^}iK@?|w{`4{$j&2Wk%J=ohFxD18P{952v1y`W@gpmA^9Gk^TcG+tOa-ZBd7w?~VDr$%UO{1+pbJX1 z3=Blh$8=yVSE24d1GNvd)*fshHuodP(FR7Q*IaxSnC^#+y~$`o+(r%aKgz;qsYovs^X?4Ac&mM9ZSKjmoY#{-gn ze4zTJ@bwLl(+`2Ndk)k*|_BS-&U>XU@H&dYIJ%qOfQRgf`YiMVH7L+kS*BXQSAK*2S z;Qj}=kLSW?z~qKDuI9lF&H0Xe60YFMaCdH|osh_MfepU7aWfwR&A=fqdiDU9Svt`2 zFPI(s95uMj3(jBA`1ruYybn}nVR{r?2Y}+Efd*z?ftvXS)19t-u(?-6e7N&XU}oOQ zg0*oDuKz$~s|K{3N+y&yK+BpyV+HWS6|y!b1FHWhN}UW|N8`$eQr<(uu7R0Z2$b$H z%X@IT1LgBQP&4NeY?p$~^x}KK4xXR?0@Y_s+!&QRUjef{C>k-H;tpQdr~=-cz`y`% zQ-bP6)INy=Xnq5+_RyOfJdPIu)kBSP{|M;JDh39IJ+QDPv_>F+SpmC$yuj&PL?2S_ zPlSaJA@e3MGEc>BAh_HCjiq>iB8-870lZ(ugHM3z9T#}h18A%^1uFLxw1yX4XW?mA zY+z)LWa8Vw=*V|~(S`2>qYK{!#$dh;j3GEG1n3;~38)>Q!)qD9^D(ZVH8-GAVgnbS zgcqNH8^}Gi@VOaBZU*qdZKja0$OjFkf!&7I9suWeaD4?Dd}P92LHlqsbFgA{pdUAr z2M!5b;>;UBYd|p*qZ>CjJC+zthY$j-kV-3{IPDH(c(r*OWdjYCu9*SSE z#TmFv@Z-C{!u$~A7i{6l02wn@0S!tZ?_uCW?XQB`aT?~3Fm%N`F7FNMZ-C|-8nH%{ zC$xVIH49Xqg3@X;6KLT=9v65H&=t~F*#ULa4p<%q*MW%j4&XY_ozH=p4^)>SZz_PS zDY^l*;~Hp95w^HNPS*v@VW1$wOh4Y-pmixKphd=@y?ju!FxuSUelKWwxHf255^aLs z3p_8|0WA-cG3zYsV+;+9Opmb!q8m48|IH4lo5VrufD!#F@IEaUJ_F{@DE%rgZss-2 z$Rjzf+)S@f`Oy8l2GDW@w3igo#s;s62k)%__s_xW{ry18y4G{?8MvcPP`QHpwiQrw zKxHG?9KH#Rh@AzHzI6@s)C%a*IPjXQ2~aU`7Zz%yB({+Es*@#Y89;Rzrd{BECMZly%piH)6tiq|V+$$M{Nd@g1*(4mW_obtLkUl4 zy8Xb)?18;H1&@h?>Izu-77A;x@_k@M9%BUcTmC@pHHN9dSq_5Z(VMS;X))F!#~l*( zKF~4;R3<{gz5v-uaQ+Rjg`^$y{0j=B96WLzc;uGgkvo7#?haHAT$O;!l0(>(>TOIClp{x zF*6{a_=u2aW&qt^fZ)Se%navYOca`#;UWqj#$jdvl>#sxf@Ws8ir^rzm>EDTK#&BW zOlF3gP!@s$jhQkbg%3C#Lf55(#G&142AFsw0|Ns{9Mnz+nF13B?X3rigD!kQ76-AJ z8NfTLKukCWt$$}i5(ka_gCuR4K;|RV!^FjyA>uGTc>g|$-GqvRE`~rBZ)Jz5hwaCQsdwOjh=VT6Kvw?} zD*gbJP?6j-ffJ%0Wgk5Q14958L>zW}Ewnkra33lT+XoNc@6N!$pv?_Y4>|_}WG{FP zHUk60HK;h~ybF*xcuzP;Jr6|v1W+G~fq?^aB~-lwbgvsMWn1$>%!lnS1Eoul#`92d15mpSHogOr zU;yQ7(1;L}gG4biJVxRnn9K}M5ga5IGs80^9)iit@EpNGVlhL`R7VnlFqs)%K^SNx zGXv;K2{b{l`#)j|g2g{$i1YG;!sjmdj1`b1EPOz0W`?gI3Ij7Ue8&(22{404=0Ge2 zj)$5L%Eus4(3n4n24QCK$tfTfDrRQ*hbjQ&F*7hiQ#n+Cfq|g|YCf!Ff?a9jC;;)7 zJE*S!Tk8cngdHq?oM8fJ!5FBW0F~b^2vNTsnr=aRaY43}2tmYuLd8M*Z$aW9%*?=y z;U0)MD-Lnk(d!^p2+YjDg+o2;BoKsJ5Q~|C4~Kf#aqb{h2+RyVaR$MMv6vaeaF_#H zNdr@bpqUw@aj2KY5Z4n1g&RT~TFrwEV`h-UP!Ez|W>CZ-4muGBqyiN)GpONE589QC zsur}V3sgQUK=;gm))T-~Ff(Xlm~%=5Jw~sQ1Jn?t?=dR@;G0MPO!zAROvLaEOC0CP3(iv6va6aHt2JQUz0mpqUxsaHx;R zAr2aqM(BsJm>JS=s0XchgQ-H$%naE$)aT+5&&MGSTKSDI7sg^{0Ig1f@enjK11uFI z#6T=&2GFTpAQl4Wi-FR4BivrlULcq(Geb3893}>$nHg$vh}Yu~N0<-N55vq1tvJ-T z;}Gw}A>NHcycdT!>{Jk#OBfg?i-W@9F2f6Gy8^Vo1t!bPFd2tA({PB-!XZ8vhd6i? z8)hAxW@cE7L;W%w;wy28gHB_E8w+PJGpxsGMPF_;;4;ZP4d zVG5=aLNhb$$Dtmyy9%NPnPg@FtyDl3VPJRxjo(wyb|9?%;~)Wv_gheLXqTIz5h^YO z-RBM(0|1%$7%FarChjT;F((Kr4qBHEQV+t+499S|A9QOLNCg7V0-JLjvIv%efdRA@ z93=Zq3S#~|sQJ(-O^_6*ABw~LvpB@hV~B^#K+Hb{H6OanhhYa){2f#r7H$Tz5cU6{ z;-Ef0$T6VnI6(a}G3efT*gBe*Q1u2-ahQ5nIfywPXyOZ?;t5c3&{|fI`5?^9a1q1( z5OL5BSr7{qGc#Ppp&qoN2vseJ$INgOhx$7>#P4B_VvcDX2Jj z%!7e};S5y#4^$i$&XNicb9kWp@nPbnP;nVF@$*n|9W-%mMTj{zP;pp4xC<&i4Jr;Z z{~1(#8JalA56ld(UMPr%z|0JfFv7uE31shah5{>yI#`H51&iNh*oJ0)zcNVuU4~;& zanM>Vh)z&{?FokYAUS3R@CjWYCLEioK+I`?w*O)MkttB|IcVY_jm!)$ahU%GhxmI8 z@efe*cR%I&IK)9a#ZcW+5A|;y)W5KL^8{3U8B`oJHw4ltq7Dh4Ur=$- z{0vAu0xBK=txg4)IzH@qX~y*4<3d<{QXZFrEe#2Xl~!xnS|zNFosCBB(g*yj+MV1H*E# zIP64Rm?#6o8nF0n2GB)+2vG)xjbQOR4A5#5F0~CTewzV(L}52r{0;+XzXe<|0|UbW zu=s5T^q$92sQ3lw_#RBpDX2IHc!CWk%D`|QEPjUpy0r-|aTP3no1p?t{cWiD2Q=}A zQ1JxlnQ}0LoAc}Af`T4d?JX0giWF12a&`;Olz=s5+iJ$10)8*PEc{^G9Hi+7<+=n?|{$v1`9xm z0I)dt0#T?4gbD|X--Z>}5J3h8hB&A=^f(B(cq&-@4#voL4pba;K{8x10|P@bR9qa* zhAOc5Z3Y2o`3BR|2o}GCF_PK=6-OTt><5dpGeV0)m@y1f!Q!_WUZBO-9I*HujC{8k zDh|Fc9&QQ)!z!paXe~C9FvCWuIQmG*4zT!bh72@+?FWnBVF2wtLpJ9aR2*~;6S6pD zjrtu1*ty;?xl2&>pfl%TVj%hkRD2nTgM{xv#Wx{|ftXLA;`=}xB>W00j$R^u1dHEh zut4+I53u-DM%cUs%&7lh@i*YJVPRq*niag}{56P)g1N!sZ@}j*BTEQE#i3g@;8NmH zaeKH3gdqzR2dy=Oh(JhXs5pd&AT^=l==n$=DvqB1O`+mh2qVBOYq0oxFdLb01dGFF zRS`1oP;s z0%wE8Vb|;;#0#O~pkzB1qarAiE3>AkS69l(nCsZ7IYy(_;KU5sL zr4lZF6eKB2*l$I%T*H7KhEsgO!4byI^t9&I~XYPCSN+Lx&&W z;xEDCuv7Wr!VK@h;-D2j2r&@rD_Go&aUF<*gnvWDVe_OgDMs)<3NuFZl_Ts>ar6}; zyijrUc9bww9DU|o3M%dnvk*!vK*f>!?I0<2s5tt}vmR6&be1(p9Soa5#bNy#n79>G z9C^GFBwiAZ7|wJPyP`!dXyp*mxOCssJhuqv`L8m2xcnE9`7Wc;p2Ro=ZY}^5+!xbtHTb~3I_koJT z)=$91gTdl{j4RM=hysg;p@}juBtpespvh!_#Us%~85r`x;z^9?{fIKCIPy3Y$W66S zaS$6Bw}8bH8PUtDZm2kDPZ+ZLNnr6LM)00~B#D_&arE@L04$!!Sb^q)$|Fk~O%Mhx@Y!Rq&6i1&fT4`PT<1&g1-5T64U zzl{-(i=pD+VjAHbhE-5;^!&aNEdC6`{2gHN*BIja!Q$^Q#E*f+KVyiW1&e>f5Qprk z{EZ=g8>}95S_6{fLHC}4#dl$h*S!RbD>9*{!w+C_B_`-GHgLnfgT)n@&{vTCgNnly zLK&>!y^Tst=;a;{R2-@dP6>m>Rne1j~s5p9m*&8gb$^_b10yl(#fguPiuEvC3ZbU-Gk=26O zkbU^Onb6yT>0tGm7~zu#6^E^h2AKiErBHG7c4G}x9CXhgNF59}L&XiyQdSpOT!#s5 z_>*BGR2;p(GXp9PT@C{?o?$*z9KD^h3@VP^j$I2CNAEvwfr=xq7X(?d8!C=I9(V{U z4%#mRQU}8)q2g%6R}2@R;>hFvAU)Ti;-Eb;AU+J=gNjGP1fcX&s5p9hcmoxODuYv> zq2lQA{tGOwixKaP;Jvmw80m@wEUwFh-ah1qildLWi-E;0m|*M1VGfdoiYuVmtO6BB zpUKyTio@2W!^|;)io^IY+7c>`KC|Qi7Pn?XH{Ts94$}{#{h;FLE1^Qc;&y1RXJCkd zitm6K0Hu?`;`SKov%um`OtAF;P~{ATP;uBjD=_g2sCWcg!@V9V-hh^o+MwbFXyUz4 z@ds!wngSI^59irXaRD@Y7eU2g_Y%O|xe_XlKEJR5DlULFAhI1Q4!)ETW(WfV!#=2Z z0owe;;{9EF!R-+ z;y=*larB_#E6~JEq2du};xZCK&bcww0Mkwio@IuqvOHi z&S<7EFrfZhXJ3Ka+KH-f1J(QClsVNB@#xXobka18hC0*i++*?=@7 z;e$|d^m)${P;t=tSV+nl&O^nK#X#(9VDT6x*!_4QF%Z5B6$i1A@e`;xdOh+QES`+v z{!d_W*v)eYlYWB5F_bfCgCh#9Fa({~02W6}vRAp|UrKKjhSuo5he-g;wThyyoF(0iK<3@5?j=%Z!~48her9H?T#6D2ixam84$X?pX+T4=e{3;85QKR=*fS{RStHI}z)DVB@AgkAckZf~$x5 z_bLwaAA-$a30Dtu51TW{e8f5>nE8upLFP|}tB0AdCjL!8|eWG`YC4Ynd#(G|PD zGF(CVVk@p7jVOFZwL+~aam2n?*!=Ah9OC=H;)vDIu>BE_ak%Fn4sjuOkb5xAF$aqyW-Gz>8-w=ofyEK~ zWWje8GcYi0amOA$yWJTWgcy!99DufmVJ(%*Q1J^;ao9YAf(JxBx_GV!$eoCNwXl^0 zJ3X-5%j5}CkJxVuzHb<`j~grwKDh^+LSXafOFglh^Ad-8J1>YkVf|cK&7I_h-JEV5 z;(NS6?)(FG3y1*SK@6g~y|J6)?F~|o*yjtYac6?X5&L{${lzcdpnS0np3Y(ULdOSG zzO9Cf!^*<|u=r98@k+4xat!e~J|OoX_VdElkp}u=cYm)hcJ)qvAaTV0Usw%#8Z3_3 z{|nops_Bp2{7f9;3vr0Q$04pCfZcpc9OCvk#Onh<{zB|ihP4#A0zu-4eafIad_nPE z8i?KAb{yi)gXwY51AbYdH;)u~?*t&oXLD=1M9IPIun}Go~W04*V zG9R&y7gnE63R})u+3Hv73J$Yz|_dHS7e6$PkeEnBtGY;)wm%uoh}@C`dhG z-!$l)Q;>hBfW;B}ros1BGB7ZhhJn;$ieCeZBlc5+?gR#zGdmol9AP~ z7Kf!`1_tn*zo2s)B0=gA`>8?q`GU+>ivo!w_D6&6a07|2jlv#ocfslr`=&v62!PZV zMq@YU2Ur|aeNPOee1qMO3A)b~WX@b1;_IN|8=wtanEDeq#2>|g+=JN14Z6P;Wd4*` z?BZ^55ceoRyP}}GY(eT{aEKShfy@EjfB;g(0N<%=5sy9G+;NEa#e>X2>>mf+T?;a? zIsqh(SQQGoe-=OswAqx`UorvAun_%^b_3*I#@;4EbUnXGW7lkBHyX62} z9M*2JNdno6*oO|fXBK4dvn1^He#arskc?fuQZmSV#C~=is0&u(P=5}r9d-S1SVp!=!wWIAWhZY^SJX0Z1INPak|IDgy(<8n8HGpFa3pRR#tI zwnC74#6Er4IXT8)al}4-*vgx!h1lJ{4y+!re;*c}g+(CqF~v=aLE?yg{h+%`LE*C> zERNWZ4=bUvOR(F!5{LMq671&tmV(3)=Kz53zhYouU@yaNz6K6)pE8g+i1PtpJy^kV zkT~KT0MI?6Ab;%zizChffYl?x6(IGP;xEDCi1PtpBS&IYAoYmz0YLY8g3LFq28koi z2Y~G)_o~6}uS6W;vui-+z;Z3*%xaMN-nEeOe*v`ohqd5mgZk-A`{4NtRvsR&1(}05 zX8?3}Cdiz!I_&P*TnAE*SXB?Y8xy2HzaAuxIDY_i{~}1-sR1O8IDY^pF4_nZN6fl` z?f?X-e*qRpoIe0lzq<*f9&!Ev=$=TB`U%Y-am4upF!jkTAaTU`1E6~xLF$!SLE?z> z2SE2Rg2W$!#S!NZz{D4{fz%_;AAseTly>am8XX{U#JL2poOu?9cu^-vJ>pyf(A|k3 z_i%S%7heJvN1RIl3%90jka}2ZVt}7;WY~i}9?N?`>JjG^fX-$I*{j_PO+V0ycF;})RQ&|#9fvUWO8wZ?SM@{8FMu|X zL3jIs+<6Lzdj1I@|02#qfbEC)Isv=+suMx#5$7bp${&MC*wq(J0;xX*U;O}Esi`s< zB#t-_0k-pSJy;xZ9s=l|IgtCKr$GE=0NpqaTVb{xDt-VuF#{Wk)|v`Yp8#FZ3~Sjp zK*bxNQwh-KCc{&xIOv=MkbN+5k7*Ed4nWnzYOICRu={r@4)N7ca}1zU6)^WOO^28t z0L?(KnU5r>cmY%#R$lFZi9@G0U^^1EW`M#IaSj7)-%m4G99FwBFu>aLx4`0va~NPP zUBj6mb6}?eFfhPYs?7q6BhF!f)rgF)VbEP&w#bFyuz-P8IFfjapiZ6gp*}%r_ zz2`v8KL8bnt*BcB6)ym&cML%9V#vWUO$2m_nQkb2Qtskz@Q18NLVo!yMLeK z5LcduU3~x!@kAWr3vh@Z!y$eXhq%;yh`%0y=h+bcErg0Ufak{$;wR^W(gR|48FXI~ zDBe^SfW#5!QNUKz)h>XTuK=DOV_*Q?V+2yKv=Aa50G>yJAHTw|cOl3e#JLloJAgpy zOBR8|VWYeZ44`{_K;q_$v5Ws&3^Bg|YCf#Q4_*QhcYvN(3KL(o1Y{24JPKIh(61{O!0M*+Hv z0wiv=0ek%V;t=n}A$|#mxX?!I<}2e6PuU1^KjM50(A^gxclvDti6hR(fR%?5n?d4; z^D$uQ>JwNTaXtp<&Iyn?r?!C9BhJSF-5miEU$PY>jyN9!)^dFd7Dt?q0lxbIbl(0p zP`$7nUN6A*XP0jSnS(et1GZm$5m+2?ZU*?C1_lNO-|g7Lr*}KZ99S!ifdO>q0mz*) zJ3!+h>*4l-r`aBKSHzy5; z_#_6=Htz$eN1R&%x~~A_p5px=am4u~;Clx^=k6Y0U_g{6Ae9ho0TPEWQOE!s;%PX< z>u`v7;}Ac30OU@@IV7-o`PVqqa~uSzN1RUr8$Z-Kh&`O0ai~uPiz8N@g6=2)c|7V6 z$b7`PC7^o-K;mwPLE?z>NkDf6fW%pjfW#5!lYq|k2Z=ubi^F;e3=E*N`9b1#N3pvz z3y1hL9O6fhg6zdK|D`Gh?0Nr2%I)fkN&UMGIyYnCp@oPB5 zKY`XQFztb+Rt5&xc!lh7hg`W}!VPhL3oQMl;1KTwi^E2n5a)QW2a98lV_yb~W6lTt1&d>@>rgrg zau4EM7x1z%(A^$jam2YUF!2nqIII`N06({*7c7oA*9E42GgusPt_w{3E?69Kt_w_@ z=@h8msfWiGczGUZo(L=sJM|k8<{76DY*0MGa35HGGu#~TGBySVhGSsy7PvUH+t2V1 zhdJt}LGEdTtA}=v89cz^?Qn6JIhm)iyQd1Qz7wt<+O1`n2Nv&vi^I~xajS6vfAa_oMi^I$}28&OFi^JR*4i=vQ7l(y&7g&5ITpYIEX)joOHe4Lq zonv?h7M}wbhnX*b7UUjSEyutB+gC9WEIuDYy*jS>k*wnUJdf0zg480tJcLn`Ww@=HtN^V8ys67$kihgIB>=QGR9lGGw_5jK!{%(6JOBt9uMJu}a>3{N3} zwq4{CUMhQzy?$H$i?=9H$oCb^o$$Cp$V zq`C%q<8HJC8^@zJ+k%bbK@B$$X+ z+NAVEG?THVrg+@0C*0&Tz|!VKBqOjto#S0y4UOV`exIzK+SDL^pGCYkTA^8D=sN2O)l{a z@J@DhEenYcwulcdF)~QYFDg$gN{I)x9uiCPi{eWX(-EN&Tw;=%mx48vU4w#442>Z@ zjeJO!@dSsgYp@w|+N9jUQ1_Y>;a=R4jx$L*8+n4WRDgGKkaw_gyk0UWs0xbm3m|z5 z-oF``XL`VJ~I#8O-n4Ta0Nw8yi;ZgJX(_waq4Gi z7G9KD0xGM#iu3c_GILU$ja02dFUd$Pf^^AXl?Q#>Sf)tDj;m|1VSHwgcd!$r4~WQi@KgY8x)_>)dc!%H zh>SC&TyFrXfQDeG4*_@MN$cQ|g25H)paBo`#EvvPHb7;b38(-w%goCxfeuK;=VTU_ zfcmx2><1ZRDoRcB3=N(l8e$M15+CdlAM73< z6k>=`9U+Q-{H~@?>nt_5ASW?7H6Ap==jjEBi=bdHUN2`(|o zNi8n+ECV-1-Q!(dE#iISQ;QOdQ(XhVwJX#+@p<_vsbDQgHS93(t~sdTonKJt>62vO z>KE)AZ)h0rn3I#A4E8XnTZcUqf`j5g;RBCuu=4n%#NyN-P!|xXMuoK*EI>_$r2PCG zyd5H(?KjsT?<7Q-3p3Qv0Awm;1e{EBgUvyi57NLfGzu@=b3`$e@`hvK!b-x7%)FBL(!9*V(o|2-5J-uUVL@hUa%y>IacVrcYXRzo#g_z^ zn3j|l7_a%@8J2lr1ogHqJ;aCNnu=8fIvoSqvGWjZcivE6q(xEux;; zrbuQ}kQ52Hn##dzXp)>?Pzf3h&&*4YFUcn}I0BM$u{KkX13WLD%8AYb5#V|8`AJ!+ z$>f$TurN0?2T%IvrWU2A#wQjOq~@gr5!VwTr@sU1x?t(KAkDV82D>0lsu&qzxG=uB zB(-2rI1@6;4jnHXsSss82|IfMbZW z2Us;jJk?zVj{!pikpCcS*^CV1bMg~Yz^lRH(~7`rt&%f96M96p@sP|iG$=?cNzMS9 z1u5roHxfb9h0u)bhZ;AKFvqPE;tf3?XG04^20b5VBV%(AWdI@|0w9(#h%f;WrXa!$ zM1a*HU%4LYzlUY30RvcSjH4=i7D98reMcFlp30W-Dw2z zl%W~KP_SYnurgz?b|Z*5*xkku9blV`z*ZQ6tuqE2ZVb@{mW9NZF+?v|r3u&s6R?>k zVD%|;Om{TYwF>fQW#t zwgihBMc3|Vul7_Hyc9IjiCY9 z07C z1`HulZfFd#50V%RA!*VOl35HPDaX(V>^DP5>M(>PBtv6}%OHux5RzI9ArWr~$xVik zWMc?PH-^R#$3xPLAta#~Leh>QB=Hy;Lo9+ME<;GNH-w~nLrC59t|Oh$`F$N3?WI+5R&Q)AxYB^k`fIe z3C|Fc@(dwK&k&OK457t_IV2h(DZ$VJoD>WpsmTzMv!U&S+j37zF2$D36AVF>f zi6bLO92r64$OsZgMv#yfi2x%=j2S`V)(8^QMv$;Jf`qjZBsz>B(P0FM4kJjA8$t5B z5hUb|AR%uA31lNkC>cRQ*9a22M$ozf60Am$STTYGxe+ADjUZud1PN;+NLgY8i7F#V zq#8lu&j?bg7(t@g2$ETiAo2Y7AbPfVSYk z$S}XO1apy>XR@n{scRWX2Y8S*xF9|`zcjBTH6^~Fq$oZ!4?N9*yP4~g42@Vt?6 zysHoLA~B-Y2uT z#5CSBw;;#WFW5NV&=|~)Pf5*51+THgWwYsEUKj{-G}4?b1+nLB3Yv(-ob?VijR(b< z892`1F*86j^QNx;!OnxkCBY@2RXAj>5dfuNcwj>KYL23J&Ao z5<{c-F!25!aQ;LpfM^x}1Xn6Rmnp!~K0FL*8k1X?O>5$}^};Ogq?9|B8< zXpNsi7RQc;@t}p?gE*264Z!mi;6;1RrmlX$@z8P-zK##2jvla-NXTJOS0mcUuyVlA z5oEx^_t{Nd)_w^aejlz(DOsSxOCa0z4nX6rt=b z#Hk8tnJrE=7z?0rsx(Ae_X<v;o-Cl$?OFTu>IFYk))io?2W| zlwS#U24Z#?n)&b~WQfB_&|zp=UX)pq3f^9pm<;MdgY!;szHvcm2_zrU*Y_szzVV=0 zL0FGI$UC^i5|qK?GxO5&8RDa&K(kVo@xcZ0xry1S@x>X5MX4#E-A1PI!SN-Tu4S&K z@gOckd{jtqaET!{r3}R-Maj8XPjJ8;xQ1qEK~?M;;GGOfAo-AB1PSCY#K%JqI!H^* z1o4t965|s=OI|?>#o;3$Aoqn~#1x|RcZH-pL*t^-ypqh^RLFXNXG2gQ9@KOQ!PJa; z3;{?#dWnXj!UdeQ<3Y|V$tcP%$L=CSl%gK&DhyLmlz@%RP0fV_FlcXBd_35E(AGQ9 z+92?`3Gl%mQrkP0@xIV?6QIzB1V70&AIK2M7E{-t+*}5bYYQsD^RkAPaM$LiXC^~J z9qicn;u6sL6UiCb@sNm(@(a#4P0J}Q&Vb}ow)n z6N^irLxofswS!j=R51;dIEqV(a#Hgc;-m7)!GV;UUzQ3=R*2Cl%aVNP${trTqXKnX zp=&Ov`~l^0i}-lRnJR`B@$n`3;1a4h-p~MYG(oPbYgs^YR!F=nNL^-nW=S!`VK~PQ zosB>_$1tA3C0ws4HBB!*KE0wMz96-zI6p5jC$pq7z6^Xc3#iwHV;MGN_z{u?jX-&j zj3qgc;vG@7h31uK=B303r52awLcbx=b$S*{xODQL2(IM)POdKjVNrKjgW_9 zF^U{;`Ugb{LI2�t0bOj-eU!)S47f9LA@o=D7wW2W18u$Ah-gLk`h# z4K@KCp96|tJO&x3fsV{6iBBp`OG_;Roqv;=nF-3-#i=D=t+4hoc-47IVo4%6Q({>@ z16h7RYPke188Mf3IvbL;B@$c~QDa+juq7o4wI~%lVd0t!+A$5v;FRx`4gl@F0d1HD zMG7dhp$>82O#G0{hj;8BngP5)rsB=QXwwGCIj#YI!A9{=!>R8uSpI`0K^)s#VHV?c zyED`7p`_*z^P<$^)S|Lfa7{tEb3kbb zoR~na!6+Eu?JSeL#9ZiNCQ=>jnh9-hg6bIX`CeG-qAaX+5!Ut@(k^9Cd4Ww0Mt>NW zLZr?$NC`$$a&S+1LGx;Gi6vy~e`bC$wlf%9O_Os{6N^AIT1N4n`Nbeyl2`(+DbeG6 zaC;bgrnNQUDv* zgl9GjNCZPxl|v7Bz_}F-TDk?7

`bW1KgK?W~C8ka*W%(|AY|1=7UMhu8u=$N+1y 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 literal 0 HcmV?d00001 diff --git a/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/miscHelper.o b/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/miscHelper.o new file mode 100644 index 0000000000000000000000000000000000000000..753963d0f4444cf258e6b389ba74eb3b33acb86f GIT binary patch literal 1712 zcmb<-^>JfjWMqH=Mg}_u1P><4z_5WC!FB*M9T<2RxEVh4%l+~=_>PIcg^Q7aA=Iar zXL~TeyaNOOHg{$h{%!L7+u|Adw}mq~b{=r)yxDooweyzaffsDe4-YsTc*oLt)sgc= z=gsD4%*{`E4!mS?Jot#M`Jn+w@Zy1&EX@yjpiHLbhdi9;I&U^VG~hhv)XOs$P^Seq#J~;Z^f9kO=3ej_|*o zrx;IOc-8z6EO4qL{9orGkS2&8&I=vx|2-{#^0#vQ|NlQa_AtM^3j@R9329&&6h1!P z>>l0a96p`LeKe1~JoWGYe+GAFXDbDb(4^A5l2QdjLp>8c16{*XFxRlo$Vkt?L=!3u z@+boX0}BHKg8%~q11kdqgS%fS0}}(o0gxChT124g7^{L97%K!ArFqynCNMHEs4y@v z$Ux;JK@scEC(y>^$|upx%=DK}z>$x`?eH-M1_qFR7pOWhD2SMG!gz#wtmzC}Ge`Ni0cZ&`T;VX3$H{ z&&^HED`C*f%P&dQbN36?EiOq+&W7^S^Gfv!it-Cmi%KdP^omk*67^Cu;?s%}b5o&~ zQ$R^GFo0u$4b2Qlo@QV$gT@0)8We9ZHi%Y)>W8H}kQfM;q3HvOfiSwTIs*d(2Ll5G zx%zdW_8WiBbD>s2RYIs4Q2n(KE}R6}2j?&_FbG1;MHU0GJ)nlB KgE&YST|WS;G6}T+ literal 0 HcmV?d00001 diff --git a/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/regex/match.o b/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/regex/match.o new file mode 100644 index 0000000000000000000000000000000000000000..6af7c774d5b28c55508725f92ff9a2f758208373 GIT binary patch literal 10664 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 MIS%ArkUkg&0LbGbdjJ3c literal 0 HcmV?d00001 diff --git a/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/regex/regexPcre2.o b/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/regex/regexPcre2.o new file mode 100644 index 0000000000000000000000000000000000000000..66526ff1efc272c79495a0f2d7c054bb634b54a8 GIT binary patch literal 22648 zcmb<-^>JfjWMpQ50!9Wq21Y0wnfl?4;5mSq4h%*NhG4b)3=9kc3=CklAOiz~5R@&< zz`!8Fz`!61<%=;eFo-iSFi1f8vJ4Cia!|Gc0|SF1l&uD()uFTo0|SF5*iHrp#}LoX zE1@2pUxPh5e|t2)5lHdqW>E#H@aS|=;V?Yl(R!(b)1&npe@g=c1B0jL8=p=U70>2B z{N*kl-PWGXe;7-R`M0?;bg=t$tEhN%Tl;h-b2uGiQD^Yzc2VI-@z91CR~q2ad_*8R z)-mQVzq|v3Z|jqitFL7ycy!+P=zL~)=>^C=9-Yh{oyR@8SyVhaodtY4A9-}X14}@S ze!bYE*A}D@EC?osy8A!#%l-1`4Hr1(E@I@-`NN}A{J6V7fOC+m$8mQKRt5%!WA361 zhtu@<)w&VwG`O+n^*bYAo5d4zel$Qg!Rp%^F1ixXn1x)%=GAvQQ>ekJOC0; z_EC}XXnw=t*?G{j^O#3>Fo#FCv12$`r$_RQh^Xe@jQo93%nS_sK}i}S-gz8ko&bb% z@G*-|Z;eWUPj8A!g5g`A-Zd(qRO!(fqoUx`nWJI=A}n5)A;Qb2^N~;IGwm1^8K2Jo zAlU+s z2VA`QsDOucj*0?*OAaFggHPvouyUWy?;hPUkPz|cc46gcz0Ke88WcO-Au1f2H$0M0 z`*fzL1b7^GQHcPD^bC*gAdX`$DhUi8mKXV(-T(jp4-RrW5Tm29-UjjT0pL=0J-iMI|In%0v{YK{{QEfcVS@g=oJO&g$H`)wHJY4cY*@__@V#*|Nlo1c>b0(|3E&020kck z;Q(?Kx~4{MOiU?B}j=#Q;~e7;!}60) zuP)e~kgVj>`5qjDpyYn%&;S3Py)G&SaIZY`I1bK1pz<7A5P5WhMW7NOlaQDY)eH;` z_DF(AOt4ijD_`dP`Tsv{0;sr^@o4_V$lo%J0hFX51t2(9L4Jiq+c6e#NSwS30|$u% z16q_q6HASXg->^mior{Lurg4*9CuLx)h!G!&-?@12Q39WdVN$}Tn$h9^tz~c>|$VH zU;w+$1Dwk}IuAp65-(Z){Qu9t4H8Ek>KUfv0i1O$>`Vtfx#IPr%A+qZP zkOpk!Tjyzy#y2-Wd8o5SMFEs{4N!`>6X-=;B?~C^lUT%E0%-ylaVJ15u;;;kGW_q; zZQ;{dqv8SP`gHy`{00hg3ozFcRB5@WD0p;pcyv2(fHIYXNAhWq0u2yHz{Bz&fAdc! z28Ics^3S*Pr>o(C|0OC89^F15T_GwK9^K$|9^HGu^6;Dv(u*kVy7zz!22eo=E+Z#^Tm;Xep!{l`qawlI zaspfyLJ|Y0wCavw{Q)(fMFUh8nuGIYh>C*d4WHg6DqwStx2S;J4@xv1GkiLifUWXK zK7FhOEYAQcA;D#$6sSxDm6C!WMmH!mXr4m%Fx;o0^71=sd3o|X$mcC!pMrc0Do;GR zr>KBR2ynqU0qndUaL9oR&f{Q#EntUubVAa;N9PoqBqP)9A1(E_inw>c$ zd^#a9?a>{<0V<(5K(#TnzP650(co|5_zNoRVX9hGKzS9Zl%50%wC)-e3y;Plpd5}U zrNKo=8l*mHy;PzEDHlQUC`S}Z!5+KDO zsEm(+mhlPbWxQwSQLy)XIyGK0|0c62XJAN5EY3`hFD@y{%uBbjiua9A&d)0@DJo4a zQOGOJ$x+D5FHtB<%*jjvWd{ZZNP9NKv-3}Aut#^ifJf`?5;IW$z@zi7N4K;`cP)oU zud9TI}V5 zqjJHsyF}%N=W!Pmh|qBtl?NaN;NmRW`VVIXtX`1xhc1s(k^E?qUwlZhNrvS`U=&@n}B6;nVp5 z

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 literal 0 HcmV?d00001 diff --git a/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/regex/regexStd.o b/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/regex/regexStd.o new file mode 100644 index 0000000000000000000000000000000000000000..32a7b9db5cccf0d164b3829a30b0deb7c6b505cb GIT binary patch literal 269608 zcmb<-^>JfjWMpQ50!9Wq21Y0wnOe~dSHj=`mT+K5V@hQLsXfNP0M>IHN}ph0U^oe7 zpMuh-85kJOK-p)Z^f@Sf9!g(;(ifrhB`AFvN?&1MV7Sh}z;FY~zskVCa1F}7$-uyH z3(CIDz`$?^%D&6Mz;F-BzR$qG@Bqqw$iTqx2+DrUz`*bX%6`hg!0-&pe$K$a@B+$y z$-uzy3d(-Xz`*bZ%6`kh!0-;re$T+b@BzyH$iTqx3CjM$z`*bo%KpZ{!0;W){=vY& z@RNao;VdHq!#PFO$7Vfl-Jf#Ek)-5&-9hQCnuKL!Sd|Df=Ps$*niU;sq| zGnCK5$iTqL$iTn`<+C#~FmOQGoQw<%T#O71+)zF*BLf2;BLf3JBLjl~R7{YOfk6n$ z7G`8%5P`Bq85tPFploqQ1_lWzTauB1K?=&2W@KQHfwE;885rcCYWMEKZWMEK-@--P57_^{l9YzKQT_{_Rk%2)U$~I(VU@(HRO&A#%OrdNu zMg|6RDBF^efx!yOwqayou!XYi85tNH7#SEGp?oJs1_oy++m(@l!HtoD!5zx?U}RwM zWMp9Qg7Uo?85n#R85n$_e1Ap;h5$wehCnDkh>?LI7|IS|WMBw|vcnh|7{a0K2u22m zNGLmsk%1wak%1uw%8zAaV2ER6V2FqE6Brp75*Zm7lA!!#Mh1oyC_9yrfgugbPG@9b z$bhml85tO|7#SF{q5K?128LWl28KK+KcA6-p@5Nrp^%Y*p_q|@p#&;k%E-V_24$Bs zGB8v?*_Dh83{_Be4I=|XEh7U%9h6_s$iUD5Wj8W1Ff=hTFf=nVFtji-FtkF&+ZY)b z+M(629?IUp$iT1>%HGV#z_10%-pa_puno%I&d9*9 z1IpgX$iT1*%HGY$z_16(-pk0qun)@K&&a@V0Lnhd$iQ$2%0A4m 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 LQ77m=Y+U*QZYY2f literal 0 HcmV?d00001 diff --git a/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/regexHelper.o b/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/helpers/regexHelper.o new file mode 100644 index 0000000000000000000000000000000000000000..5bb336298608602dd77cbebcd39d17ff027acbca GIT binary patch literal 5672 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 BA%y?{ literal 0 HcmV?d00001 diff --git a/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/libs/gzip/DKRGzip.o b/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/libs/gzip/DKRGzip.o new file mode 100644 index 0000000000000000000000000000000000000000..03256d0268d7e28ea9b64a21c55c8da332fa635e GIT binary patch literal 29384 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 LgA^fQG~*ZmR$G;# literal 0 HcmV?d00001 diff --git a/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/libs/n64graphics/n64graphics.o b/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/libs/n64graphics/n64graphics.o new file mode 100644 index 0000000000000000000000000000000000000000..fe6926cdedcaacb008512a0f81b105124b6fcdc2 GIT binary patch literal 138992 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

mwU=qUW# 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 QZd-*YhNcxbhk=0s0IC!!FaQ7m literal 0 HcmV?d00001 diff --git a/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/main.o b/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/main.o new file mode 100644 index 0000000000000000000000000000000000000000..b8ace2f24acbb1661fe1bba78dac906d0c52f553 GIT binary patch literal 226032 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

    !Ac90GxyqJQu za8XVv2WM%hOgH!tD^ME(Jh%#DNY7(0{E9Z3j6t{8cK^1ZmcTX?EzyQPG2FZa&Ni zN>5t++q4}T{>GF-HfMvE%!BOEj{z%teE^Z(Kql$HOgiSGq62jX_=>&W5*5(#h+s{i zk~;!a0tJ9d5Xh)Adc=WbAe*f)!wzCd?-uZ-jj)&o8Cn4{v;etAfysgw1cCM8ImQRn zt#E|JzZZ-l3t=Gb))Gbr!|Qk0ln!jM#&nUlg$ zP?QQ`l%y7yFzD)L<`tBdFz9A7c!C%TUcvr;3Tc@+sRfB88F~!5y7{FgUGiNVD?NWrnVIJKl$AtXOPhao7n zEEA+y!Gr;%H4!WoUy`4n6JMNKQj(dMUaXf@oS(-~S{x5@c2Z(-YEgb}u|5MtsXojj zAY1eqGV_viN>frnvbp*U#YM^b3^|!e`iaH45C&KzC9xz?AL4O+2EF9O=a8f`R0tzn#FE>9WH7C9}IWZ@dLBAxUC^a#q7`;9M zO_q6feudOSpo5q}9YvJ#3e-CVE#?OG0vJHE9K{@<(NWO4&`=IgLjW{%2 zp~GF4&#?_sc7q!>u+~}UdzceoGX>xq!|#EH;UTR(NVdakX2WifBN&c>u3F-6UBSV? zaI852bZOSH=0p(X0rD{9E=j0qTfn{sbz(sMbWo+(+XB8Y5n3WkfQE5Fy%?~1@UF4W zpU{SsN9TQ?PT1T##8lAnq0kXo@G2QZ*Jlejm_gI!pi@=Brh$4(;OHPTe0re=Grc4! zj64X2dvCD^IPC93{Yf3i78lUKP{_sTpsVGn>)6fU_A>R&ZHBZSkYWrp@X!e#RRpEa zHQ>G!B+$XF{m%EtK&K&t+6@7)*z1MNwSmMm;8_SXtI!KQ9~?Y?0cur1d(*wpYskRI zns-9_cc5`p@Hhzg#zR<22ldOq8?(XZ2Z2XiIY84Qps81D*VR%@13!Wm`tpU2bqw^QUpM(px&EVq|I+4N~s*{9- zg{7kE-3+>X4OF~A!UWbAhP4qt@e6?KV`%mC3A9DWgTECtM*E3husMJUdV)Drp1(DZ zk%6J}fJbL@1gK8!CRDfV0hbt{y2k=i(SouZ{7^tpRD<)bb&ZMvL>@f0h^U)D_ZNUK zIRcN$fyOnFG$Yo~w5Whu7x0c9e=B%&x$y|75rVQT1auw)#3X1M1*-^cGxzHZAxC!J<&gqZ7>YfG7nOAxKP^V1qr9Aa*7svY}0xm(RX| z2e%;O_t1`rN9X%a7Znem?!};15JY`1=<0E#Qz&MDdkEmD0V{YJ4IcG^v}QWr23zu=mY5vgWD-3DjwiTEO=>PqXKDufo<&oH*8=AK~oN-;nTwR z{r`WMfuMs&-ow{jdvv220%{h)40(C?8+3#arB?*%jr)RKgj6%Z27%xW#BLiEu)9$E zO0fPPq|m|81dR$AFx|#*d2>%Zm)Oo!h#C;7> zvj@!H1}4FqiC-@SvuA_Jd0=t|hy+cEiNYAVP{vCM(D(#KjSMTaSyWzr2Sq%F0#Gds z-g5@6bwC9^_;5Rrxi3|r4t*&DV+g|-T>t<72ldcE&3=$t(EOB7Z@B|_&k%TwqBmZ_ zqwx)BnG8y!AGFW}G)Unt0J`EGG{^{AaOKg-?$PUR;L+)>0ADwJ+#P&r$T4>V2Jl4% zF)Glb0ef8|j=4rKcyzjYfKO;W?iv8jXQ1&#$PtH-*zIiv7Z1l>!L0y~PS*mD-d0fQ zattg1Iyo2AjsVrNFb$9ij8;&Y12GbMR4n-D(qpY4X_z(;8>S7^==L}cIq(!b9^MKm z)mlMqhhyNQYGK+yM#Hp$n(-dTTS4t=sBIt_kKR_$?A|fRd9C1?+!pY?iXce_k6y?L zxyM^U1sqfxs7~_eZ3XRZItG@8*#`10OdDuY&f_?E77VHlv_{dRw-q!Oc&rs94bui% zxB}A#j-KPKpp$5!+CcT2M{g@=M*CPRNE)UM6x=Xvpm_E;-U?oo1_=^yz0=zYN)g9e zLDCRy@D(M!t)TTo9>-h3GgJ^g;5x7uTzDS?OT+X)b~SqRwt_CV_Bh@OzAzY~2Ydo- zZ|e_628Lr`X_%f2nA^acbW@^gs@O@aS!|0M%~CTMa;6 zGl)H)`rMtBn{I8xvCdlfLQ)62}Wsow5WhW1$3Jds6`55LtNqN0PS)?hr+vC zR6wB%>gXMBQ2{Ma1gS$@A+iNxPV2W4UeLq<$RLOhyZ3-Kf*N+9NCIVQ(21^)8WS{_ zi>OW^H36h82(qY~MFrfOgjfwR4pcUPbb<1hiwfi(Dwyv;=T(5_VqwkT-WC5IgL)-#tD}fz=Xe)udgw!0`q5=vVkT#Tl zJUB=Z%dsFK4WHTEq5_Ve)^8axT2w#<0lb-3D&*041XMsEHPOI91gc^{6<;QV!J-1Hx}g;|D9M7> z1%r|~STU@M_UTqpLDc!k=XyXr1sW514AufN4&r2Z!tSn7fn;Ql-o2o#4p#>&683@$ z4Y(+*aM=qge&C|8Vrnm_AcKp-R{87&6^T$$$b>S4)4LZG1rT=k9u=h0crU2PhD#uo z?t4Lz3YP%&av>bZMSc)=H)Kj1!s*=$N~{oe_a5-fJ%rP{7oocw(prZ~)IxpJy+;Mq zWrm4DQX}$w7_^>-wwPc&3{cd)41!K#fgPCOIIXiptyn9 z@%lDM!|Ssk64bf^&%1#1Ye1F1{`689$^^-S&G+a${8IMc|Nk#}p)#-Eg7kxg1t43a zKwMD!1>AN4ZHF1%pE$Zd5meQV?oa%WvYV2Q`x9aL(X;bQD0sgO_zp00kM3{|r0#@^ z3iuwd9LPOj2H+;bd(b+3$n+|B-vwwRuDyq)i;4z+OCSpa19)N((S-(=VxWB&9G=~v z8Ej}H0y0+^AOMpGnBk)S2-VzlD&^hbvp>(+q|y02IP zIxVETUI4W1bg7SJj*0+(%QQv?2FPxiQVn0re?FbRV7BnUy33FQ^gn>MYJ>Oe){8*) z>+<(RGBPl<9^mf?1T{WE%hWwPT@8G?cY_)T9=*+=trws%Wze1r{+4vGCy%`5PMZMp zUx;sazJgEZC(s=LzLsA-`Q5If@6%EA>3j+Hm5=5}EFRkm_Skx)djZyfcIt4Hxchd4 z5*^6w5*5(SX(YoTDG2T@=*DFJe$cXCh}R(7qD>hY7{EI92KW+$*F&~o`c z2GF%h@{sW(&{Vttvd!;2dUu2RcOaWRJCFNxf_9s^s7QGB=7X&F>~uE(o8;LE3PApr z*&th650r9ySca$w@VCxoK-w5003P~;oHppu+ze_JGJ+E%C}o0=p+Vk50y-5BY_>;p zGpPH=2+9SB`|J2yXM*f%K2m|yA_QHyX~6LMDs2A-M1U001g*l#4Z9K&_3=7s8*J0fv(K+>4fYpKv)Y}^1=XKcLv&l%JI?>wt5db z3<&lGs3`$zdEh-20i+04zJ-pqHyC_I&qILqe@D+lKt8=;0NNX&!5+Qy!JX~qHy+@{ z=b#%8J7ZJ~JbLGYhUGv@paejtq=64r*8pwW-~e@Iz>CyV85tOMgAN`6mlL4#Ogy@C zR5-u~X?8;nr19zA0P3pwwtg!Wc)1BwEKl(5E|UPA@8j#+ou}a0T?abc#HaI>C%@Zu zaDC;|3E4Fcs#1J4|9V>9McpEJv~I6U=Zn?@72A9|zxsBU34jdW3_eDzB-o?dSHYvZ zRKwHqyhkUfjt8451|InEf$sAF?dMZyJy0s=)A<8*Vw2?!{@(SVau;;yKX~7&hvkVn z@L3+9z9FLO05xh1JUZWbb{_EQtWfajOwa%orV^gL0Schw<`q0U9UxT)=)465kJd|` zotH||LDdFF31}r@NfvTtaLK0=aj2qzM{@&cwuaH8nMFkb9G2ilT--r>=mrQm7#-UAV`YM$Li8lY|YpowOm&JbvD_;iP;D1aPn z(R!fsc&WN?=TF1`o|-Q`EpPJo27(6KL2KH<;o@m|kiXCJ|Ns9ko#zj}mw##e|Nno; zdc6?nh#0i-ih7JEhetQNhvkJ5SEwS;0XKpkosT>^|AE5;bi$B`3ixsZ$o?!3%kL!; zu7*zo1`h~XVe7ch%{WZim3ODFX5YUA~jxmS9%0b;3zx+NiAg!BdJKN~3T25orKt)9Mfqi!DXA&YGaEtXfa|X?P;c22 zbd=wBkIrl0Y7BV;yo-tl=qzN=YI_F$mKsoE>V#Ys>e0OeG!p00dDz2p2Waf6#2@TJ z@Ve4g(3yF?Au0mk+g?FI5WwNl4Qkj!)O5Rm&naR7-%(Vm3^_C50j!cf3{3~k6&VaA zP9D7#8LyXs^??^OgIVx~|8WoKVKcB53DAIs4qAW}gSEkKF$Ue~3Dph0h3Ke9^D9U< z1GJhEwyz5Lkl#-D+GW__2y8U!br&cMK@A1)O}pTexFCbRFcq-YF>EXgrXIX#_%-b5R4;Jni2HIB)I*19>BVz|8A8@Mi0G-IuSp!;y z+YO0VP@~=gbYhr0_-+^haPg{n0=&t{@&bR07HBBG^#G(J*ZCQA?qZRuh+p>~p=T+F5w@}rk+u(=Z?g#CI@a?Tt@UWIqDarKcjZrap zZ3D~y-~)L(Z~1gS1Kaoif+uK96ms$xNDy?A4d{5?Bj5vYeJoW}O4L9~kdMIK1wB>P zvl*eP^cJWz7XXz`(x5s5xw6tGK8j&c5Yu1(yS; zMK@^wJ^cJz&19oBxDAjUgy)h7gX+fcFU-M#0)$^+qPDMwyyQ2s0h4{L0Z2IN?;zxp(nJq z9w;dTwKrfl=)&UIqZvHY2R>gI97W*!HlKkGKLDM{3_So3WKD@1*tOHah43wK3HAIx z=;*udt)TMP!+I;Io-OSFpHU83{{4C-X#X4J9M{)Vq3H~i4j>2Kfz1G)(1%hU+k(!G zgB8Ze_kiRJcy!Byc8Mr}4vmC{gpcKC{?`Bh{{Mfy0~{}40#ufPmOq2bMGynhlX?Ry z2hqz%P#FW#1Mg3HbbbZj8IQQNrumHq=$Jj9ZgX1P_f^Q@(JctRsim_9bQ3+|0_)NH zzM$g`L+!pV(5YA+-Sr$E*0lm9N*=x80-yu2y305`I>iyU%rv`lD8wEHmCK;}j=)P- zV!>ks(DDVe{@F1k)T1|F0My6FJVUjc9aMh^fH%%q9)+IE47v}f+g$)uLJ0VD=W}>; z>cbX9fT|S^(4vXganN>7ckKtzvT0Bw%cI-%f=6%c1JJFGE4l1p> zLCf$g-}AS0g4%`M{sNwz?7p4(9G;!wpc`Rf4NDsp&>^z|pu!ovh3ObO1K6pS-%G%w zs-WBRVCMz7s30FB3p!vM{TSH^&`<-p5gcNj(H}fI@4vhRTmOXQ2vFofWAXdT8gNiJ zFz|0&dN%)MEKvoIok5ljf}_H- z+aBa!r(-PoU@w8!`S5RZQ4s*ykfXxk*=_$Ca#97TB!pm;@(`5vJizq_%D6eGeFfTU zy#@&|v*6_8n=QD@I?_Ya^Htl*>h88m<{;n{h|v$Otz=W%y%+VMR2ht=_z z`v(S(*4zAjpvy}4uI7&z0L|Amd8u#J-UN`cyv1}fR6I>=nR(d=oa?q3~5q`;_ROZp0{lUZXb?G{=L9LfcgglymG4i)agB=Q6 zA>jJMqdQc{fa0|(^ z+s?=G1%JyUP%`Ze1Mf0Z@UXnj-vSy+@azr~@B|%an8)GSSq4eCpd+}TLkS@&3ZRq= z8t-QSr`#G90r-S~0(?5(r}H;xGcgB$YYM2n(~a7)dI-ucs4Xja`T}iylk)5~1D#XX z`3e++;8*|+t($|4YCfz0t6pEv;g^S`-)R4Z4^Vpb z1)Y=(-&Fo7<=-!>L3wAJi;6-A zJ7~xR)1aHM;a0?bxaUD#if{0n+d&mSXn!K(UytTD8K4t5G*FU!1Zdfr(|^y-1D*$8 z*n2V_@VxlL$MP6|uL=tTgHLa$fM@5I*CinTH{SxqimJ`V1Nu1 z0Jr+V{yxSc4l2MI(0thg-Z%?yMTw~A^sL6kaTB=ih*Z$IQU{?2T#y~LFfOT-QgULpgIxO zmGSI6?s@RNJt+1qJQhxy&3 z^8zR%!@cNh`LEUsv@g)Yr}H;>g5@u0C#?_TTc7S!4v;%qLFd+kr*+@O$@WJ7r`lHj>rxP?(04iNU_hPz&R>&dhQICUdZ`7fBjNW!`7pkInep%c ze^~jzzs(g~-KBDPbX&ikG6BN(=!T@jm$iREN?jNjz~vOUf^~R#2P_Dg@AByU{xTNH zJdn@w|9~_><$GhK8NsI|-SIs5gw>bv4S2izQ?LhLrh>u%oKHMDKfg2tole(z_hkj5 zID)qKJT(77n|z=uHv^;SY5u3c-)F(Rs+T z^EhaiiGjz#N34)c(HkQ!@Ny~mcoY}VF@M}1-NipZX&~Mf|>*t;M;s3ffpx&E)#{F$bJkoQUdlpICa4*BjmJIqXL@f zEs6GQe$VJ(`5uz^5Ve&@^J@i;_m&oe3-kp4kO2W_%9z3#cyS@a=pD4iC^>^c4VP z(QD8+N^jnS*Ic0cY2PZe94LtZ=a9~KpeUGrp!B6j>+KR3P+12my*)Z_fh}k~P-1ZK zh5YN&Aah%9m+S_wg6Ia-STF^Z%R!dB?u54|d@a8hOM@NxA2dS@Hs@tLr~-$alj+ed zq5>WvfQ%*hbp8MZ7Brke=X!g9!kNDXv|hot^Y6K{*G1u{{Q#1yisc8*mL9uHI3iy@-rMEr7(Nau?ZA$-o?!ucO!!TP`d|9f_R z2j%VF5EXsUczW}D0sd`}t#!V=p#0vOqv8PSy(DzFsOW=(7*yT_fW}*2f;w)XlyBhK z%?_d+JiFb0_;%KRa0FFtpa~P`2qHKuds-glZvh=y=-KK10dxW+hi9kz4-f;?WdmiN zP8}8a6&J@qWtWSJ0q88v01r^Z8FCu43ur+N_*`2Tl>{Hn$DkU_0(2}sc(&@6;Wtoc z!oUNR-#S5u^Lqu4=HCkZePZCK z1NB>SR17?O<3IRV{@`!@1zI!c$e+&+DyAG>{s6a$^Fb%bYWk=oyo>;~rYs-xw0C~9l`xO z#}0O|uGc5P9)tAkAS9%J2ilheD&ssmuY#^5{sJ1c2=)M9zKS;41ZwxXTO4z@VDRX4 z*YN0dkMQVp_weX#hm?!%70{hd9-Zyr8BWMGP0&-#VWSW5BixU>gL^6-$KAoB=^n@3 z!DmT(9Crur!Z_w0!QgS+9dcULad+skt?l3e0tN<#V_-`eje?Hxn93IEpL1U^QO&-VF zL4%o4CTKtt$^@;*0`J&54nC(I#PkK-IML6@z~IQg&m7dK$psI6LKg0TMmdE+w;445 z_+P^1+5C=?zf}si%3NuvL``>C}^Mr zyockZ2&gUxudhMUZUxc~ZehJg7y=$S^XV=W@ae7u1u=gM=+0xq1CSd7K+AVKVJ$9D z@(0bBb*}|QxJUO~P!a$g5h4ZZq(f#sKvw}mW<5Zc?7V*H(G4Da_vi)>b$e+3^Jx8F z0%=n?_SW-d>9*)c){$3y^v@Z zJ_g15*hq?3C<%_Br20bPe-fc-ps&u$SF zXh3>cUN6}VI%91cY>|UUGkDV!qet^vuw}33fLsA?(?JfR-v{ywSPT|ux(v1qy1E&u zIRy;584Sf4`Q^n5Af7^QYH@L5da6QVUW!6$MP^AcCx${0a=df8sO3C>fq7q zTHw*?n&8pf3XbdJt{$LN<y2s}3%vkGU2wxO9N`#DQvh$fUMMFL<{bbjBOH z@D!R@Asf_udbfh|0;oj^YH9lPt_8)4M<;k=nosXuP{Hfb37(|#0BvIb@6ih`(T+j( z$@z3{1#PnT>4cba931T+*ZFj=1?4`UPKbHO!HEteaU8ra4#e^}-U`aIP$s;v?*#9F z1GxgUO%A*&ws$TlrFtB11vNIo>N~+3*E~8~J3zhn-qr;ms&g)A6P!mUSoLwprZ!NY z>3Az>i7i+kVlUfqupX!&XfZ07+1U!(^uw~Hx&h$2ahsH zeF3^~ws!+4L_v)^cSrthQ^5PDKv4~z(1ld@|3xlAJ{2ZpryQ^f}^(rnw~%h z6@f-H0$_!3C#WTO+(iWxDGVOH(?R8|hvg^!7DiCpyYo7@^9t(s!p1;CK;tDPDi+}R zZ;*tC2V^UBiHgDh5J_B&E`NJalr9F562Hfm}oZl$uYw*(T_y7NCp!-1G1o#Er1z!IC1>%Fw zZ|Cqh-VBeD8qnnypra>{TRWc3M>N1wQebOd>VP^h-Rk>5 zO?t41Pv`TOW}roEpwNe6kiqczbx_Th!Oy_ZS)*bD+Wh%|hk*fnRudNk11MWMfYK5q zmmsxGT2vzV85lqZ4#Ebg;Uxp4lmczcG+<_6*a>R2fiC(2-Ch7r{gA^^VZMdc`LIo8 zAlndw-iQ+kIw1?tK}U8naDrS2-slPs_1+d01y;CiuRwzty-2n}t2^jEi%!VWESS}x zE;Td`pq@Y&J4Z!;9iOrHLHP>O{(@_QnuTO6Xjd!vyb4G-!qW`IiI6!LpU&@)kO7An zH0~f_iR4h2R?y~Da770(5$Zn!&rZnVNFRvFKAo>1uD~=IlAIC7iGtDwDDYth#y}6g zY3Km;Y*;`W`#}t72zhiKhAqek+0a`JN%L^AZqV8Zlp+=;1vL+}T(GwVvNaWEC3s~J zG*k3eYk=~a0(|2y{G68(M9qV=dlwYr&{7_J>LGNv4b2HqQOI^0NKk=%0!?P1bB(~Y z#Xo3xLOkUGb&CduTd}g2B-Pxi7NfF@tntd!^lxRaO zh4v&sDIBVRICPh&*uXO4 zE|9yR=SM?2a}ei)4x#mdP6@)2OT!+OAE12A4<2vd2Vz1OzQRnySQN_NvX&8g(hPX< z5-7Pr4;`y>^b4qcCHKoQ%m-3Tf=&b01qHrih)=I7h!N@mIqxVKG|tob26Th~ zN=*&wl|cs*Ji0+wXEJ~n@VtX+0|z!pE5v*#_nk*K*cPx-coacPf3OQu zssI+7G*tth?1Bt;f$c%8&W88|?iNUPA60{hD{%EhdH8_ZbdXfi3%SGz5$~Xc0h?0> zO^gaaN-t>4fX*$-QGvCHYg8gpQrif#`s zJ~_tYG7Fn{6vBgsCNLicBo-B?7CD=^l4EG)N3QZ^yvEz=I^_0%aqMflpjzU|;~Z9vB!HKzeha z>V%;*XaE5`*aK7N!za+j6v78u@di>4T7d#mimV<~aDv3Z<|3&#VPIf51Cn51U`Pbf zjv%vK_#~Q{-T4%%x%ea;`2-yKINZ5ixcDSoz-&iuh`T^{6@av4g9xZwLGwc(t|f?o zis?Wj2_^;#3s8R*qy$uuGdS@H^f0;bNwhJ$@F_I2xbqn>#c}Z|ID##A;^T1TW&njL z=x%e6o>UM4*25IQ#mC{s&A`9_I=*fS)E@8=bYOW$sF{Tjf4G8;0;>hJ!$HP?cXuKD z?9HdZ?t#6>_lHyj7*^E^IKH${B4%)=eAPq|+p!ib(DPUk=P-I|W0HrI2 zKt2IKJ`M(u9Qc}NEOMZ@s$ha>tOZeS@Njbkg&R{O7oUVXpMVn|hc`Do@E90C`ZhrI z&Bdm#mWxlq6|Bz_S)UFA1H%ibKF~lL1K2)rm_qD}f`k;1qw^p`FFEmafcQzE_?w@8OZ6^ksBNb640;&UFi#sa}0e6OpRFdfzE*i zMH{Gsf8KG&+iBF)9$(2u{7Ze{oEG~Q+ZJ_vQ zW^>_dU}TnN_3;A>!PW@}^ZVd-V=V`5+cr4Z#mC{r%`^#I7&2!t^Km$X>;a{L6(BVX3=E|p%fMme$|upo zj1oqbTzncXNCD!??F$odmYTznQT7zKqpw+{mYLjg1$`68tSWVgA3${iQD+r0QDFfz@= zYMv|DyaQ14Ky?&2tz&Z^*gO}AUnej!wPE$F2RA71=zuC_1_lNvP+D;X#WS-mGZ!C+ zAGaeoY(aHf094IyXgu{WF?Dl+s$B+1-YS5~!^-_$P(JPf)zNJ%Oc7kL+~EYuub_5C z3pB27B85pGD1Tw(eRsYB=BZe+z85!WjnNsXIft2`WeB#gK$Pk3dwdrJ99EH*8>H76By~%$mg&WG1MrS^_l_ z)bWGGF|_s4s`6jS1n=xZe6X5y<P!Y31_p)+ zQ1e$~rd@YXUFiaym`h{3?X0GhP` z#}gv%(b}TWxZl9YY>VAYc$sknYGxr)I70g^?x6NJw3p$;$KeRBM>wG220FDL?1li; zdJZj32k<#Cbz)6@PTb&fGXiQJC?3G(d4byh;5HVx-vlZ;9l;G~M{ZCZ&;eDi3QJdR zp!OdkT_M_kpgLd$C|RL3|J=dmT!5NGNnHZ!??^!7{vA^ILCbz{nG4F)p!(bas%`?3 zyD`!OxXc2V1ulF6%*Q}chgsaaaf90HYxp6F?Ju;g(Zd7|GjQ9P`5_~`6XS!FfI<24 z2~^*IkaleKo-3$L0doV>MXV*U3pWGEPa=FELl_u%P|8eKc;5(-7QpSNK)wbhrckVj z!4;ggQlRGf6AUA8`VQnvV9v%KMxNXtzg_@kP6h@BO8p8lOGXglR~1m70WHmg^D=VW zB``N*cb7Xi$VnMcvp{JcWGX0cCqUyx5G5?#;9&{216*E!ifw%u}piRlTBI0yMV0&3oFf^iP^H@H*x0OW7Xi~+8DKyF+E zH8YbNokj(34 z@t#Q2P^q*#hcafw~?psACkK+ze9~ z7#KL91A#)IvGlW1a28JWBdX{kBl*OKWT)}0=3#fTcNO6PQ#{jomT=)#2;|uLr zDj0ZM%>)`JhCImW5K%sY^E9H|@a1b@W}c19anN=}2h>bK4rDXY+G+?h1Nk;EF}Gkh z6WqQ6h2b5jnfGB~2##~GJKaF}#SPTgL^d;lSq;09kh)0+8c)GUVTe6Fg42)}-vM@T zzDR-UI|D0Q!0j7PP#Fkz2U>W!^G#r44#VCC2bTq)e(DaWnN_g*nQsD9GkY6b4{I+= zA9Ftws0_LTRr7)ydzd2XF>o2=#rJ@Txs?NJst1qTg3L4!g`~^9nDK<>7jPJO^F3f@ zHfFfA!bq|kH3MMHJI`^Xfb()7{rgaU}*rH7SYl-qU?6(+rY^D7ke6T z-@#=G z$V?V!Se`-hOFt8~x)GXYCNMI)VmA}qMgzr91k_AW{J_E!dpZP{6L{OapfR^2(vbWE zo-72<0cCN4W{AA_IKX3+PoVN;@VXr>Z-L8sSI8J(0rOn!&UXg4*9|}xGB7aQ!)q2a zEE*V@Utu>4lpVqSi3X^7y`X>q=X-D+Os;z*gUkpGSqzw7@4!MyANFcg3MEpg@o-Dxcjh$9oRf@`#cmhMuOQ+1)G<`z`zg! zjf=-P+WcTYgUdRwpWXQan3HiCS;EDKwXFrpgL|O%fVR7VoDK>LeEDRsP-BWZ~W`=5XAuykr zp$<%=6U+?t=t5vVGeaYoMkkoTGfwED3=GT+ZJ2@#AaT%ACQK=22GG$c*u;A<1;OTk zj*>@}0uALcA^8_PXAf1v%rF7ULZz4)CZP&IdCcG*43vXJF*8g<;z5`R3=9k)d%=5* z85kJAbKwjO44@NwK;p3dB(Q!u=(t9ZIA|d}$OQ15JOcv*=+tJAIOz5-kT`h$oq>U2 zB_qWA51{f9$$XF+W(M#~0f>o$nHfMcuqZ-c4l@IIz8%a)CYTvuDEC^Pr!H(dIeZL!W?LmgMo(?WX>A!oF_;ncchBnwen_oQ=$2 zX4r?!g|nF%4#L^U3}%MI$Xqy^nE{qd;6h*qGXvyMRxk&NU}iXp#6vKd8BQZONGxWC zvq(GylbHdu;sC*iv6xX}111W}M^_OXBo;FRXqF900Lo-$xD92YQp^nZPz9hoW(Ls7 zYfugn#mw*oiHBe^Gk^|wLhxZMW`&e9OBM6#NBX+gN_G5xDUo+W&qs<1mi*I zYH++%GcHZ!@&VD z2ew`j)P@GBRfLLz+GQXHGf{MdZG)(+4R2){Kz{LMR#X*bcK}NyEB{`w~1qmXVZw3{Ise{pBP;uCL zSeSSrR2*~#FvuvFIEc;60J`N0#6sY1sCwAiK2-I=(9l7s2eFtLLUD+P;}DO;As&rG z9JHGaWD_c8W{Ah3J{gBNsMU>X28hSZkd8xrCJymz9OAhc;!8L|;>^bcsaP84La)r#6#dUU~wOqv2ck^VDTB?_0e!a1_p*5 zU~yP(M9Ay~i#H<#psYh+@k9*sPk_afFvQP+#q}A%d*z^JfT$~AanSL`ARYqW1dD_2 z2||d0Sogry_&a&?yL*FasA<9K6K~F3P|l02T+Gsf#4Yz`!5|7Qc%s$iToL z0~Uvs!U$<4s5o>u3@)Jo6-W1%9#mWtt`fp9fr`V@Jw%j&!3r$?7_#;qCdk0R-~bgz z5&|>9lSK@V8KBD%!D1l72do}+yf27{z(G)PXtsb$M1aM?JG9_pAVwTi9J;g(Bm~AO zP;oE?7J(31U;)rd76>0k7C^;a~nVF6hDBb*OoEQ5-po3jQg4qBHCQwyRu zLB-L-VFy^84I^Lg1B>%xh#!H9qsPlBs5oe@8)P30UjU24cA>yT85pjC#X*OWBg8b#PJwEbhbzYd69qfr^{K1faANR2;qB@PLXVwHZl%@ii3k2Ng@g?4q7peBnVoo0~Oap6=q0-ile(f2PzKRvjfvs1Qid02|(!z zsCW{T52Na!;^;duTcF~gJr6LoAi4`Gjy|$G0V<9@aybnuju?RhnZm#@2P(c7!iAHI zpyHtMUAQ0v1H%faIOz0!Wbt)SarBa73s@Yq3L0581H&$`xGy8<{BLBL15k1Ff&ODq zarAt81}qLb4+z;528K&uapX}+i2MzxIC{Ns4=RpcFF%2bqo<$OP;uxoJc!{83=E&3 z;@WT#2;(PI9K5?5A_O79YaQz_@)0{&+y`_97epPDRtx$3F7IY6(d>cp+5}phdN6&Y&pyKEwy9=S>=aI|+F;_sv?|?W+cs*1c zbdWugFvB*eIQj_aUZ^-?L=&Rx2vi(>#PKv#oDnVMUV@6FkMP}uiu0kVe*hInA8C6I z6-OUYdj}PVjWa-8$-wXxDvn+=|AC6b_MpPlGlMgV4z4gz)pa~X7&vgt8 zj$mn^xBAlfgjv((}x)gr&GY< z=&e8ohMiz>W4JmP;|o|Ev`QK#0--&?4J(Y&ieWQY+zO%yiM#?9_e2tbFu#Dsy&xPU zQVG1S6Ev%hB*?(PU<($HMHOUVU^oO82dxA^l`;`xU{FGu&xLl68T`TGi1}Pt3}u7G z5w$5yybmmnn9qf^%N&J4`xihbL_+KZdxwF6VV*F^Uc@{vEJpW&)z5^da#*|grZ8mB zG{h7H`4)#cJR%_T5%a|`_h^e?H^&&P9x;y$bC0(O$o?OAoMIg2bc4ka^U*N( zEXHBZDzJLQd^Bv2_-h>MKZ4bRRxCln2G-6xA_{W@vW58)6$sR+s!;MH9qXMoR@05O=9 zK<+`zkHg|!28XyASR65L4&K|$z`zisgx#IlN+5gN;Q0|Y57K}`eGk}t#QZyKJZT?}F7M=H}x%P|vIaG9NL&58n68z`)?Fg55nOVD*T3e^^iTCl2)rs@Tmb#vy(jhd7TK$eoDR zCv5(wObxsFd%)@u>kYtroEaDxuHz8@1QtiELjdo0W?*2jQ^#(8yE@1{i1i7u^5-g8 z9F}_+7(jc|K^!i1iGhJ;@+* zuHZ07NejFA7C6KMafqkm5U_x280PTwg zg~L~{IAWa!tmki}gWY^@9gsPQ^&6nQ&meQEaj4&gL;M>Kab;cX_L|@jFUBE06NmU3 zU6A_`>r6oVtU>O-2Np;4vOs&KLE_wcAoYlKCZPS!An^ry*xh*_tRAtR1hnrMq@F_` zWDa6|2y_`1!$Gh(qPGTH(IsGj-TVLpkU5BTBd~P^^Kgj20gJ;*J5bpUat#B6qanx~ zOz~-8al|?k=n`&**Eqx-j6mkVW{V+vfoW;p!Ju=^_lhj<*=99S!cfdRCa7i8}OGX{o* z471_&HLUGdY7Vj&u?`2kSC@f-VHytc?O<`lr~z!eFv0?44q|-{XumDU-o+N!-Tx4W zxUMC3^)5KXBP>DoB1S9xp#zL>!QzPZKQMRpT7lFfMlry9WkKs5tU=<4^*o?Gt|0f% zwZ`tAmtggXbw03q?Ys@h9K<>w&>mEfIpww>al|?w&|XrI_+79#Vx13YKPX7N#|{)< zb1~xUqCH4_K8CoEBX)P{I)dy)tQP|94+WVY2Np++!hrU9g2Z1rfz%_`3xW4>f!2jO zV>f?=Ge|vR9T9kM5d#B5vJxJ(M7K{={KEqbqiM zRdI;hxq{q-X?_k^9I>tmwAT`3?**_pVqFtx-y}%f+YP(Dy>1}$5$l~mdm=&V|AWO5 z>zzRR8bRXv?jZGu^-iGui6HR;ckJeG#3B9(hq$5#c5^~-h)={JegKE~Cl8SO5$mZS z^L7jj0iK|Ay9l0cVg2G_u=rxQIBb4wiYIn=Uc({&8;3YQs2>U~6F}hz!!jUo7zc^g z#362rL%auv_+1?0y56AhL9BxU?Y#t9?}0-+87z)i2L;QIWbHoEd z<|Ec$f%eaV#1{vF#1ZSSVE*+F28koqQ-SxYF)%PRg@D8n>#4x|&KMXNHiUx25$mbI z`^Oj<7@mfK#1ZSMU?T8IdMfaKE(Qh$$4Kn{ZHxq|N362~?biaipDhZzcsE!a zvHl8HBVLZeZazme$Q;DFEYSWckoi@(#JLz4gcuO(wLp8PKN!l49*`W_tO zOK^za1DVgz3O64-j1Ri!3x|4{IPCt?i38#nI)-3i6!|(@g<4r2-|{73UaVH6mmi{ z?sJbr;zJDLLk#0xUHyYC;)A?{E#i?4HA&4&!D_B+P;iN%F(j<=i%W`96LUSmX1Rg_ zgpxo=40iPoHbHU)ZpY(1ks3W9y`dp#K}1OU1(#UF2PMUq6s4w;kRXCfObQY+i#)+; zqQuZ7-Y2uT1RhzQh-0bY=We^Yx(1gR8pH>u=A@=L6x8S^fP;=IM-OsmOuso3^qVt^-{428o2R6fBxdFmn-rxM z6nT=7Zb3=HJU+-f1UdQB(0IM%{G1f>$|`3goSDNY-nGot732$W35i@hl5dxBysK+~ zcQRHJ;USb$>>3oD4?4s?9+AxusgUl6ulsq!j)zaq@eBs#8JEOhC*;UAGJx#K{zV2Z3uD!kIos20^X?{_#Qn{vq*ho_;Rz0gfRa z!JsrnhJmoO?_+4`;_BuY>Jt+0;vEzp<{A|2>F>u7ALV0Y2$OJjboOwK4-Rz#SqPRg zfk`Ll6?dLC(k$MsQd7csj+S=|Yu6*J+02ig+ykg9n;ZsHcw$iluN5xHyJ5BFh+B zx_AdUhQtTEhJ<+fxd+F)dHT45;*~ZD6V!IW+Rg(NGOpNCtdF5F#Dz%7!_WXCoo+M zWoQf*2Wv9~n`Q{sXb9G12+;*L#R#m+2yB88SeFsl1S7CsBd}g0uwEmuUL%MuunERs zUB+OQ#$c7kV7U|WpA<{N|cnt=71fYqCTWlg}cCScP{z^0ji%`pL+ zU;;MH6s*z|q8DtADcA&4ur5=uE>o~MreIxWVD)BTSu?P>8Cb6wL>I(NusLQB5-ef{ z)@u$?2{zLV>=JV@+Z-YbR%s5_WdT-c0k+EmY_bK|E(@@|7GPZ#U=u9BdM&_uEx>v$ z!FnyhdM&}aEWsw2gVkGtO|S&(vIOh01nV+10BbWe0P8a}0BbQc0P8n20BbTd0NZP5 z05-_b0BnY#0oV{j1BfZGgaa`JnslIP#}Hx)H1$A}4>bK4LQH|CBS_*ggrploNFp+X zq#r{_0y2c8AVWwJGK8cdLnDYIAgRa@l0*z4Daa6#R16_$%Mg;d3?b>t5R#+}A?eEy zlAH`7>B$h1lnhObAf*h}OLbgKUCW@-D0lQA#F1)ELj#=kbE0RkQM{`wOq-#BS8;xx zM`}(%Y7tBf+_-fs%>&=V6Q7h=oC=e{QnSINs8cv1Ofxi!4+FOXzz!g*{R(ReAQ@^< znwMEvni^kF0&ZR43@1}?kI6LNGq)he)i2mM-q0A#j!#L=Ni9h&LIfb5#*nkAr=v-H zaxkbv3u=J+1slejL0VIwG8(m^gVQPCju$A(oJ~P}Au~`Jotc=ES(RE8pOXpds2RmW zdjHVmfh+EvP00&IT+W9#bkTb@Na2kdiMhdvp1H_D2TQWS@t#mQP@I7*bT)O(4e|~) z1dRe1#e;l?CG9yw^90-_@OHMdsi#k_k*k+au7Rsht|7Fqg|(W+xJSy>Ke)s+v8X7q z64a862#E)GjmbBPi{gt@3rj&=JkMOOh~k0}gLqe0aBRXIfgT*rrZl+f2^1pU z!6l~2C6xuKp2@BjDf#i`nJKAxuE|g-P}3W6m6u6*Mq&x11o6gkZ5NUfP+vA4UIJt! z=B4DM7J0e_ml!AJRf2jnWL(RIWzYfnvaeu^cvn!f-5}mKJ~uHhF+H^iG^}G8@0eE^ zpORRT7~~!78XsI@Xc6xVk&e$V01ZB6=I1fQM};8uwBe}$*?clx9S@FM93kdn1P;-V zFdXurmcYcRS)VwVY@fY#Sm;9PH6+MbV^P@SuVt6)F_6U4t5Pn6#-Ff z0lKLTbgLUw9mpCKWk}Yeii7OUP0dZt1&>cc5`m#PJQ_e5qbM&i$1};*GCmj@d9HrJ z@y7A~1+D?!!SMlp!SN>Xjz#I9zzp$Bf;h;~97_@_BQu`x_ojnQ<}!ft zOhF~Mdu3=DA77GDlwTg7lb@cM9G_ZLlwTC!oy-s)UtE%yoE@K>ksY6wn3)5~8su0E z8gI-?0S!w*N{4*og3=O5Z4jJqnwC>qoB=LBKobn`YQxYt-WO7D#Dm%uUxt>;Y2g1sd-xF~nBSgIW=;uC9hA@$qGu z#hE4XnR#XT*{QCe@r{6Z2A6QXqSQ3K`1tgSiui)mqT>9##GK5M%J?$q)XRtsHgLlW zSFpuLk=g==)m)$!46ar#q~(s*Tu;t%4e$##iibAnA(;%;_ykpixJ-jLzG0OkN`DDd z{pY6U7N?egOhl1FRON%TmIIYl&}1Cs9bAHFX9b&sNW@_K!rOl4psCB!+*D6L z%lP>8yi)KjvgYyedHF@Ti8+Y5umG~EW%v*^sQ5_q40Z#RAg->iA@RXJV1#4t7E~sI zM&W~f;$7oW%OPy#AK2XB5O8r84zU7nF@+<)1;qy&f;&;cB}S&mMLVp-jZaR@$$^&f zq}Dy)=2A*#aY24@DyaSl%_|3uod=~Bm*%E|@&#xLll*F9H16HXf{BTH15hUyv#f>3 zJ*b$&Ru)0p^JF%=iR;wiE^916WsM)i2}oUv)QXZ+aF>Fd%t=%)B(EION+P)uR=DQo<|Z=~mlWlsLi?e?B%2B97J;J21koV^kGg^C7jP|Uh%N)EUO+1` zkh3%F-tIC6(52al@rgM(`N@eTsqye0D7dGLam_bGHMo5W$*`bqzA3cT1a7|?nIqeS zcHcLs;0OUtz+&svf((QYjlfH1LyOGf_>|P-Oi)>z171av0~*~Ta)burCKH&O@=HtN z^V8ys67$kiVJ#DLFqk zH!&|IzO*}$QxKj)QpVcbMg~YK(j-j>D>6V zqWoOYU@3uF-vIAqa&juj5qQQ=6N5oPX9zALEI`B5Zkai$hTyP(+yd`PUa19X;eaw6 zu4W&oz=HOtK)q_n$|8uJxL09;d}C+;awB9o9lS~^H?br>Ek7p(G;j#Mxt>5sf(^l( zhBq>V#tYaC)Mz2K!UlB_gH6GqN_tTR4w>TO%=A1^+?aq(!IF+(Ep=>Cu(FF9Ys7*r z!7d=(AK+F?Q7U+afNO4UfOj&eKA?QzT7Y-3X*_848Ym*+#RQ_kX7edak*k!Cz30N=!~J%`MGIEFs+f^(H6hB4&F)3jz~8gU!LM z(_nMZ0!B=48(VNS7G8@6zL2r1#-X(T@8~n5{u$XiV`zR zianD-nF3=$XL3lqYp`iNtg=MP@}|fZCzYmQ>!$`Mf{ZmTE-9kS-O%907G@?!Si=mG z)8h+@^2;()Qd5uv4_gW|ff$mPSd?B2ZPAn^=47TMmSpDVA!`oK2bIOpo_Q`P$nqhj z2o_TfO+XEZ(&9u=`=~T02fm&O)E*2YI}$f&VcJ3@S1l> z-9c)z&K%TVD=JHM1vO+qnS~0AC}AlcQQaeFIU>^mcnlS^Bomr%K@D%zbpaF^is&R$ z(NIY31ac`ASBxNBN<~AVF2&N&HnfEF83w*12N{!xR{7vS#j!jIJh)O^kds*wpPXAz zQVgrBaW0O5n;hgF3?AXcXL?E)sLulFPl6iBI2_?@L}=L#PUkoq64FZ2q=T~&Xov#u zil6x8ip2P&)O1i|Iem$6OY7$ML7 zdeU)**BCq{0@@n`+4%#i`;caMy-=rCTtO`v(C|2DeF|iv8r;}`2R?dJ1Xl0iRsbz_ zy+M;3&_OrQ2q=-`m$clU1!;DHHadV}9?@1s_hV)SC}R`pV31Lyw*bNYUC_`eWDwgB zY3&18ikx~M;u1q-v!Lw?aF-WZ9HJDdw1Z~?Qd=&dsfqZaRPcB@Y%grlX zXoeBA`Uo^W0^WE6aTI(+c2Fi7>NNMT1{!1=4(UOLI~^Mt6o7WPNDFETnmhQ{C#ue8jfV$j?KXv{Si)G!BCUxRIM&H(IG@PH(? zK{-#*x@FG*&_Exgz%2`jcMZ(}57T)=hv`6rbYAhnzR+Y?Rwtl(IwT&nT)_>r zgb{1GZw_1SO1Q2c%+vC&;E@c_YGP2G9}*wz4MsSYWPsANp`jyqvx8$nK~5!F;{ofs z43Oc$f#606Xni=y9<;Uvs9}J)>H)REG`s>4ysiaQAP^mZ!QcQ4gAO@i1R&bTwzDCq z6b0ocME!&%*TN_wcAaG2D zLSl-XB}f7B!G_>TaBy5u)?z05OaLR$S`Em+ENJ~&JZ$q%K4@n)cm@<@(mW*% z6k#+kqV2tcZq0#pia^UpQ1)iQ;&yagnIT#aK|X^3KFJknx8*Z{i`czPr!wJbHSIHM#r zGcP_Rv$!NNFPW4xH(Wv1gv19!mNdbueDrRYp=Cj0QE_TKczy@Ab%L6$)!-5%OL($? zOb^9_mZB7;CMD*8{FDSbw*#Jv5lcdX4dR1>!Gry{9dCeeJT={nm><9hE@T@s1H7Tr zf4Bxg@D2ZgDrwjV3387BItc_?>k2yY0CIc`p@~cK4S@Dm(Ohbgm{gpfQwrKS;O!S2 z59_Hy4pjgZJfL+vxR$FJnr0*x#}_0PrRJ5ygNAz{C`!#qEXgcO1JrV$Q8$4PFH_j4dTv|?kBKZb_ z4|IVW2oA-h{Cv=HRpi8MkT-bm7?z~t44quTCIzpT;DsLbMqNO45{*v%A>4YQLR$*F z*BkY8C|Y`nk|vFFJoqpSP`<)lK^Z5eKvypo6@zz>A{w304uBzK&InQOnaBIaXXNK+ zy9NX!6jRnh#S*HBDh@sf0NHRv%$ZvQl@us*G$oPkNK9m#Wag!$R)CsP;6XoEY{4EJ zj}+eEC1i$1@$s;g(x4N%NFUdBbqy#3EvyAClLoDz@dPzOLxRaE(LgK5p&M&)4{?HO zFS4e#z#CFMEJ&oMv25$?;J9I|w$Qkxgl+liRCG|V* z2B7va=Kc}njyvt9Qb2VM@~R@(Dr?9YNF+}eK=wJ6=7HN)sVVU}nR%&+MX;G0Li07` zIxb0!b>P;6QYl;FpWn( zr@||qsBnhW zP0UWEdyox{;0lNjLd}dNMfsq77@w1$Pu~jez&h;U3KjHUqT`{0z}egAHLC8n|Q^xmJ`EB_@~PumKdp$jV?^Ekja^ zOTb4~;?amu1k+{_P?QSx5*}S}HDFD!!#Scr%YzU{F@f9_TmoO(Z{nGk3GxD{BL_;j zuqFRsaj-eyB}}9yKd8=-U{G%gJgt#e84o&x3Dj#0^D{I6?Yyl>Ov)@XG%|>fFV2il z&PgmTjt3p;6`z@xmJeE{268z3@FtK(kZCx!+J*#U>9SMn7_1Of7lTfI!RFjxq?Rp4 zE;gY-o`SY&!5gAN2F!MYcm{dsy#Szl--8$#82pj$~`;;uk=HU?U#38;Ghxl0>;-7Jdi$Sjh2T3El#{`FX2o7;&=oRAV z=Gfs7kHjHfi$i=a4)Mb{#Gm01XJJRgJFan&D>%fz;1JJ*UaSamKj;=5SbjW#LtKsvd$^h65N|{hM^67&ki;vH(!V7)!hGcX z7>Xp0oF9{s#F5Rv=u52QV+V-_%EcG{Qm$d4pM&*$(^wKwm{;C zki>r>ssD#0&JVqa9i$#~D-tZ6b&KuSnv^ z=7{hi>_rY|O(bz-_1;M0$o6I+i8CSDTZ<%)Y|bnsab$DWA&DcaKaC`gte&4A;eO|=+=0}CZVQ9OV=pw{fy`G!GJhtT zI7lDJ<;S4r!_=Px2{JG+TtX9v-IRL|P5c;C{VO!_Z&2}XIK-Kt7iYrkHG$Um5@_NQ zP;nJBaoCNl2591JQ1v!w;xPAkpozoGffoOuq|dMdDcq37LARd6!dV*XKal%Dw-Um{ zk=284C4^=-252yV+b5n#@rz5nFw}fdJRz%x-SY?%M^1;x=74Su#AdHQ4ttT+BioCt z9+$l^dqCj;$|A6ENQSx}Bp!lfFH{&D&Y&V80xAIV4~Pj;4-!uSaTpNyn!&_9pyJ5( zg48=h#i7v)H{Sp%jvQZMNbW%vk3bUFgX#mh3%MMC*$)y&4*xtP^~mBTIK&-sh$kV5 zXCb*~0+Kkg`7rl`+>?u>9@(A9?dByMtlz z4$3FQ}{rNrBvnZ0~xIAk<&T_S!(jLE#3%IZ!?S6f^U0ejD7>mCGq2eI-BlnNOpyD8NklS6k zNaD!ty}d}{$o_)WKOl4VBZUL(es+*Jvio865=b1`zt51&M>Yp`A2dikvN^E&0VIxW z4y=9vi6ff>t7kys$mZ}t>mQIfvU*rO1`#F5n__pg!F!|F+pdSrLnA=!(p z9(DsRNPR6*cm_h%gW_=&Qhf)C3sBI3)XO5ZqhL3NYB4Y{+(t47R7Qc+gUq>uBo1;L zNE~Di=(bB(ItTSZVB$4M>S6bFg48cW5}yurCrJDnk~r+(A-)$$d@_>x zN0G#l?LCVm4)P<+U!X97`RfFdIj@n_w*vv4p78G z#gWYsKoUnbM*>M4*&GEVab$Beki?PAF+dVWHm3rqA8G|kjG#i3fq`KQ4sqD{Hb|*1 zQa&<+>H}GW++GTWii6aHFs$9x2^9yaM|S69s5nS1=+P^*ge^7C_Ab znUAaOf48y&&-?AP!o82PAF*6^FIcVCs9I;>i6Skop}^aZsNK z#01%cT#muobs%#BkjfcYKLR9Pha|2FG6Y(VA@>tOaRHJ7nU7p<5MwW>O#%yNWP6)% z*o)kc#%1q!=y)~A{cDlZ$v-6Vbx7i@NaMyWNcQqW#nH_XLlQ?eM;0m$3I}9!RG{MM z=4c~{Bb#Fc6-PJ65-N^vjsuc7vN`ThaddOEL6HS52ilPQ8;c|kx(gl_FR=bM$Qy1QiFF(~G1Y*8c^G_aTWdL{g8O-`_*UL1u$6 zto#u`azC$nAXO^2!lOJ+e4xj0j{k$eqaL5^{eK)W(LH?+H?jB^;3Z zp~&Ho3RMp>A9Tw&%$z19ab$m;g^Gj10EA)Ta04oiZVqxfK{n?hZ+BZ(uc|A-`xtezRE zU5Bh5)@}!dGqQSfB=yMRexSgFh7a=mJ97JEDpENnhNK>Oo=yWv99ccATm^Y!15$lz z3snyi--sk0f+P--gO#`F<**D$l7WGt5~?2Ezf+LJXCS$s2bxYm+Cdm*jtW#9-5g`6 zI7n?Uk~vqQ;vn_Ny%@+LPH?^WqQ}#UU<>Bo3;(Vd18Z zB#vypK9V?czBWe^M^+B#QY7`&NaD!pxfw|u*y5h@OHCvtj2F8`6!+a9QTP&go)k37GF z952Z2`DIA%zk*~AG2!flq#ik(eW2nX_wPh1Phj&tAa^2%a~xDXNE|twk>^8^!x_1L zM-JykBy*6%p#v(89?tzxagaNa!+APX9ONG4aNdO^j%@xRByr?$K7}NX9L|@J#F4|< z2uU0{JtNPzB8M}qp9OM1$ZfFn9FJrUayY}n0pu^x90yE2tRDd~XE#!OA%_F9IiR&q zAS=+#0gah}#6jkO(j?4$P~8L)2dPIk=R8OdTK*ur=O$DfWDaPK4`vSXJRPz*uc7Ke z<|C({-$>%f=?8gS4mtfGkINy)uPC&BM^8U8P;rnuk<$-yyAe74SVPr=+=(2Iu1Mm@ z;Q(4Y0rCRK{C!CAf;?V<91ftla*%qE`N-yUBAJiuFHj#GrXD%ng4!f7apZIhQUeo5 zPPfSAEw*$EazAo=5;@(1R^WOJ@U#X%GZ!`%4+#DV&EKT`bu zfQp0MiEKU>Qaz3=o`)ok+|O!55=VAVFH{_4&1yyl2H1G+9whNKj0_C0@#05NagckE z&3OqG2br@LN&P>lI7t0Er1}Nc-Tp+qu=WE?J#0Kh z4^6!aNHGHggD09e%>4mq;xPYaBZ+T7a(@d{97JtIa{q3S0MwlakmBnwk~qk%u=IQx zN&Fy^`rA-(5QUt7k=Id!@+K_Z+Cj&kLF$p)fr&`s$oV=Ghj=lPIC8$OMiNKP*R4q6 z$mVarA-)TTxEnNnK<-B_AJF^nuzZ2Mt_C?AKz$RCQJ^pe)w!_n0hNs)agh1Q`2u;K z1X&zbFM!MeVVJ#g&~gAIb{HwX)S%+%=7Z`Qn7zpP4%C-~i6iHiO-SY-i^ImXK=vZ% z$45~0AaUgU$O;mGmOsemAkX_F=SMjt^~m{A6)Fy*K=}^jKajh1KmyQo4ibmuM;A14 zSbp?I6NlwT*gQT+8e|SEKc<5Okj#hW#~LJY2|H3bhAb`v6$fcU&etkXagaI4`Pv6b963FQA&DdB>jETkhZ6fdsMS3)uQAbbC3W`3qz|vN_1}M9AV6 zIMjRN5C`c6ISFL%QKa$&v}O+^j&3g~ZGgl<>OpIwVgB8X!+hj*L?F9h>Te>cN1o?; z3l#^Mk32r}6)KMI9$3Bxi6fV9u<>w^ImqQzHAn!OPLRv1c~EhXImqP|Y&;w!ja*(K zj|U=`SFrIPka|#g0x}O2Ua;|Vm^iGwf{o|E#9`$X@^}u&99Vhv6QmI8evmkNkI3ogAt=(I;f$PqVEr;sI3uSY zWu)|poPJ>QbRhM}>BkaDJ#zYSfQp0EgW?h7Kaf-0(Zpft2ejrHBo9*$OFyY->S5`p z3QZiAen4Y%$mYP(&lDu}$mwSlR2<|!&PbA98xLMluIEy%AH797ie-an&Pjpg@DVA9;QsG}Zx<0$Gn-kATdC ziG$=|;eb4Dum!0-k37zgoNkflk&(lJ0UFMrctI9dMG{9IXYfT5N1ktjt#<{PgPfj` z>jh+UKx;lh{sO5-b|+|z8YYfx&JC!&pfCW139OuX02N0!=N%4lHjn|(@ZX9QZb?Yu z$nJry&jd*$+gk||fSQA>z8!}+Y#ssKoyhY7$m=>zLCpbC$n$8h`BRWM2*c9DI}iuz z9^~`@E9cSe<-k#X3g8g8gNlQ!K~A4;P;rp?$n8Vqb|7;26hhU5%s~lHs5rYp} zJt49=Qc(3Eb3kLNu=Fes6$eqs;pqYrfYvXkk?i$>ii0R*d*eX@Slp8d6$jai+#f{V ze~oN!6_R?;7(2|JO;B+Vg>3H}kO0(PuC}eZ~g9M=A zfLuR{AobIc>qlv*ILKb)`cVl@99BQtqKU)mM;A14Sp67}CJw6~)6m3W^IXKsOeG#F5(@{7`Xp^CghPk7E;>hbHk<$rm z{0S5epfM|$`a&dgkkupaUqjCCpt&267LYj?k;*+#*#!~@xf9u(uOLBa`QVPE9=4tk zWDasU25aYl#F5*d$mrgMU~hz4l@U(-iN9O#UpaP{}@Re zG{*-kXOQ>DA@_fg`!&evL=EI2XuKoW3wlW6$mzrkNgO#{L7N-k{Tg0Km*%4o`u>AnhSurKOIRNdA_m?hj=$s9ONwIb#AcrZyPyiXa$ zzewsqX#i#pu6^0!IMgHW??7Is>I+p5az6;e`fJGRLy*^#!`6+1)PgWXFBpk;4r+KO&1G*MlH` z!P*C)F$9p+Aon1vM;-@2PS2pU1XGW^-wG5aFmdE~KZBHyki}u+2_Sos#gWGokkbih zPY}#}#somg2fl|zHgA*VCf1u-jTx@wyz_;B#2RWUC)~v$JnGJFbG`^6} ztAUlzATvN17Vn@wCP)j&zsT_j+vf!mM|Kaa9R(6cR?mwRp2+bfk0g$)9(mjnS$ztU zdgS<>h9r(0FY}PZk>edyrosG$tR7Ssz{HW`5wsT-CXQ?l^7;zo_!R;vhK4h8`3Bo> z1qx#jhQ&K_J&PRg$n9$6a7J!FBfAHAUkS3mkk1W3_7`mZ2`Ijh_x-`z)gU*5Ff3gm zryt~W1v^gwq!zSx4wl|-BZUKUdHV-R9NC>LNb!Zd?^_y4966o9>Sd7ok<$tCxp~O@ zqmkDOA*%e409UyW% zMk1+44jU!T^T=T9IYD9|49nNqNaiDl1Fm}H4OBhI3=oEygB)MT z=5Ryf3#1lQhQq>511b)3KXQ7*wSEbCejgM^Fmqu0^g-qz+p7q&5E}l-@i@}?)lD38O!KL~0LDEyJtBbQ6a;;{XXpy;`dWG}2-K{p3B zzXnnd!mx7~koONF&kMlzvw+khpPzudP8hl0fxO=kIe#I~vxC;O!2AnpLxQ{vGXE0N z_&;dv4M-g1e&qFy$n$;3=05@{hNe$Y9RxG~6_Pk|x0Zt4)w5d0Aw%nz7Npac$hiJ;>hL9btM1J11W}vC-Qt8Xe<{b1qw?LhSkf+^P8Z) z11#Smj}L&bFmceD7MS}%Z48(=vO8h@7myo480Jpo_(HZ9Htq*<53)PiL7JiAjI5p?hd6S* zj9h-IL)C*Q&^d~*@eNCm0CYSDw3iv?FGr|2$UUI8JxtsONgVlHmk=azWOv5k5Ko4R zgVwQw&KiQ558KBIk_PRig^3q|1fb!7T+Wvxi6fUw{Yc`-?m<3p2U#4~c{|II%t5Xf zVC(uo;e%|>Z6x)`;*XKUL1V};f4xQ$M>d}gX*>|w9OV5GAg!?c0vp!?xd*wNK`u9t z+k2q1SV8F)WCm!D1I#@vAOUDNBli~ski?Pu1@cJZ$nI1@5=U;gn<9xLyVDs-9J#-M zyzUD*d`K|DuNv^13zT@R5eP2Sg!tkQ~e$0}uyVo*=8YfQp06M@}cW&gsfQQjhF@*gju$bCB2X zf!cmBcdmh&1EN5EVVF4bd0C(_UYPhUkV2^Y?;y344wb~zWn^=ffD}Ugi@ZM$majqfB8SfwB=yMRdvJ&!!6AMIhxip7 z;;?!j)Sdy2fy2V*IaED}0=4a7;;`}(hY*KmiF&C&=Yt z2$DFm`WPf}WcA4N6v*upQBVXz%|~u0z}m4OY2TLg)N#x!8!bszy~I3SB7pUZ(Pj(mk5#|Np)!Y z0a*`Piwkp)5mX%H-xo;!f}IbEp06FC>Otlp=W7qBILI92e4T(K4q6iev-b&-II{b> zK?Yz6A444Cfk@)W=_(mX9620{pyD9+Blibk`wck$j z$o6I3nUywVI%MIl9*vRD`FDL+@;e(vsVErSIG-z)HEPP=71(5m3<>4Eo zehR3K1XGVZeuZp42gqQky`Vh~F!jj&Q)GXE$|9J*Kx?jG>a#$CP;-#$Q`ovSkUNpZ zk;el;ZibnIJl>A19yUG9M@|o*HCizDd_pQeL1%2j#6f#TVD^H}PKSwu z+Q2Yz&{_Q;agf_VePNh5@;DxH`T^w;ka|!!AlI9qvJ@u%9?3nRu}7FVa=nS1{*miP zYKpg z1vEAeQ;)n}1$mzZ^7-)hkm9!(DPEo;i6fu8j@*xi?JoxT7damx?;iwt5#}D`{kh2X z0v}R64%#yXQ?CRS2blqydxD80pGS>cpPE9|gWQ8$KO&#w1WNNTbKH^CBa8b%#nJ1* zP^dV_J)klKW=IXqW_42HH7KtE1bQJ8vJr1}fA*9<1^iX{FMDc;MF#F6vG930}uaEQOfAufQl&Kx$5PuC72Zap?!}^B;(D^P<_#mfqGbC|jdn1v=k^S2P6$hCO!mw~#0u=|DkF0(j zk~nfXuoWr}G6T7M-USs0nS)%OTtpH_E>~|OiSI#*uct`j$ocdwk~nfX^8-m7IsG#r z-5-bC{^3FrM^YpNwYw1A6LF$qF9p*^l$o{oQ5=Zv0 zCl2uds5p8!ghRza?m-TRc&IqYJ;>oO2T2?`92P^xLFRz&e1V0-I;c3v9OVARR;W0- zd-g!ZLFOR4=Ll3BWDc@>&LN2-yXPuY9Apl%dmcc=LFOR4=Q&gy-97K1;vjR7-SZ79 z4l)PXJu=X9tU=<)?#YFUgUmthx7H(xKSxRr?ND)$Imqc}8dMx)&I=^<3!&m5^~mXG z50W_Yxab9_ILI92ba(?Qj&9ClByr?)_!>zZIURn*A^sPKI4jb9j>zWl;t&^silfJu zG*leqFXZ@AhKhsyg&bd|NaD!xWe*hxnS)#|c|pZN<{-xl^1YeJ;S-Cb9@$?hP;qqk zXG6t7_9DB#7%C337uo$2ki?PAUx+0B4XK{mizE(OGXTq{kC4QX&3S`E{0k28KRCo$ zpc@uI?ngG?7}R)%w&y{24a3}nd|w!HzY=st4M+>foE1p^0_}~3iG$XB!OQ{e;ev@H zn}a-mx*W+IPf)-^-Gkg7MxIAN&M(OOxRLj*JcOD9qFy59)0ZFtsQJk2E`p%#Qjoup z#gWgkL2l9}8`-g4_dII|nmA2`UaU4!NBMJEsd>eI5?=$me$hVo6iFO8+>rPG zB8#izP_K_e9M^tfdmQTBpyKH1(-$fZ@-K4w426n=!VNin!uo?Cab)+;L{g6|z8Hu2 zY8>L5aft86A$}N19624HMiNI(=g8+9Baa&(uVX~s_W_&72Zav^!}`~twjZosLmoE} zLmEdyF8`6w-9i@6hN=gdjodE=jcLQoM=ozcYw}^@$mJ*U_#|?F5EQ2{^~m7>T7wM} zNA7Qe_JqR3k>e5hen8~@IP(2~$o+BT`W@L`&>C!*`N;iK&|YbnIP$u8;ESq*^3-*ptK5857Gl_3xfEdvK>T&{EO^GnS<<35(k-sT)rXiLqRrQ6J!9i9fcfj$mdES ztG7i`4_bQXG+@gZ3K3#6fqRfUE|E8}fcG(Agj`apdw1lxIQWAoD>@T~HYT z;)B-6foPaGXip=EkL%tj*!@Q!^&mAc_aN_Mnt;@fMZOma**&1KWsp4}b3nKT+FydL z>jsH|Fl<~JWF|~KXe~O-UQinVBn}D(P+EnF!_qTI9NAvb-J>w|$l(U+6T!rh)r01A zK;j^`fWi&7KN(c!AdAD+v%=POgVcjC%>A(YI6z{cy}dAZYJdcw=^5GmZb;(D?t!IG zkTl3WuzU?$zYP-yl?5R8A)k*5l7qRY0>pu)+fPXSvRbG(DBQY{;t}~C7G(D4AmMRU~oHUDYu6AfNAz>>lLxV94bvY@H0qY><(#bMRs3alyo4=iomCc@#_d zAg}BAjuc-ENc}rd83J>s9FjP4_^3j~VfMoI+3KK)!^%74emY1GEPQg1)Pv3dgxL$* zF9q@jvU`xvp+a`gLL_rQ;R7qLSD=Z5#@s>a{5+C4vU?sPiG$igF!y|bile)S58D3% zi6gs56eQ7dd>gki?PQQwS9Y znFDeU?EH`lG;!GZA>BygAU!bmz|PSEiGj}ahK0`psCsnw>_ZYqcF!fKILI8(-Yb|n z&v1zU#39ZN?Kh#DBacH|4M`jn4mF^}z`($uizW`+|LK4v4zdFl4uMGGptKKjKk~dJ za=tEyst1J+ayZmM#X)9++%pI2o>nyRB~bAhNa7$pF!!uP5(n)8gt=!UR2*b4vU_$S zi6fUY2chC1vq5J#!_0XI6$hCE+N%W<7e|`sLiU$A4)Jgt;w3o5>yX5e-HAL8h}_QH zjies5h6?7+Q&4e`zd-Fq*tt4ak;Fk~x5CulK@tb4hXy~xYb0?{Ul^wT6OuScJ#1g} zPc(5@eZc^o4}!S|W)3@=I8-}>5Slpb{$SYpcbGX6P=~6csaJrC8=;BA?hCX<6NlY@ z;|3K6#XA=h0|U&Ren{e=wfZpeWT-gEJ)kx)OuP(993%%@hu;Pj2bm8#OCP3wI+8eY zyd%#Wg3gA8sow-u4>B8sVdfu#ii6Att>uHMzl0=?Z2l{#ILHh}q;}muByo@&%zR#? z`679MpD$+1rC8j;wwP4sn?M zAbXM3FU6sLJr41mIK&Ski6i$PPa=sU+j|j79QmAzn@Hlw>K`JBBb)ylNgP>y3$*`) z;a?o$$mdre_fL`U%Rm-~)#o7dk;OrEB`6D`i^JBLql+VtlOUUeJU)gj4%*9x&3sT= z!X}Qq9}U@@GEky~_Op=1k?+|-7Qcr>y%4A}!(xsUR2-xYgkk+zSbqT|2Ewp?#K`B} zA@@Uzpyq(W4S9T^2T2@R{Wc_VPapv-=IBG) z&mc2E7-o(QR2-y@8L57WK@vxfFXZ_+BKF{RtfEk>}Bn)&Iw#9(KPx zy7|cSR>g+u*xBynW(am{mWz@dH* zk~p$^P9ljTn|~Ea99jJ%BynW*uaU%&)g!NaL{`rTZ5V^X0a-mKk~p$@VI*;6_0l-R zm661e+ZA3&;>hNtB8em0i@XjTG?oi1S4YDB3qhpv9CqF&sO$$}SosgTw+JMLd~PuE zJ*3F%Ly-3uAdAD+?SRYyVOaYCw3Y@`v4YYGayblY+hY?)KGz6&z7=_2j0lpykk4B{ zj^9^E^G(R&DImu|>qlg9*uHy^JCVha_x&NeM+~W5fxK?q8!8U6283bhEgLEhG9THT zsYv2NNd7v8B#ylP9Jc-kWDc@8>>fanIC3~AfdpXf9HjB9)lhK|gf?1gs6!RP&g))>Id*8?errXSE5 zK`?RT`_!b6(mCkt4v-d*y`ZyDVCrG>j39C3^l1fB3{7vKGg@KlL1UO8DUf;zB=ceC z27~e<2*b)f&>8zM^~mOf?#PCTBhL$i%0`el$c$A;`3U*kRL~wMn0sL5A!z*!Xiga> z4m$e?W)7&Y0}}`B@dSy3+>boJ3|dnJ69>&%!PJB1!eHXa?u4ZikUK$V+`-iIAjLcK z`Zw755+L=+`)ZNPThQDk%p5%=bCAzvLQaRsjDP-{oBy*6(k<%@*IP$qe$m@2H z*S#Q@Gsx)^bVfJa{h&Z2kUl|Yhl1h(q?FY335rvYK9GLoe1tsjkDN~%K>-hS5AweL zHmEqr9OUx08%Z2F-6Ef_3py(a=HJOk;S35Zm^kwKA7pbtX#?hdno7MAN~9&SU(y$9+AUmxSk({>-<>Q`JABm1+5{0#S3UJGc25u%X!%Obs+V~_c9~z zH$)CkKR90X!2iacG-2pK3Vf(>B!GUbfZye?$-^YjSPUQ6@$l}Q7>>-=K6BHTH z@JAL$-am^hZjKc1ptAyC?*EP?jvQb7AP+&!M~*MpJ>4K_Wbr6|`m#W)5r}5h(aTW9cyQ zU(onM7dHV3K>dXr@BT>QpfUkw4)VD)$mIa?Juk@a`Hf@_a`<>5#S3ycM?l3v+CXU! zW^Xf8927pFwN)_jek5_^dTlk5IC6Ufd0z&yIBdKcWInPv$o(~B_2+Sze;r92*`4>1 z#F6XMt00d;!yh@EVdu<)+=ILh*$$LQpz4vuk=x10?T{iQ^`NzjuyBLT!-LF6?svoP zj{u2_Bel1Y`}?4~HDTt!2G~LBk>ghcn%+R-$ngtXUjq_H4hPtIu%O^zM#?XswQ3+Q zfW$!l)BCqe-j$}UUd?AoE;Yi}h=Lmt?05E%z?_p#|Qjb0^0rPJRG`)e$ z2Vq$K2s;N1B!=96o(okE@)vUYhwak`i6f_f=TRf?(?LF8Is$4w$Q)$xBqVWU^Yd|t!`3^2%t2P)h(moB4)IAi#AhLi zBbOT|ki?P8nQJ)2k@x!`tB0*C0fiYTE5O#*BH!7hwXm>i6Q$7d0rmbU!bxbWG}k=L2kn)4%`vtN7;-oxpNoqu4%(Xl zG6!Tn2*d0JjqSk1`H;#V*m`7;S`db*hqc2&V#w}DeJ_y6?J%<#Y{7CKuof(2nJ?P93m^iXK|3S?Gxd+*upuGbi^&oL%cOtK& zKo$p$or2VZ+z9GJ!QvM*1_BcoL~RN4w438 zm^)$jB!a|180O9$APyFH9z_xd_0eGNxqw3)b{;7xJdxEu!=e5yR2)Qs@+{2!FCYP^ zzd&OhFmc#@jv(`q!vWT>2Z@8yBuu?9sE~!40~*_eiEAT?gRFvuj}4kQEPPy`;vn;p z;}N+XC5aUNu>Ig5v!#&4qmax&c7F;~9HbsJ<_~ixY+XIb-t$Q2)FY`!ZdV|$pGR(2 zz|MOFnGeD+|H9VEfW$x;=3nG>GRXdA067GjPLRzPL=p$}8DZ|1g^GjBMvh0=x*Cu) z$WEAgQ;+~OzCe0Fa-jSPYwv-ik=+vx5`d~l4rk>1tdZvhs-fyZlpIpM*$onanxl^- zJ`E}kqCjUF!`unGpBf}?h@^f4NB|l>pgZef>W|_Ozkx#>xqXOi4)S@A*O1Z!GgA8y zS)3P#xHt}RMI>?1STW4~nn>cv=4V00L2-p#u9iZ@LEZz!A9Msl@nGZW33?vT1F!Pbu`6Iit8p#}x`LKPLO-SN$Naar#k~p&YGoa$=?w=18 z2dM>_58Ds83`ra`hXr&0IwWzB9+><0K*iC`KMWNIsRhj)z|1*^Bo2~;nFHHjfNsuX zB=sP7g3>xD{k%dFS40X280W;vhMg z`(fvjp_{Lbq#k5GD9wS~kG$^yG`9;g-wH`RviTlRadh+jq2eI5AoD?cZ$RdUA&GOiGrtK*9Ha+k{sgEvy7{nu4Is53 z^I`kK=0Vki#6fq|!pvWWBo2~;nZE@pj&A;Ls5nS1$b8s-BG^6%khnTh`ZSTg^LlF^ZlUWAhjU# zVf*ajkiImqkJ&mxH|7Y+eV`z7l0cEnz`$UHrXDsAVTUFT>koUOiMK<|2}2VH-IW6JR}z}|6sY<*m2Qxl>sFCJ$2Y0CE&a5DA0CahU_VTM(oi*&JBf2Z_Tl$Q&0Y z1_qcqWcR@CjDx8K(fHJZ);EIGAY**$VQ0J$s~)yS0;C? z?N0@X2Z9KYAOiyfY=0_92zI6rNDA3}*qJ9Fab)woK$<{;3=9m&=6fTFBbyI9LjtM= zOo5cb#>_zi$o9g{U_k~32GCqBhz%0s z1u>u))}H{0^FzfzlmRHfp#FlT4Ujl2u0iTS80H_)ngozMNDPEw`eEx5L1G{b+iwZl z6NjuG7WW^J>;0VrO9Bo1~HH1Wdj>j8hpy2^B2c#Yr zXC6r6AURmOyah=db|wMHs9q#-komAUM#k5(k+BJI^ZxNgO5yQs00iZUhp5V&wBMVQ2P&q<$c&hm}zvaTjQM0r|@m zBml(|ki^ZPVjv23ej`Xd$el1f50KQGgA_vXOC)iSde}LA2GBwcWR3+?Er<$161M~i zKrw9m3Zx#k7XT!+1W7$?Z7oQAEs{9MURe3_21y*&2L-ABiX;wFUjY(iU|?{7rc;o; zwoow;Re&T8TXO{xuS60DnFDGAfy80wqJzw_2MIv&Sv2*qbI`sZi90~mf~dbp;vn-u zX9(A*VBJOWAF2_yi;iAdrg^{{pPYmmg9p=v?YRwQwd z`d(yz%MDWxJCAP#l6p6gLMYyd zBn~nkwvPpN-ZjV^SX~U#!iv<61*wOvUkpGJ_XH_~;z%TMkb2lXE_0B?y`gGB)CMGR zACLeP??e&@nFDM8e?SuVg{lQn8qmrZ`HBpwYC zfMOG9V+-USSQ`=~Ws4*ZGJg`(zb#1Ousg*->U)vILF!@mZeBqWj{_-$Vg*4617t7k zE-H{n4w5)*jT1<`0ZAOTwizVei6joP_Y2gWSCGV$K?K8!Gmw`4&K<-Hg zDTHEGByo`XdraZvjcwmgBfHmY|SA^d?J!K$o!X3 z^S>a8!|wP7sds>Oia_ST?xqKc-#`-Y1_?m12DGyTQr`m=15t)Z;vjo@pzWRrB=KI5 zLMTo|5(lY=-RrXeNxToL7DTN?5(lY=&4*n;67L5ogyNe>;vn^QQ1_@nI|v~6!`5Vi zwCEyiPXsB1;zlHKkopX$`V&avu)TF4EiaJ7VRz|*#7&@`NsxPBXY+!@ zTad)3fdruV3X(YN?nRK4iY$nP2y zI7odBv|alFNgQN8Y&`QPk~m2H4ybw?d64Z8_k+wo1g+Oxk;FmjVfXGZ=oMGymLw)I z=oOa~LFfz^t0*-mQLiMmqJ%*&C9x!tK`*Jem;o%H7a!&49b96XTvAz(>Y40nk&+)@ zo|%%G=bFr*SCkJ@4OL=jl$4kfpO{w}pPX1+Vp5)wSmIg+vdd7OF*J{NE6qy=SrDI*n3s~1TIA^#Tw)NVQ2{QTXAM`d~r!pW?s5ya&U>EVRA-dQG7{JVrEIPXR>Q>qGz(JtE;P@ zMPgBUL1IyHs)b`wdTDNIUWr9+d?MHi-_V?3i+I;~S64%Wc;EQk#Jt4x)FRiQ;1bJt z$GpmTP+$gm2fM}xml#^a`$DAS^9xdo55^Sb` z0?^PL?uE>}lGLKS#2n8gSIhWdsK;IXg5!DABrQmE zP-Yq^X@e3TjuM z%pA-3__D;J%)~rUPL5Ac&5JK9NleN~jnB+2$no?GHi$PgiuWzeDanjaEGkN@^bBw- z^N#|Ho5hDgbjBB#_Kgn?h-c7CPfm_ctw>HSD2WG$0wl$c1{T)9 zLKF!jHh>IAQ&V0Eu~`p)V4*Z`f=kTGQj<&ai#+{;OAHOtGILUkD~n4~b79R1lY+#O z3{aCH*eKrB6-y;+Xy8?xpXZU9Q;=GOMSAd7W0vv0uu>_=8@XK*Y#tA-*{PH9KxMd* zA*dcmDNRm=mWM^D#icnVo@K7C{zz3bydh?uoS#=*nw#qBXBi)#o>vNP+nLA5=j9jW zCg#LvmVg>s`9+=qt7}Mnun!oO7@8*~B3hC0Wtpkvp2^_) z0n`o%_Q9wVu+>FibAv;`RZBR;3cOVYj&vIoA8cqulR9HGX57kxsSq=0MG7Ug)M%6t z86`N{SEHF_z>6^gF@u&_2C83=yZW=hS=J6tw;}?xG%qJJJ2j^gT79E;GN8hUS{<$L zpIQO!`;$|tQe(J)<_sOFd>n}ar51{w;2^rGXjwTKKYGK=F=Qj;@5?VlWQ11Ja7`^4H% z!5H&$MU3vz+71h3@6*C7gv~e1ERKhTE(u{2YyxWd!o$ZKK0b&(Vg!zh;?kt#{M_8c zyp;IT;?xw^An#y93@yRMK1zCIlmwW_Xsj>uZP5k z7{rGd#=E-u2V2AkTcTMWTtca_0p7u;@gTF2hvDJL72b<7G=>dkmL=wtrg|p1x&{Rs z#QTTfNT;NjfMheM=bV_FT$)>&lUPEy%SP5{JyM^|JU%$lGuRy5p$aw!O?qIu+t?y4 zGcP3`#ryG@dGW~^`I*V7#qs$?kOCb%#1{mLBzMqgKPcMbgT3N|JwefjH8T%a&!T2Z z%9AK4b%K*AQbO@Vlw$BSN_I5E{X@|@A!hE{IblH)D)7PMw+n%+-Ph9absR$QF?KFQDRdcH7Y#ET*JcOh7woQGu9PGl$Id6q{t_XXX(cxudiiumo2Fmf&i@)iu~M zJ|sTaJw7Pd5mej48*%V#m{aT;6r2y5J&cE!J+6A0#YKsF2G~m$qO>B1KQ;~ML5b85 zM{bS~r4=>Ykva+JmN=WZ;%=Pao)Hf=i}wr0Jp=0J4I29dO@}4tcm|t+hQkwso#LTk zi0U{{vvF`vaN_RwqYryiUI&8fzaZ~m(1-$}mmVMGhiJ`^6;Fwt!KR?#$GU#NC_W54 zqY)44)`F%rNNzBLnpe2ZHz>`^EG$h0bq_$Ma8fHPC!nxb+x z@^mzbPYwokIzS5*{DKYR%^*$%t+ccd#+EBZ1!Mr?xGag$tf=AS+AZ2sf-{G`#*m?_ZG>)$l$UnkV5^0&eTP z5gj_@ddSewB{iuu9Wp0r3T~!)dIflc7Cn`@6yWOo5z>X`Jfsy@2H>0yEpITL4Npv< zg%!y;sfk4xLlSUJ=rtK;pB%Kr%_2T1DZZpAHPsU|y^3w74s!r3xWuF&F|)`MlxTxX z3{4S_Y& zY`O+PMj7B)4bj;__f=*EC|8j@a)+E4sbn~EvO&qTB$rsQN&~d|E50Z-F()TKIX*M5 zIJKz6(<=xxUg7HMT1IF(7qk!y)U$Ufz&S`U=$wg>F$Q(=L{3CB3`%eVg~a&A2uP&0 z8RVx&qtx7joW$hR_@u<-Y)>zU!-9fM;~{Ab(gQ%w2e`AAkwHOGYC%yxXmKlOEC9S_ zv=}tzL>WRCx1iVS0~R!>NnoeN9+j_UN;#Nw2rpxW>7odWw_cDi1ade zU5=Wxkh*4&)y$xJ%>c9x+#I|t6s=wh21yZ7%o)UkTFkECA_qBYFkd1%VgUg@Q{`S8^8B1;hs%8h}O$QKOX7rdtxIVUN;f zFvILJfQHVDOyYgxAtS?}CUQJ%P$eHUOo=gD30g-_S(k@+hk*vjkQ|ngnOB1By5JHc zV_5eq9<)lc1hE3fp!JX_BWm!16gCKL1Rn9vNi9pwE6ylM&CH8W$t*5O1TD`ezSHOmvN0qcGJpqf zl)>#n@7Ebxg0~Zanuf*kpj`o=oiwy;9uBBW&>M#X6nP@%?9huaP>h1QSIDDY&X`pgs1HN$DvZv)qof{mj)#o~BIhvNnbSBi1-kgE zs2IG>lm<-`EWw9J2JqH9@q?a&Ao?kDKP3_DNMZz=Wag!$R)87?;4vdtY>^R+G%*dD zvq4Ha!6k-9@$e1Xso>p8Bo8yW29yPOL;5PnB^jcRj$RfRr>B;Hruay=3AB?2#~vC} zSWgnve1KOH1LX)%O@$QBNUMqH6&R?M07gV7p~f1rTantz;BD}rb~0!<0_zAonFAH5 z_KkL0>C|a809C`7n}>09TB$Njj(vCwMn8<4g0>OB0JgtLQ*Wwi1hAlURhNuE_EReBJ;wFbrSS z3fcr_8XuouP;6)tAC{OCpPZjt0PbdcBCYy?*V)b{o<6xouHa4QKDppsgt&siG~U%e zxWp8)!#>z6J|ZL@=N|Tm;(`!RdEyEhr}hqs5Ap_aK`~zz91tHIj5c}#+6f;I4Xn)k zy!hh$q7s6Oz-SX_rtzL7sYQb_)UXGfaeRDYN>*ucNqk0XVgWrvEhpGK9x1sE;*bjl zCAkp8_z?85pWqTh!}$2z#OzeMhu+W#xq$c}oVm56C?Awj<8$)!>6`9`O3(!dL#N}A zn?mrO9HI<1BDxI5T$_SaB%2afB%@WPaQC3MS`CdrJxkb8HsDo2poJ^0pk-@F-3`#H zAmly)PV=0NXt1&rF^&W84-A9@KphgSk&GUwGzkRc7%eVIEGj82fC_;Y-$BmAL5iY~ zU{F^9c{?IhHRxn2&=FpGMfrO1Q6ZoeQYeQ&p__s2U@F{3;ZO~Ww~$~gU2^0@wa6Rj zbB%}fhtYjUL+g2P#;wIw&VUIWY%R7=#f~W}qm>k=;S1B(jfTdi+2`*qG;i8O0-=_vJ~)Q@xDA zv&5jWYFAg#;#27UY}lz@UZ}IpuAu!RppG}_;5*3SWZ1GXNuC9@at7rfeR{VgF#Edhz{6b zaKMIvdgQLI;PV#{sTN!|f)5APi;r>-i}FK0rwTN%>ssb&k(mdX5r?TGS{3pFb4#-2ViN zeq$2!f54(YhXnnw`)Hxp7J$L9T^PW? zzihSoFUpLH`vj`rneE{{a^Lwj}6(gGE2+?oDFD?*|tB-$<~Z1!@s; z{Cy`uzW^5fKS|IpgGK)@67*|e(f^wS{U%uS+moQ*0gHY?66$XsEc%5=&>w+Czc2~< zQ?Te4B|$&zK4|3hBSwOL*nNx0`o&4m-+{&b5+vxKf<-^5PXZMtIQ|N|{}I{!awOQl z25J$qet8n~@4%uTbXPi5n4tTQKoug}uSkOZ7ohr)>rc>_6jYd?{ZF6@k?mI^!Tt|e z^edB~{|^@ZDkSKK-IIyzepM3mi$L$eMAolHf_?=o`n5>VuY*OuBMIf71yn!s_@5mK z_B%lJBm2LO1p9rU`jPE-B*Fd=sD5Pon@F%f0jeL_erFQw&w%Pjw%?5e`%9quk?ofv z!TuVkeq{SANwB{Isvp^YR}$=>0M(Cde*_8k&w=Vkw%?5e`;@m(3mE%`mbQo|BM9pKft2@ISKmTK=mWXA81UHSoeRyqMwz7 z`2T}Nzdi~2S)lg@Bc~rL67&mT(VvVZ{1g}%7(he4Q01U02QXHE3i!Y#punOG3}{>i z(6zCkFon%mLzOWUTmqTOz~BMBw-q#hUCqG20E-Xkb-xUtJ550H$e4+%51PgC;{>>lnJH`Vg84X7l8#C7#Lvsq1PqDgfaXd1l4Z@ zR{>$PL+yuNYY!2Gss(Xi{%C@Vv7y<&0IDAr{~$dej2`~A43IHB*myBW4G8bJ4Y2_h z&YMx1svc-G2b8pOE{n;c)*2Eba&0 zQ;nW}I2j>sLAU<`)P7ZvBatwA__09q1bX-fMLGkK?eP0eUYs^m=u;3()O9 zgu{M@JCKkzfa(OrALt%!bo)QzuwMacKOz5v=83@h7cKo6K<$UEBLUeDx_=wperYD` z;SalCoRI%veLD2;uYlT*?0?XG-stv&+JvBxLXZCfBK>a(EmP6$Ujelr+5e#XzR~SZ z#Nq!1Q2Vo?@du;O<39$6{U4zABl{n8A2_=GYoYctp~W8$G=rn(Ur=1b+ybIk;ILl- zG}y|(z)%5F#J~Vv{{Xr#9NqrkQ2WutUjb^rB~(9*LihhS9QMzE+7C4bY(HpC4!Zp} znX#w81gJ(r_JhXhKw*L&{~NH_54z_Z-TsX%5c|=~&jnEXL3tMDcMuKJ4@$Ej{sE|d z^zbu)-fyo6QiO!j!|x$0#D4Vn4}|Im`3*@sxUNU$^RYwpquZYV)lbNNeGZ6zbo(2j z`U%;e$O+MpZvO|S*L$8ch=|4u;T4>|wN#Zvz*#$msJ6vS4L9taCUqT4?Y zhy4Pe$p!`n2G}|{Q299@i~Wai*uMd4{~Cz3a1!1Ay*TVIfZ7jRhX%5LAr|}Fxv+z!XtE3~|8Bx!e}phJ{?XiT0JR?)4G_mLVD=wt zap(_(>Ie1D;F_U*4P<_WFf{$3+24W1{adlPe+3TvCqV7jM79iz`;X$#zZ0sTkoynd za6bcRvJox(cVKbOCy{0Gy21galB z{X0PQd!rQ$=;?pI2=@4^fcjqnY7r>?@4@1K6;X)$(e0mL3UPlago2ak_REW6w|@qx zV}zFf_hGTW8frg!__3Nntb~OZga>gehz<1?!*Qs7boUED^~2U7gYHyl;;`Sr3SuE>&I!VTkm&w@fW!V3?;s9Gw*NR5`=i9M zhkt`L#6Bmqfh~0VL&dR&|B3ey`*%RgMNs}ZiN*c~9QI$ZgV_HYLcvLN`>S!--|z`y zKXUzf8jJncaoKMVv64{x{}K-SH(;^n;0QC6pm&ES=3!fo21VAWo|NSzS@UN1>Zoh#m#KxHr3QnTi zUn+&&eub|Pi;>H}t61zm2eltP{7ypchgM^7`yr-6+zb*_mWHs=!;irYB+I~1jn?2o zcfXu8cK0_x-M<2w|3UE&+Earb|5;G`(cNF|1+gD}{1x5(yP*2f-9G`UA7m%QBnXM_ z{;fFNuK`-D!@$4*+eZO%KWMBN-Ti-{_M^K$!y96sD1?HO=T6 z`7b~Qd-zWPEfzv^|2-_}X93iHboYn(Kx{REP;e66{U4$FF~T3Je<@4@)CBbKe}lvQ zKR}C>7#J9k%m0U1+;1Wa2|slAoBBa4MC(4m$B$sns(|W8cfSKv{{iSc7{oNp_J6S~ z_VC~E4`PD?H2;9o4`@#qdiq%hwIAL64A2dXQ0*}5G2H(Jsvq6`0#N<1{0B1tJ^bI} zaQ_8phYY44Ip!&~3%MXZYnBkuxhdul&pay<` z>Ib?16&Cj|#bN(~Xo!vW1nQ3kIPA~hf@p;8Ljc+T28;a;^4P=gek{a(TL=XwA*l+Y z2P9Yv)erS9NC=D-;=mL`C)xxcdi+<&V-LRrJP`N4fF@Xw``=@6{~DVm$^1h8s}*AoqX5;(l2LNLZrVzabN1qYWe& zARH{^uY>~j@N1BSXoQW+gY5r;#r|D5?Ee6rc!5qo~hYo{++s~lN3*G;9%GkrdARl7i zK3IVV;bQckE0wW_{|(S$Qw9bGWc!&IG1qVKt6;a^pb%mql!9=uq(3ed?Dp>fEjDFf zU_hR~0L|5-`#%6`KYIDO0%|d#@v9wB{pjV_1E~Hy0^zqAhx-#ii(MHQ7(jczK%NJs zUv@0vC$5S;`~r$Wx)>M;9wAdAG{2#Pd0zLeCaoB$VYCmYrDa0iZ5VF3@22P@fU%DFh__KfpJZv8_DE$avasO-__FsTb+)sd1qd4uK zhQodab%;jf_yf&lpr@Y~IP6aVE%styVE9WQ|2)QFzXEgvE^Hq-$p0c({4b&oi9hu4 zPk;^_{fGM;!axsyes%2Oe?b%Cf8_BiF)a4)hT4ywe&XvO_MxwTfdvPQmeRoP{syRi z*gistX_)OdQ4Q?wX8#o7@6qo<##Q2Sxw2XPHVEr<<`R)+sL^q+w0hfYI)w16?p|1kX%bRcG;=YIz1 z!W%(o`Uh*q68_yf*u&oe>i+^rG61)~)UfzpLKnOJ3f&MJ35}l$>teTmgCWFXqFd+Zhr!3u^9sc!)}N%5YJ$VzdU{H_J1&gXhbeQbg|ffA8J2(_(@NNSP31*hj6fr zpD!}N;eM$8d;;TNa}BV&|A#rm{m9`5I{ylm{$c&1a6^dw=&h_us%_zXEjOl?cQboc3SFVSfU2-~riw z(D^aw_U9Wz!Vlg54xq(a3=9kfu#5tA0lNRQjIsOw2GoA!^=F{-Bhc;VFu`vBh6NA{ zL3=hKEC`8iKeGvT`xR^<0f#((06M<`-Tq@Z?7y%GVjrRY`#~J`KY-c~OQ)dv8+3jH zy8Rz<*v|l3EXKgVaD+hkzrkVu52*df{V&k|X>|LwOtFXm1<=BH1_lNvNH9VI155d% zYKlGl4WI*`$mI`c|1Y}zQ=s;v=U<`a5G&Ewufl=@M$4H&+>fq50IDAvj1a?+#xG#{ z*FyE9r+-+-+YoI62|fL-FvISD3+TXI0dxWt6#t;}2hshnXO7+dhR_4>pwl>T_ru%` zqqjiyqr1NWs$URhA=CtP_pdj{?*0|tkcj^PUB3cyKWP6P%s5!OHnf1aAKm^1pv5W- z3=Gg^gizZt+wVFS*zKPY1hF4>4j0IN(EcrS`*U#E-vC;y!oa`~3^4|${pmRDHwb}f zgq=eIvfm3!{ka)xKYIGR3@vy-X&!DlmiqG$4*f!hAi6|h5e?yjhQPoqn6QZ@_V70V zEjD3bV0Zyde_%~m@~^%n_VD)zhxq>jbO9>J|DgSM=;1#DYCpRFCC)=^geD&d2aErY zL-nJl9|frXy)X-*CZMO^Lpac3-F*yC>j)P86(1h+px=Wn9hf6f}a{RN=OY6b>| zTLjv_C#|vDpO6pn{{jdFwjXqUC%XMyHrVYCcmVM~q3~z5!EQf85yWET@Q=h2|EF-+ ze*iRD%)r1vDEyD&u-^k}KXUj-W3hj|Eq4DucntABq49%Nw%Gm8Q4H}v^7wHq7W+Bv zu-k9&3}QcM&k2MDA<^?6iye0RH$d%2ZhyvOu|ElFKYICb0%|{KeopK#c};044+LgD`why4L%5c`qCA9Q{#y8W^a*!}PD5@LTp#25$%OZ_3? zfZhKmu-KoDCH{MH*niWC4a9zEHw;|?!fwAsJ;Z)!HUisU zjm7_EQ2WvAzXhz2h=(o%hglB|6^NTbg5PoIzX8>czW*8Ke~9S}47J`6v(W251~!O_ zFK7*T^!l&D8@vBCpa+;XK+_MX{He#{|6efsL7qXzpvg)G1_mVp{qL_Z`;qm6=FM9m z;jaPRhYYeGbpAEW|FHU(*N1@t)WtzdW(*pj$s(lj0+{hI{czd`>VKF5D1Biz#D17P zAp1dW379^ZxTFsx{GrR`pt>0t450R--;IDC{?<_aptDWkni&`vJfQkv_Q2#|_QUvQ zF!w{83lnB|0d+re`?(EE{KZ1;M|Xb$4*SvF-v-r>?*0lK`qACrh{OE`b08iRg{B{fb78^^ z6;Ssh*WaKs&0+ds?r(-G36QAKm>CQ2m75e*}m7S732Js4hcy zKffO&{LtOs0JXmg?s5nN-Tkwm`qACbAWdBOPxZqd{x`6=e-f7Tuj-H8{R&X~q00au zjtA8za2ABI5vm{E{R^P_35EX}f9&q(m^K-`aR{|2c28W3l~Nm%^B z1Z)Ga+iwB2A9?;3bpAU`KP>&`^1)ej4Amr>_=A*|cPze$f2|F!#gUr5OrIKd^iT^JfIqe)RDpSo(p{Mo|4QeK5KO zsvpLO(J*~5zEdaz189jndiw2v>PJs6F!#gsM?vjJ*S`X)KSCa+5<;Wv4-JLJA4D2X z?tq4$2Q*=U;%_aM_yhR|-EOcUpu^HZ?P%yeTu?s_bpIC2epvW})|aEVok99n6oE`; gU^o#E;vq0Z6u}3zZ?WlT*a&e|b|^wEh=r~n02L~4ga7~l literal 0 HcmV?d00001 diff --git a/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/prebuild/compileAssets/compile.o b/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/prebuild/compileAssets/compile.o new file mode 100644 index 0000000000000000000000000000000000000000..db7c4c7f3df726b4b8d05d61cf26f5329139fbe8 GIT binary patch literal 222008 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

    ^hV-!!Ot0cb@5n$G}*vkD`2_4QEo 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 literal 0 HcmV?d00001 diff --git a/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/prebuild/linker/ld.o b/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/prebuild/linker/ld.o new file mode 100644 index 0000000000000000000000000000000000000000..2454795d8f2932966fe0484da17b6901608d6de3 GIT binary patch literal 29864 zcmb<-^>JfjWMqH=Mg}_u1P><4z_200|SFR*enF$7~Z;$3T0x2HdEUFp|3=AHf zE-D;`2RvFYm2i5re&cUxU|?YI)O_R9siNZ9{D;5X#iQHWv-uBWsWJaHSB4IDpKcWu zk8W$9&SVa!V=U?n9^Eb~94Q{!5aUV%JerRPM8`VD9OjpIVDN2yQgZdR%mk0l`yQRo z3@^O^Imx4w*`xEgM>mU#N2jxZPv;|#&Uau5sL`(%d-U3Z6oLi8#AklFUyk7(z3vi@ zVUD4WAwIq78lfJ&>sK%^FhIQ|;n8XC(do|NaoimgS`5eBB^W$9--EULbnAl5^XO#- zQHI|CD#f z=`3N^@Hp;l05a0EyY__-<8!d}9^G(zoh>}N9bS0!)-YQ@MLjy%krjD#i-NTK^k!Fh z^cFk#^nxAe)A`<`(?rDw5-wmPIzyN>pdRw*bk^`_J`e!)mPhjo4UbM|3!lzn2an^< z9w75PjynfH=?EyD0HrgabODG4JH@B7+QFmSM8%`?y+?2J3!SB6*vbbF(EBY zk6*q8q=tcCo&l^55?kQt?R1BFupJa{5D&Urz`gJ8;L*Jw>>h}7JuHux2zYdZ9qrLu zzzA^`#5|AQ>I#oeX9tKFBxaz2?$Ns&Y&|zE5I3#I+vQpwBTe7cvgeqdk#XV_B5h8h(Mh7u)5{(U7X&ah16(R_p>)}!;dV+`2AVE4i-^6X|& z*~bNT6gc^MbUPS$SY9YO?9=)D{{{YiA71YStA|)u@xp`geRsJ+^EpV&yiEH4|3BD? zup~gp{}8LdS%U=sgYv2eEYyay|9QbdJ#zieIl}!vBGP}TXXjT?`3EWpuY{r$fF7Mk zeOur1x4Z!tc95*>)A^1-VMnNZB(8kmZvj<#&@xgEwTz5)i~*I9vCt9{UJ&CdACJS! z$GwEgN2ol5M>j_CDF7=zC!my{;hvq}9m9Nj%Pky3Jv*<0g7Hi!xH@fqBjM2x?m`KH;~wyO3jxua<_{LPwRowGLLRZ?d;jTh7DAad4Q4! zh|y4M!BC>kzpvEUr}H~l3%Gsa(Rn=9F$U5^fyR~#s5K063#gvLR-f(h=zI^U&o+VM zV;3kR`gDGW)+%7*yGvAfU{--$3$BHagXLa^{{R1}=F`BeP!2UvO zhLpqe5yU@`@N0g<;nS^#S^Nw=|AYpEb3LdBc-#Wfm_*6GM?E?rNfld+WJ6=b!V$G) z2-i|9;L%&nVR$Lpafbo}14Hai76t|er1V6ny|@-$9xevw7nJfW1mym50dNoY9}9o` za!?u4jnv~~VDRV;7VzjU=J4pPwg4Ld&VbO|>CuVTbNNuuDWiHW8mY~j26GP~e;k7Q zV+XjL@MwO=;?Y~r0qp_541uRK-MtL;BXBD&n(8^P32iF#-?610LP(89u!^ zDgwt`R0J4&I(1Y$JD+$QcTwR070e#32l!i_fHHWudxS5Da~#C6Jiy<+4;)ec35J&p zzxi}N_tZQAw%nuJ*rPj`!=pDxMZu@HM8&`ZRIHb%D0nb_dg1l{|9_v}8WjhhPDq^t zE2|(e3NEamrj)2Sc(i^i;ee~`u2E6&vHV`b2O66&Ky(1RZB%?L-$R52kc3@SJP-pI z79Pz>7>=Pnz2NZ^(6|e@ z5)So%2n2�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 literal 0 HcmV?d00001 diff --git a/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/prebuild/makeIncludes/assetEnums.o b/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/prebuild/makeIncludes/assetEnums.o new file mode 100644 index 0000000000000000000000000000000000000000..7f6ec48e50bd1789f03a77a2b180983efe31b8c7 GIT binary patch literal 33640 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 literal 0 HcmV?d00001 diff --git a/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/prebuild/makeIncludes/assetsAsm.o b/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/prebuild/makeIncludes/assetsAsm.o new file mode 100644 index 0000000000000000000000000000000000000000..ffbfe460d116adf333a132a73d48bca5f64d9fc9 GIT binary patch literal 88576 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 cObv(z)#>PY4il001zk0?*IS* literal 0 HcmV?d00001 diff --git a/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/prebuild/prebuild.o b/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/prebuild/prebuild.o new file mode 100644 index 0000000000000000000000000000000000000000..27b7edf285f496f87e700b94ae7e994b40af6adf GIT binary patch literal 157808 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 JsX}0M{Qz4)DMtVR literal 0 HcmV?d00001 diff --git a/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/test/test.o b/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/test/test.o new file mode 100644 index 0000000000000000000000000000000000000000..7bd9cc00f133f41a4657a21fb5e4df7e389ef297 GIT binary patch literal 111456 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 RsDzzA15yjZ5K#~df&o9Tn=t?Y literal 0 HcmV?d00001 diff --git a/tools/dkr_assets_tool_src/builder/buildInfo.cpp b/tools/dkr_assets_tool_src/builder/buildInfo.cpp new file mode 100644 index 00000000..01833d39 --- /dev/null +++ b/tools/dkr_assets_tool_src/builder/buildInfo.cpp @@ -0,0 +1,8 @@ +#include "buildInfo.h" + +BuildInfo::BuildInfo(JsonFile *src, const fs::path &dst, const fs::path &dir) + : srcFile(src), dstPath(dst), localDirectory(dir) { +} + +BuildInfo::~BuildInfo() { +} diff --git a/tools/dkr_assets_tool_src/builder/buildInfo.h b/tools/dkr_assets_tool_src/builder/buildInfo.h new file mode 100644 index 00000000..e4af0f39 --- /dev/null +++ b/tools/dkr_assets_tool_src/builder/buildInfo.h @@ -0,0 +1,16 @@ +#pragma once + +#include + +#include "helpers/jsonHelper.h" + +class BuildInfo { +public: + BuildInfo(JsonFile *src, const fs::path &dst, const fs::path &dir); + ~BuildInfo(); + + JsonFile *srcFile; + const fs::path &dstPath; + const fs::path &localDirectory; +private: +}; \ No newline at end of file diff --git a/tools/dkr_assets_tool_src/builder/buildTypes/buildAudio.cpp b/tools/dkr_assets_tool_src/builder/buildTypes/buildAudio.cpp new file mode 100644 index 00000000..b371a0c9 --- /dev/null +++ b/tools/dkr_assets_tool_src/builder/buildTypes/buildAudio.cpp @@ -0,0 +1,20 @@ +#include "buildAudio.h" + +BuildAudio::BuildAudio(DkrAssetsSettings &settings, BuildInfo &info) : _settings(settings), _info(info) { + if(info.srcFile->is_value_null("/raw")) { + FileHelper::write_empty_file(_info.dstPath, true); + return; + } + + std::string rawPath = info.srcFile->get_string("/raw"); + + DebugHelper::assert(!rawPath.empty(), "(BuildAudio::BuildAudio) \"raw\" not specified!"); + + // Copy file from rawPath to destination path. + FileHelper::copy(_info.localDirectory / rawPath, info.dstPath); +} + +BuildAudio::~BuildAudio() { + +} + diff --git a/tools/dkr_assets_tool_src/builder/buildTypes/buildAudio.h b/tools/dkr_assets_tool_src/builder/buildTypes/buildAudio.h new file mode 100644 index 00000000..a3e137bf --- /dev/null +++ b/tools/dkr_assets_tool_src/builder/buildTypes/buildAudio.h @@ -0,0 +1,19 @@ +#pragma once + +#include "builder/buildInfo.h" +#include "misc/settings.hpp" + +#include "fileTypes/fonts.hpp" + +#include "helpers/debugHelper.h" +#include "helpers/fileHelper.h" +#include "helpers/jsonHelper.h" + +class BuildAudio { +public: + BuildAudio(DkrAssetsSettings &settings, BuildInfo &info); + ~BuildAudio(); +private: + DkrAssetsSettings &_settings; + BuildInfo &_info; +}; diff --git a/tools/dkr_assets_tool_src/builder/buildTypes/buildBinary.cpp b/tools/dkr_assets_tool_src/builder/buildTypes/buildBinary.cpp new file mode 100644 index 00000000..ea81fa7a --- /dev/null +++ b/tools/dkr_assets_tool_src/builder/buildTypes/buildBinary.cpp @@ -0,0 +1,15 @@ +#include "buildBinary.h" + +BuildBinary::BuildBinary(DkrAssetsSettings &settings, BuildInfo &info) : _settings(settings), _info(info) { + std::string rawPath = info.srcFile->get_string("/raw"); + + DebugHelper::assert(!rawPath.empty(), "(BuildBinary::BuildBinary) \"raw\" not specified!"); + + // Copy file from rawPath to destination path. + FileHelper::copy(_info.localDirectory / rawPath, info.dstPath); +} + +BuildBinary::~BuildBinary() { + +} + diff --git a/tools/dkr_assets_tool_src/builder/buildTypes/buildBinary.h b/tools/dkr_assets_tool_src/builder/buildTypes/buildBinary.h new file mode 100644 index 00000000..8303b0fa --- /dev/null +++ b/tools/dkr_assets_tool_src/builder/buildTypes/buildBinary.h @@ -0,0 +1,19 @@ +#pragma once + +#include "builder/buildInfo.h" +#include "misc/settings.hpp" + +#include "fileTypes/fonts.hpp" + +#include "helpers/debugHelper.h" +#include "helpers/fileHelper.h" +#include "helpers/jsonHelper.h" + +class BuildBinary { +public: + BuildBinary(DkrAssetsSettings &settings, BuildInfo &info); + ~BuildBinary(); +private: + DkrAssetsSettings &_settings; + BuildInfo &_info; +}; diff --git a/tools/dkr_assets_tool_src/builder/buildTypes/buildFonts.cpp b/tools/dkr_assets_tool_src/builder/buildTypes/buildFonts.cpp new file mode 100644 index 00000000..8cdfaf2f --- /dev/null +++ b/tools/dkr_assets_tool_src/builder/buildTypes/buildFonts.cpp @@ -0,0 +1,120 @@ +#include "buildFonts.h" + +#include // for memset + +#include "helpers/stringHelper.h" +#include "helpers/assetsHelper.h" + +BuildFonts::BuildFonts(DkrAssetsSettings &settings, BuildInfo &info) : _settings(settings), _info(info) { + size_t numberOfFonts = info.srcFile->length_of_array("/fonts-order"); + + // "rawDataSize" is the size of the FontData structure with the correct number of fonts. + // Have to do this, since the number of fonts is dynamic. + size_t rawDataSize = FileHelper::align16(4 + numberOfFonts * sizeof(FontFile)); + uint8_t *rawData = new uint8_t[rawDataSize]; + std::memset(rawData, 0, rawDataSize); // zero out rawData bytes. + + // Convert the raw bytes into the FontData structure. + FontData *fontData = reinterpret_cast(rawData); + + fontData->numberOfFonts = numberOfFonts; + + for(size_t fontIndex = 0; fontIndex < numberOfFonts; fontIndex++) { + std::string fontBuildId = info.srcFile->get_string("/fonts-order/" + std::to_string(fontIndex)); + fs::path localFontFilepath = info.srcFile->get_string("/fonts/" + fontBuildId); + + JsonFile *fontJson = _get_font_file(localFontFilepath); + FontFile *outFontFile = &fontData->fonts[fontIndex]; + + fontJson->copy_string_to("/name", outFontFile->name, FONTS_NAME_LENGTH, "unnamedFont"); + fontJson->copy_string_to("/junk-text", outFontFile->junkText, FONTS_JUNKTEXT_LENGTH); + + outFontFile->tabWidth = fontJson->get_int("/tab-width"); + outFontFile->fixedWidth = fontJson->get_int("/fixed-width"); + outFontFile->yOffset = fontJson->get_int("/y-offset"); + outFontFile->specialCharacterWidth = fontJson->get_int("/special-character-width"); + + size_t numTextures = fontJson->length_of_array("/textures"); + + if(numTextures > FONTS_NUMBER_OF_TEXTURE_INDICES) { + std::string fontName = fontJson->get_string("/name"); + DebugHelper::warn("(BuildFonts::BuildFonts) Too many textures in font \"", fontName, "\". Have ", numTextures, " texture ids, but the limit is ", FONTS_NUMBER_OF_TEXTURE_INDICES); + numTextures = FONTS_NUMBER_OF_TEXTURE_INDICES; + } + + for(size_t texIndex = 0; texIndex < numTextures; texIndex++) { + std::string texIndexPtr = "/textures/" + std::to_string(texIndex); + + if(fontJson->is_value_null(texIndexPtr)) { + outFontFile->textureIndices[texIndex] = -1; // -1 = No Texture + continue; + } + + DebugHelper::assert(fontJson->is_value_a_string(texIndexPtr), "(BuildFonts::BuildFonts) [", texIndexPtr, "] is not a string!"); + + std::string texBuildId = fontJson->get_string(texIndexPtr); + + int fontTextureIndex = AssetsHelper::get_asset_index(settings, "ASSET_TEXTURES_2D", texBuildId); + + outFontFile->textureIndices[texIndex] = fontTextureIndex; + } + + std::string encodingType = fontJson->get_string("/encoding/type"); + + StringHelper::make_uppercase(encodingType); // Make sure string is uppercase. + + if(encodingType == "ASCII") { + _parse_ascii_encoding(fontJson, outFontFile); + } else { + // TODO: Support other encodings! + DebugHelper::error("(BuildFonts::BuildFonts) Unsupported font encoding type: \"", encodingType, "\""); + } + } + + DebugHelper::info(info.dstPath); + + FileHelper::write_binary_file(rawData, rawDataSize, _info.dstPath, true); + + delete rawData; +} + +BuildFonts::~BuildFonts() { +} + +JsonFile *BuildFonts::_get_font_file(fs::path &localFontFilepath) { + fs::path fontPath = _info.localDirectory / localFontFilepath; + + JsonFile *jsonFile; + + // Get the font file, and throw an error if it doesn't exist. + DebugHelper::assert(JsonHelper::get().get_file(fontPath, &jsonFile), "(BuildFonts::_get_font_file) Could not font file ", fontPath); + + return jsonFile; +} + + void BuildFonts::_parse_ascii_encoding(JsonFile *fontJson, FontFile *fontFile) { + for(int i = 0; i < FONTS_NUMBER_OF_CHARACTERS; i++) { + FontCharacter *outFontCharacter = &fontFile->characters[i]; + char character = (char)(FONTS_START_CHAR + i); + std::string charPtr = "/characters/"; + + if(character == '~') { + charPtr += "~0"; // Tilde + } else if(character == '/') { + charPtr += "~1"; // Frontslash + } else if(character == 127) { + charPtr += "DEL"; // Delete + } else { + charPtr += character; + } + + outFontCharacter->texIndex = fontJson->get_int(charPtr + "/tex-index"); + outFontCharacter->charWidth = fontJson->get_int(charPtr + "/char-width", 0); + outFontCharacter->offsetX = fontJson->get_int(charPtr + "/offset/x", 0); + outFontCharacter->offsetY = fontJson->get_int(charPtr + "/offset/y", 0); + outFontCharacter->texU = fontJson->get_int(charPtr + "/uv/u", 0); + outFontCharacter->texV = fontJson->get_int(charPtr + "/uv/v", 0); + outFontCharacter->texWidth = fontJson->get_int(charPtr + "/tex-size/width", 0); + outFontCharacter->texHeight = fontJson->get_int(charPtr + "/tex-size/height", 0); + } + } diff --git a/tools/dkr_assets_tool_src/builder/buildTypes/buildFonts.h b/tools/dkr_assets_tool_src/builder/buildTypes/buildFonts.h new file mode 100644 index 00000000..1b535e8b --- /dev/null +++ b/tools/dkr_assets_tool_src/builder/buildTypes/buildFonts.h @@ -0,0 +1,22 @@ +#pragma once + +#include "builder/buildInfo.h" +#include "misc/settings.hpp" + +#include "fileTypes/fonts.hpp" + +#include "helpers/debugHelper.h" +#include "helpers/fileHelper.h" +#include "helpers/jsonHelper.h" + +class BuildFonts { +public: + BuildFonts(DkrAssetsSettings &settings, BuildInfo &info); + ~BuildFonts(); +private: + DkrAssetsSettings &_settings; + BuildInfo &_info; + + JsonFile *_get_font_file(fs::path &localFontPath); + void _parse_ascii_encoding(JsonFile *fontJson, FontFile *fontFile); +}; diff --git a/tools/dkr_assets_tool_src/builder/buildTypes/buildGameText.cpp b/tools/dkr_assets_tool_src/builder/buildTypes/buildGameText.cpp new file mode 100644 index 00000000..1cc0203f --- /dev/null +++ b/tools/dkr_assets_tool_src/builder/buildTypes/buildGameText.cpp @@ -0,0 +1,175 @@ +#include "buildGameText.h" + +#include +#include +#include +#include + +#include "helpers/assetsHelper.h" +#include "helpers/stringHelper.h" +#include "helpers/dataHelper.h" + +#include "fileTypes/gameText.hpp" + + +#define TEXTBOX_CMD_ARGS std::vector &out, const std::string &cmdPtr +#define TEXTBOX_CMD_LAMDA(func) [this](TEXTBOX_CMD_ARGS) { func(out, cmdPtr); } + +//typedef void (*MiscFuncPtr)(MISC_ARGS); + +BuildGameText::BuildGameText(DkrAssetsSettings &settings, BuildInfo &info) : _settings(settings), _info(info) { + // Get text-type as lowercase to make sure it is case-insensitive + std::string textType = _info.srcFile->get_string_lowercase("/text-type", "not_set"); + + if(textType == "dialog") { + _build_dialog(); + } else if(textType == "textbox") { + _build_textbox(); + } else { + DebugHelper::error("Invalid text type: ", textType); + } +} + +BuildGameText::~BuildGameText() { + +} + +void BuildGameText::_build_dialog() { + std::string rawPath = _info.srcFile->get_string("/raw"); + + DebugHelper::assert(!rawPath.empty(), "(BuildGameText::BuildGameText) \"raw\" not specified!"); + + // Copy file from rawPath to destination path. + FileHelper::copy(_info.localDirectory / rawPath, _info.dstPath); +} + +void BuildGameText::_textbox_set_font(std::vector &out, const std::string &cmdPtr) { + std::string fontId = _info.srcFile->get_string(cmdPtr + "/value"); + JsonFile *fontsFile = AssetsHelper::get_asset_json(_settings, "ASSET_FONTS"); + uint8_t font = fontsFile->get_index_of_elem_in_array("/fonts-order", fontId); + + // Write font id + out.push_back(font); +} + +void BuildGameText::_textbox_set_border(std::vector &out, const std::string &cmdPtr) { + size_t offset = out.size(); + out.resize(offset + sizeof(SetBorderCommand)); + + SetBorderCommand *borderCmd = reinterpret_cast(&out[offset]); + + borderCmd->left = _info.srcFile->get_int(cmdPtr + "/value/left"); + borderCmd->top = _info.srcFile->get_int(cmdPtr + "/value/top"); + borderCmd->right = _info.srcFile->get_int(cmdPtr + "/value/right"); + borderCmd->bottom = _info.srcFile->get_int(cmdPtr + "/value/bottom"); +} + +void BuildGameText::_textbox_set_colour(std::vector &out, const std::string &cmdPtr) { + size_t offset = out.size(); + out.resize(offset + sizeof(SetColourCommand)); + + SetColourCommand *colourCmd = reinterpret_cast(&out[offset]); + + colourCmd->red = _info.srcFile->get_int(cmdPtr + "/value/red"); + colourCmd->green = _info.srcFile->get_int(cmdPtr + "/value/green"); + colourCmd->blue = _info.srcFile->get_int(cmdPtr + "/value/blue"); + colourCmd->alpha = _info.srcFile->get_int(cmdPtr + "/value/alpha"); +} + +void BuildGameText::_textbox_set_alignment(std::vector &out, const std::string &cmdPtr) { + std::string alignment = _info.srcFile->get_string_lowercase(cmdPtr + "/value"); + + if(alignment == "center") { + out.push_back(0); + } else { // alignment == "left" + out.push_back(1); + } +} + +void BuildGameText::_textbox_unknown7(std::vector &out, const std::string &cmdPtr) { + out.push_back(_info.srcFile->get_int(cmdPtr + "/value")); +} + +void BuildGameText::_textbox_add_vertical_spacing(std::vector &out, const std::string &cmdPtr) { + out.push_back(_info.srcFile->get_int(cmdPtr + "/value")); +} + +void BuildGameText::_textbox_set_line_height(std::vector &out, const std::string &cmdPtr) { + out.push_back(_info.srcFile->get_int(cmdPtr + "/value")); +} + +void BuildGameText::_textbox_set_timer(std::vector &out, const std::string &cmdPtr) { + out.push_back(_info.srcFile->get_int(cmdPtr + "/value")); +} + +void BuildGameText::_textbox_allow_user_input(std::vector &out, const std::string &cmdPtr) { + out.push_back(_info.srcFile->get_int(cmdPtr + "/value")); +} + +void BuildGameText::_textbox_text(std::vector &out, const std::string &cmdPtr) { + std::string valueStr = _info.srcFile->get_string(cmdPtr + "/value"); + size_t valueStrLen = valueStr.size(); + int offset = out.size(); + + // Expand `out` to include the string. + out.resize(out.size() + valueStrLen + 1); // +1 for the NULL terminator. + + char *outText = reinterpret_cast(&out[offset]); + std::strncpy(outText, valueStr.c_str(), valueStrLen); // Copy text to out. + outText[valueStrLen] = '\0'; // Add Null terminator to the end of the string. +} + +void BuildGameText::_build_textbox() { + if(!_info.srcFile->has("/pages")) { + // No pages means it is an empty file! + FileHelper::write_empty_file(_info.dstPath, true); + return; + } + + std::vector out; + + size_t numberOfPages = _info.srcFile->length_of_array("/pages"); + + for(size_t page = 0; page < numberOfPages; page++) { + std::string pagePtr = "/pages/" + std::to_string(page); + size_t numberOfCmds = _info.srcFile->length_of_array(pagePtr); + for(size_t cmd = 0; cmd < numberOfCmds; cmd++) { + std::string cmdPtr = pagePtr + "/" + std::to_string(cmd); + std::string command = _info.srcFile->get_string(cmdPtr + "/command"); + + const std::unordered_map> cmdFunctions = { + { "SetFont", TEXTBOX_CMD_LAMDA(_textbox_set_font) }, + { "SetBorder", TEXTBOX_CMD_LAMDA(_textbox_set_border) }, + { "SetColour", TEXTBOX_CMD_LAMDA(_textbox_set_colour) }, + { "SetAlignment", TEXTBOX_CMD_LAMDA(_textbox_set_alignment) }, + { "Unknown7", TEXTBOX_CMD_LAMDA(_textbox_unknown7) }, + { "AddVerticalSpacing", TEXTBOX_CMD_LAMDA(_textbox_add_vertical_spacing) }, + { "SetLineHeight", TEXTBOX_CMD_LAMDA(_textbox_set_line_height) }, + { "SetTimer", TEXTBOX_CMD_LAMDA(_textbox_set_timer) }, + { "AllowUserInput", TEXTBOX_CMD_LAMDA(_textbox_allow_user_input) }, + { "Text", TEXTBOX_CMD_LAMDA(_textbox_text) }, + }; + + // Make sure the misc type has a function to extract it. + DebugHelper::assert(cmdFunctions.find(command) != cmdFunctions.end(), + "(BuildGameText::_build_textbox) Invalid textbox command: ", command); + + if(command != "Text") { + int commandIndex = std::find(TEXTBOX_COMMANDS.begin(), TEXTBOX_COMMANDS.end(), command) - TEXTBOX_COMMANDS.begin(); + out.push_back(commandIndex); // Add command byte to out + } + + cmdFunctions.at(command)(out, cmdPtr); + } + if(page < numberOfPages - 1) { + out.push_back(1); // cmd 0x01 means next-page. + } + } + + // TODO: Probably should pre-allocate the correct size. + if((out.size() & 0x7)) { + out.resize(DataHelper::align8(out.size()), 0); + } + + FileHelper::write_binary_file(out, _info.dstPath, true); +} diff --git a/tools/dkr_assets_tool_src/builder/buildTypes/buildGameText.h b/tools/dkr_assets_tool_src/builder/buildTypes/buildGameText.h new file mode 100644 index 00000000..996aad72 --- /dev/null +++ b/tools/dkr_assets_tool_src/builder/buildTypes/buildGameText.h @@ -0,0 +1,34 @@ +#pragma once + +#include "builder/buildInfo.h" +#include "misc/settings.hpp" + +#include "fileTypes/fonts.hpp" + +#include "helpers/debugHelper.h" +#include "helpers/fileHelper.h" +#include "helpers/jsonHelper.h" + +class BuildGameText { +public: + BuildGameText(DkrAssetsSettings &settings, BuildInfo &info); + ~BuildGameText(); +private: + DkrAssetsSettings &_settings; + BuildInfo &_info; + + void _build_dialog(); + + void _textbox_set_font(std::vector &out, const std::string &cmdPtr); + void _textbox_set_border(std::vector &out, const std::string &cmdPtr); + void _textbox_set_colour(std::vector &out, const std::string &cmdPtr); + void _textbox_set_alignment(std::vector &out, const std::string &cmdPtr); + void _textbox_unknown7(std::vector &out, const std::string &cmdPtr); + void _textbox_add_vertical_spacing(std::vector &out, const std::string &cmdPtr); + void _textbox_set_line_height(std::vector &out, const std::string &cmdPtr); + void _textbox_set_timer(std::vector &out, const std::string &cmdPtr); + void _textbox_allow_user_input(std::vector &out, const std::string &cmdPtr); + void _textbox_text(std::vector &out, const std::string &cmdPtr); + + void _build_textbox(); +}; diff --git a/tools/dkr_assets_tool_src/builder/buildTypes/buildLevelHeader.cpp b/tools/dkr_assets_tool_src/builder/buildTypes/buildLevelHeader.cpp new file mode 100644 index 00000000..c95b5f0a --- /dev/null +++ b/tools/dkr_assets_tool_src/builder/buildTypes/buildLevelHeader.cpp @@ -0,0 +1,277 @@ +#include "buildLevelHeader.h" + +#include "helpers/assetsHelper.h" + +#include // for strncpy + +BuildLevelHeader::BuildLevelHeader(DkrAssetsSettings &settings, BuildInfo &info) : _settings(settings), _info(info) { + _preload_c_context(); // For enums + + _build_level_name(); + + LevelHeader *header = new LevelHeader(); + + // World ID + std::string worldId = _info.srcFile->get_string("/world"); + header->world = _c_context.get_int_value_of_symbol(worldId); + + // Course Height + header->courseHeight = _info.srcFile->get_float("/course-height"); + + // Track ID + std::string trackId = _info.srcFile->get_string("/model"); + header->geometry = AssetsHelper::get_asset_index(_settings, "ASSET_LEVEL_MODELS", trackId); + + // Object Maps + std::string collectableMapId = _info.srcFile->get_string("/map-collectables"); + std::string objMap2Id = _info.srcFile->get_string("/map-2"); + header->collectablesObjMap = AssetsHelper::get_asset_index(_settings, "ASSET_LEVEL_OBJECT_MAPS", collectableMapId); + header->objectMap2 = AssetsHelper::get_asset_index(_settings, "ASSET_LEVEL_OBJECT_MAPS", objMap2Id); + + // Other + header->velocityCap = _info.srcFile->get_int("/max-velocity", 0); + header->cameraFOV = _info.srcFile->get_int("/fov", 60); + header->laps = _info.srcFile->get_int("/lap-count", 3); + + // Pulsing light data + header->pulseLightData = -1; // Default value. + std::string pulsatingLightId = _info.srcFile->get_string("/pulsating-lights"); + if(!pulsatingLightId.empty()) { + header->pulseLightData = AssetsHelper::get_asset_index(_settings, "ASSET_MISC", pulsatingLightId); + } + + // Race Type + std::string raceTypeId = _info.srcFile->get_string("/race-type"); + header->raceType = _c_context.get_int_value_of_symbol(raceTypeId); + + // Audio related + header->music = _info.srcFile->get_int("/music"); + header->instruments = _info.srcFile->get_int("/instruments"); + + const size_t MAX_NUM_OF_MISC_ASSETS = 7; + + // Misc assets + size_t numMiscAssets = 0; + if(_info.srcFile->has("/misc-assets")) { + numMiscAssets = _info.srcFile->length_of_array("/misc-assets"); + if(numMiscAssets > MAX_NUM_OF_MISC_ASSETS) { + DebugHelper::warn("Level Headers are limited to 7 misc assets! You have ", numMiscAssets, ". Only setting the first 7."); + numMiscAssets = MAX_NUM_OF_MISC_ASSETS; + } + for(size_t i = 0; i < numMiscAssets; i++) { + std::string miscAssetId = _info.srcFile->get_string("/misc-assets/" + std::to_string(i)); + header->miscAssets[i] = AssetsHelper::get_asset_index(_settings, "ASSET_MISC", miscAssetId); + } + } + + // Fill the rest of the misc asset slots with -1 + for(size_t i = numMiscAssets; i < MAX_NUM_OF_MISC_ASSETS; i++) { + header->miscAssets[i] = -1; + } + + // Vehicle info + std::string vehicle = _info.srcFile->get_string("/default-vehicle", "VEHICLE_CAR"); + header->vehicle = _c_context.get_int_value_of_symbol(vehicle); + + if(_info.srcFile->has("/avaliable-vehicles")) { + header->avaliableVehicles = _build_enum_bitfield("/avaliable-vehicles"); + } + + // AI levels + _build_ai_levels("/ai-levels/adv1", header->adv1AiLevels); + _build_ai_levels("/ai-levels/adv2", header->adv2AiLevels); + + // Weather + _build_weather("/weather", header->weather); + + // Fog + _build_fog("/fog", header->fog); + + + // Background related stuff + header->skybox = -1; // Default value + header->specialSkyTexture = -1; // Default value + if(_info.srcFile->has("/background/skybox/id")) { + std::string skyboxObjId = _info.srcFile->get_string("/background/skybox/id"); + header->skybox = AssetsHelper::get_asset_index(_settings, "ASSET_OBJECTS", skyboxObjId); + } else if (_info.srcFile->has("/background/skybox/special-sky")) { // Only used in wizpig 2 + header->specialSky = _info.srcFile->get_int("/background/skybox/special-sky"); + header->specialSkyTexture = _info.srcFile->get_int("/background/skybox/special-sky-texture"); + } + + header->bgColour[0] = _info.srcFile->get_int("/background/colour/red"); + header->bgColour[1] = _info.srcFile->get_int("/background/colour/green"); + header->bgColour[2] = _info.srcFile->get_int("/background/colour/blue"); + header->bgColourBottom[0] = _info.srcFile->get_int("/background/multiplayer/gradient-colour/bottom/red"); + header->bgColourBottom[1] = _info.srcFile->get_int("/background/multiplayer/gradient-colour/bottom/green"); + header->bgColourBottom[2] = _info.srcFile->get_int("/background/multiplayer/gradient-colour/bottom/blue"); + header->bgColourTop[0] = _info.srcFile->get_int("/background/multiplayer/gradient-colour/top/red"); + header->bgColourTop[1] = _info.srcFile->get_int("/background/multiplayer/gradient-colour/top/green"); + header->bgColourTop[2] = _info.srcFile->get_int("/background/multiplayer/gradient-colour/top/blue"); + + // Unknowns + header->unk1 = _info.srcFile->get_int("/unknown/unk1"); + header->unk2 = _info.srcFile->get_int("/unknown/unk2"); + header->unk3 = _info.srcFile->get_int("/unknown/unk3"); + + for(size_t i = 0; i < 4; i++) { + header->unk4[i] = _info.srcFile->get_int("/unknown/unk4/" + std::to_string(i)); + } + + for(size_t i = 0; i < 10; i++) { + header->unkC[i] = _info.srcFile->get_int("/unknown/unkC/" + std::to_string(i)); + } + + for(size_t i = 0; i < 10; i++) { + header->unk16[i] = _info.srcFile->get_int("/unknown/unk16/" + std::to_string(i)); + } + + header->unk2A = _info.srcFile->get_int("/unknown/unk2A"); + + for(size_t i = 0; i < 9; i++) { + header->unk2B[i] = _info.srcFile->get_int("/unknown/unk2B/" + std::to_string(i)); + } + + for(size_t i = 0; i < 5; i++) { + header->unk44[i] = _info.srcFile->get_int("/unknown/unk44/" + std::to_string(i)); + } + + for(size_t i = 0; i < 3; i++) { + header->unk4F[i] = _info.srcFile->get_int("/unknown/unk4F/" + std::to_string(i)); + } + + header->unk53 = _info.srcFile->get_int("/unknown/unk53"); + + header->unk56 = _info.srcFile->get_int("/unknown/unk56"); + header->unk57 = _info.srcFile->get_int("/unknown/unk57"); + header->unk58 = _info.srcFile->get_int("/unknown/unk58"); + header->unk59 = _info.srcFile->get_int("/unknown/unk59"); + header->unk5A = _info.srcFile->get_int("/unknown/unk5A"); + header->unk5C = _info.srcFile->get_int("/unknown/unk5C"); + header->unk5D = _info.srcFile->get_int("/unknown/unk5D"); + header->unk5E = _info.srcFile->get_int("/unknown/unk5E"); + header->unk60 = _info.srcFile->get_int("/unknown/unk60"); + header->unk62 = _info.srcFile->get_int("/unknown/unk62"); + header->unk64 = _info.srcFile->get_int("/unknown/unk64"); + header->unk66 = _info.srcFile->get_int("/unknown/unk66"); + header->unk68 = _info.srcFile->get_int("/unknown/unk68"); + header->unk6A = _info.srcFile->get_int("/unknown/unk6A"); + header->unk6B = _info.srcFile->get_int("/unknown/unk6B"); + header->unk6C = _info.srcFile->get_int("/unknown/unk6C"); + header->unk6D = _info.srcFile->get_int("/unknown/unk6D"); + header->unk6E = _info.srcFile->get_int("/unknown/unk6E"); + header->unk70 = _info.srcFile->get_int("/unknown/unk70"); + header->unk71 = _info.srcFile->get_int("/unknown/unk71"); + header->unk72 = _info.srcFile->get_int("/unknown/unk72"); + header->unk73 = _info.srcFile->get_int("/unknown/unk73"); + + header->unkA0 = _info.srcFile->get_int("/unknown/unkA0"); + header->unkA2 = _info.srcFile->get_int("/unknown/unkA2"); + header->unkA3 = _info.srcFile->get_int("/unknown/unkA3"); + + header->unkA8 = _info.srcFile->get_int("/unknown/unkA8"); + header->unkAA = _info.srcFile->get_int("/unknown/unkAA"); + + header->unkB0 = _info.srcFile->get_int("/unknown/unkB0"); + header->unkB2 = _info.srcFile->get_int("/unknown/unkB2"); + header->unkB3 = _info.srcFile->get_int("/unknown/unkB3"); + header->unkB4 = _info.srcFile->get_int("/unknown/unkB4"); + header->unkB5 = _info.srcFile->get_int("/unknown/unkB5"); + header->unkB6 = _info.srcFile->get_int("/unknown/unkB6"); + header->unkB7 = _info.srcFile->get_int("/unknown/unkB7"); + header->unkB8 = _info.srcFile->get_int("/unknown/unkB8"); + header->unkB9 = _info.srcFile->get_int("/unknown/unkB9"); + header->unkBC = _info.srcFile->get_int("/unknown/unkBC"); + header->unkBD = _info.srcFile->get_int("/unknown/unkBD"); + header->unkC4 = _info.srcFile->get_int("/unknown/unkC4"); + + FileHelper::write_binary_file(reinterpret_cast(header), sizeof(LevelHeader), + _info.dstPath, true); +} + +BuildLevelHeader::~BuildLevelHeader() { + +} + +void BuildLevelHeader::_build_weather(std::string ptr, LevelHeader_Weather &weather) { + weather.enable = _info.srcFile->get_int(ptr + "/enable"); + weather.type = _info.srcFile->get_int(ptr + "/type"); + weather.intensity = _info.srcFile->get_int(ptr + "/intensity"); + weather.opacity = _info.srcFile->get_int(ptr + "/opacity"); + weather.velocity[0] = _info.srcFile->get_int(ptr + "/velocity/x"); + weather.velocity[1] = _info.srcFile->get_int(ptr + "/velocity/y"); + weather.velocity[2] = _info.srcFile->get_int(ptr + "/velocity/z"); +} + +void BuildLevelHeader::_build_ai_levels(std::string ptr, LevelHeader_AiLevels &aiLevels) { + aiLevels.baseAiLevel = _info.srcFile->get_int(ptr + "/base"); + aiLevels.silverCoinsAiLevel = _info.srcFile->get_int(ptr + "/silver-coins"); + aiLevels.completedAiLevel = _info.srcFile->get_int(ptr + "/completed"); + aiLevels.tracksModeAiLevel = _info.srcFile->get_int(ptr + "/tracks-mode"); + aiLevels.trophyRaceAiLevel = _info.srcFile->get_int(ptr + "/trophy-race"); +} + +void BuildLevelHeader::_build_fog(std::string ptr, LevelHeader_Fog &fogInfo) { + fogInfo.near = _info.srcFile->get_int(ptr + "/near"); + fogInfo.far = _info.srcFile->get_int(ptr + "/far"); + fogInfo.colour[0] = _info.srcFile->get_int(ptr + "/colour/red"); + fogInfo.colour[1] = _info.srcFile->get_int(ptr + "/colour/green"); + fogInfo.colour[2] = _info.srcFile->get_int(ptr + "/colour/blue"); +} + +template +T BuildLevelHeader::_build_enum_bitfield(std::string ptr) { + T out = 0; + + size_t numValues = _info.srcFile->length_of_array(ptr); + + for(size_t i = 0; i < numValues; i++) { + std::string enumSym = _info.srcFile->get_string(ptr + "/" + std::to_string(i)); + out |= 1 << _c_context.get_int_value_of_symbol(enumSym); + } + + return out; +} + +void BuildLevelHeader::_build_level_name() { + DeferredAssetInfo deferInfo = AssetsHelper::get_deferred_asset_info(_settings, "ASSET_LEVEL_NAMES"); + + CEnum *langEnum = _c_context.get_enum("Language"); + + size_t numLanguages = langEnum->get_member_count(); + + std::vector out; + + // TODO: Use the English name as the default, instead of an empty string. + + for(size_t i = 0; i < numLanguages; i++) { + std::string langName; + langEnum->get_symbol_of_value(i, langName); + + std::string levelLangName = _info.srcFile->get_string("/name/" + langName); + + size_t langNameSize = levelLangName.size(); + size_t offset = out.size(); + out.resize(offset + langNameSize + 1); // Resize out to fit new string. + char *outLangName = reinterpret_cast(&out[offset]); + strncpy(outLangName, levelLangName.c_str(), langNameSize); + } + + fs::path outPath = _info.dstPath.parent_path() / deferInfo.outputPath / _info.dstPath.filename(); + + FileHelper::write_binary_file(out, outPath, true); +} + +void BuildLevelHeader::_preload_c_context() { + fs::path includeFolder = _settings.pathToRepo / "include/"; + + // Load all enums from these files. + fs::path enumPaths[] = { + includeFolder / "enums.h" + }; + + for(fs::path &enumPath : enumPaths) { + CEnumsHelper::load_enums_from_file(&_c_context, enumPath); + } +} + diff --git a/tools/dkr_assets_tool_src/builder/buildTypes/buildLevelHeader.h b/tools/dkr_assets_tool_src/builder/buildTypes/buildLevelHeader.h new file mode 100644 index 00000000..1b1b5ad8 --- /dev/null +++ b/tools/dkr_assets_tool_src/builder/buildTypes/buildLevelHeader.h @@ -0,0 +1,34 @@ +#pragma once + +#include "builder/buildInfo.h" +#include "misc/settings.hpp" + +#include "fileTypes/fonts.hpp" + +#include "helpers/debugHelper.h" +#include "helpers/fileHelper.h" +#include "helpers/jsonHelper.h" +#include "helpers/c/cContext.h" +#include "fileTypes/levelHeader.hpp" + +class BuildLevelHeader { +public: + BuildLevelHeader(DkrAssetsSettings &settings, BuildInfo &info); + ~BuildLevelHeader(); +private: + DkrAssetsSettings &_settings; + BuildInfo &_info; + + CContext _c_context; // C Code context. (For loading enums & structs) + + void _build_weather(std::string ptr, LevelHeader_Weather &weather); + void _build_ai_levels(std::string ptr, LevelHeader_AiLevels &aiLevels); + void _build_fog(std::string ptr, LevelHeader_Fog &fogInfo); + + template + T _build_enum_bitfield(std::string ptr); + + void _build_level_name(); + + void _preload_c_context(); +}; diff --git a/tools/dkr_assets_tool_src/builder/buildTypes/buildLevelModel.cpp b/tools/dkr_assets_tool_src/builder/buildTypes/buildLevelModel.cpp new file mode 100644 index 00000000..bb73c3b7 --- /dev/null +++ b/tools/dkr_assets_tool_src/builder/buildTypes/buildLevelModel.cpp @@ -0,0 +1,15 @@ +#include "buildLevelModel.h" + +BuildLevelModel::BuildLevelModel(DkrAssetsSettings &settings, BuildInfo &info) : _settings(settings), _info(info) { + std::string rawPath = info.srcFile->get_string("/raw"); + + DebugHelper::assert(!rawPath.empty(), "(BuildLevelModel::BuildLevelModel) \"raw\" not specified!"); + + // Copy file from rawPath to destination path. + FileHelper::copy(_info.localDirectory / rawPath, info.dstPath); +} + +BuildLevelModel::~BuildLevelModel() { + +} + diff --git a/tools/dkr_assets_tool_src/builder/buildTypes/buildLevelModel.h b/tools/dkr_assets_tool_src/builder/buildTypes/buildLevelModel.h new file mode 100644 index 00000000..31b84cdc --- /dev/null +++ b/tools/dkr_assets_tool_src/builder/buildTypes/buildLevelModel.h @@ -0,0 +1,19 @@ +#pragma once + +#include "builder/buildInfo.h" +#include "misc/settings.hpp" + +#include "fileTypes/fonts.hpp" + +#include "helpers/debugHelper.h" +#include "helpers/fileHelper.h" +#include "helpers/jsonHelper.h" + +class BuildLevelModel { +public: + BuildLevelModel(DkrAssetsSettings &settings, BuildInfo &info); + ~BuildLevelModel(); +private: + DkrAssetsSettings &_settings; + BuildInfo &_info; +}; diff --git a/tools/dkr_assets_tool_src/builder/buildTypes/buildLevelObjectTranslationTable.cpp b/tools/dkr_assets_tool_src/builder/buildTypes/buildLevelObjectTranslationTable.cpp new file mode 100644 index 00000000..facf6ae6 --- /dev/null +++ b/tools/dkr_assets_tool_src/builder/buildTypes/buildLevelObjectTranslationTable.cpp @@ -0,0 +1,45 @@ +#include "buildLevelObjectTranslationTable.h" + +// Defines LOTT_ENTRY and LOTT_SIZE +#include "fileTypes/levelObjectTranslationTable.hpp" + +#include "helpers/assetsHelper.h" + +BuildLOTT::BuildLOTT(DkrAssetsSettings &settings, BuildInfo &info) : _settings(settings), _info(info) { + LOTT_ENTRY entries[LOTT_SIZE]; + + size_t numberOfEntries = _info.srcFile->length_of_array("/table"); + + DebugHelper::assert(numberOfEntries <= LOTT_SIZE, + "(BuildLOTT::BuildLOTT) The Level-Object Translation Table has too many entries! Can only have ", LOTT_SIZE, " entries."); + + for(size_t i = 0; i < numberOfEntries; i++) { + std::string ptr = "/table/" + std::to_string(i); + if(_info.srcFile->is_value_null(ptr)) { + entries[i] = LOTT_SIZE; + continue; + } + // Not null. + std::string entryId = _info.srcFile->get_string(ptr); + if(entryId.empty()) { + entries[i] = LOTT_SIZE; + continue; + } + + // Not empty. + entries[i] = AssetsHelper::get_asset_index(_settings, "ASSET_OBJECTS", entryId); + } + + // Fill rest of the entries as empty slots. + for(size_t i = numberOfEntries; i < LOTT_SIZE; i++) { + entries[i] = LOTT_SIZE; + } + + FileHelper::write_binary_file(reinterpret_cast(entries), sizeof(LOTT_ENTRY) * LOTT_SIZE, + _info.dstPath, true); +} + +BuildLOTT::~BuildLOTT() { + +} + diff --git a/tools/dkr_assets_tool_src/builder/buildTypes/buildLevelObjectTranslationTable.h b/tools/dkr_assets_tool_src/builder/buildTypes/buildLevelObjectTranslationTable.h new file mode 100644 index 00000000..34232652 --- /dev/null +++ b/tools/dkr_assets_tool_src/builder/buildTypes/buildLevelObjectTranslationTable.h @@ -0,0 +1,19 @@ +#pragma once + +#include "builder/buildInfo.h" +#include "misc/settings.hpp" + +#include "fileTypes/fonts.hpp" + +#include "helpers/debugHelper.h" +#include "helpers/fileHelper.h" +#include "helpers/jsonHelper.h" + +class BuildLOTT { +public: + BuildLOTT(DkrAssetsSettings &settings, BuildInfo &info); + ~BuildLOTT(); +private: + DkrAssetsSettings &_settings; + BuildInfo &_info; +}; diff --git a/tools/dkr_assets_tool_src/builder/buildTypes/buildMenuText.cpp b/tools/dkr_assets_tool_src/builder/buildTypes/buildMenuText.cpp new file mode 100644 index 00000000..708f939c --- /dev/null +++ b/tools/dkr_assets_tool_src/builder/buildTypes/buildMenuText.cpp @@ -0,0 +1,64 @@ +#include "buildMenuText.h" + +#include // for strncpy + +#include "helpers/assetsHelper.h" +#include "helpers/dataHelper.h" + +BuildMenuText::BuildMenuText(DkrAssetsSettings &settings, BuildInfo &info) : _settings(settings), _info(info) { + JsonFile *menuTextSection = AssetsHelper::get_asset_section_json(_settings, "ASSET_MENU_TEXT"); + + std::vector menuTextOrder; + menuTextSection->get_array("/menu-text-build-ids", menuTextOrder); + + size_t numberOfEntries = menuTextOrder.size(); + + size_t outSize = (numberOfEntries * 4) + _get_total_string_lengths(menuTextOrder); + outSize = DataHelper::align8(outSize); // Make sure the output is 8-byte aligned. + + std::vector out(outSize); + + be_uint32_t *offsets = reinterpret_cast(&out[0]); + + size_t currentTextOffset = numberOfEntries * 4; + + for(size_t i = 0; i < numberOfEntries; i++) { + const std::string &entryId = menuTextOrder[i]; + const std::string ptr = "/sections/" + entryId; + if(!_info.srcFile->has(ptr)) { + offsets[i] = 0xFFFFFFFF; // Null entry. + continue; + } + + offsets[i] = currentTextOffset; + + std::string entryStr = _info.srcFile->get_string(ptr); + char *text = reinterpret_cast(&out[currentTextOffset]); + std::strncpy(text, entryStr.c_str(), entryStr.size()); + currentTextOffset += entryStr.size() + 1; + + // Shouldn't need to write the null terminator? + } + + FileHelper::write_binary_file(out, _info.dstPath, true); +} + +BuildMenuText::~BuildMenuText() { + +} + +size_t BuildMenuText::_get_total_string_lengths(std::vector &menuTextOrder) { + size_t totalLength = 0; + + for(std::string &entryId : menuTextOrder) { + const std::string ptr = "/sections/" + entryId; + if(!_info.srcFile->has(ptr)) { + continue; + } + // +1 for null terminator + totalLength += _info.srcFile->length_of_string(ptr) + 1; + } + + return totalLength; +} + diff --git a/tools/dkr_assets_tool_src/builder/buildTypes/buildMenuText.h b/tools/dkr_assets_tool_src/builder/buildTypes/buildMenuText.h new file mode 100644 index 00000000..fc336b1b --- /dev/null +++ b/tools/dkr_assets_tool_src/builder/buildTypes/buildMenuText.h @@ -0,0 +1,23 @@ +#pragma once + +#include + +#include "builder/buildInfo.h" +#include "misc/settings.hpp" + +#include "fileTypes/fonts.hpp" + +#include "helpers/debugHelper.h" +#include "helpers/fileHelper.h" +#include "helpers/jsonHelper.h" + +class BuildMenuText { +public: + BuildMenuText(DkrAssetsSettings &settings, BuildInfo &info); + ~BuildMenuText(); +private: + DkrAssetsSettings &_settings; + BuildInfo &_info; + + size_t _get_total_string_lengths(std::vector &menuTextOrder); +}; diff --git a/tools/dkr_assets_tool_src/builder/buildTypes/buildMisc.cpp b/tools/dkr_assets_tool_src/builder/buildTypes/buildMisc.cpp new file mode 100644 index 00000000..71124290 --- /dev/null +++ b/tools/dkr_assets_tool_src/builder/buildTypes/buildMisc.cpp @@ -0,0 +1,227 @@ +#include "buildMisc.h" + +#include "helpers/dataHelper.h" +#include "helpers/assetsHelper.h" +#include "helpers/miscHelper.h" + +#include +#include +#include // for std::strcpy & std::memset + +#define MISC_ARGS BuildInfo &info, size_t &outDataSize +#define MISC_LAMDA(func) [this](MISC_ARGS) { return func(info, outDataSize); } + +typedef void (*MiscFuncPtr)(MISC_ARGS); + +BuildMisc::BuildMisc(DkrAssetsSettings &settings, BuildInfo &info) : _settings(settings), _info(info) { + //std::string rawPath = info.srcFile->get_string("raw"); + + std::string miscType = info.srcFile->get_string("/misc-type"); + + const std::unordered_map> miscFunctions = { + { "Binary", MISC_LAMDA(_build_binary) }, + { "RacerStat", MISC_LAMDA(_build_racer_stat) }, + { "RacerAcceleration", MISC_LAMDA(_build_racer_acceleration) }, + { "TrackIds", MISC_LAMDA(_build_track_ids) }, + { "MagicCodes", MISC_LAMDA(_build_magic_codes) }, + { "TitleScreenDemos", MISC_LAMDA(_build_title_screen_demos) }, + }; + + size_t outDataSize; + uint8_t *outData = miscFunctions.at(miscType)(info, outDataSize); + + if(outData == nullptr) { + return; + } + + FileHelper::write_binary_file(outData, outDataSize, info.dstPath, true); + delete outData; +} + +BuildMisc::~BuildMisc() { + +} + +uint8_t *BuildMisc::_build_binary(BuildInfo &info, size_t &outDataSize) { + std::string rawPath = info.srcFile->get_string("/raw"); + + DebugHelper::assert(!rawPath.empty(), "(BuildMisc::_build_binary) \"raw\" not specified!"); + + // Copy file from rawPath to destination path. + FileHelper::copy(_info.localDirectory / rawPath, info.dstPath); + return nullptr; +} + +uint8_t *BuildMisc::_build_racer_stat(BuildInfo &info, size_t &outDataSize) { + // Load enums + _preload_c_context(); + + CEnum *characters = _c_context.get_enum("Character"); + + int numberOfCharacters; + + if(!characters->get_value_of_member("NUMBER_OF_CHARACTERS", numberOfCharacters)) { + // Fallback to get_member_count if "NUMBER_OF_CHARACTERS" is not specified. + numberOfCharacters = characters->get_member_count(); + } + + outDataSize = sizeof(be_float) * numberOfCharacters; + uint8_t *out = new uint8_t[outDataSize]; + std::memset(out, 0, outDataSize); // zero out memory. + be_float *values = reinterpret_cast(out); + + for(int i = 0; i < numberOfCharacters; i++) { + std::string charId; + if(!characters->get_symbol_of_value(i, charId)) { + values[i] = -1; // Could not get symbol for character, so set it to -1 to indicate so. + continue; + } + values[i] = info.srcFile->get_float("/values/" + charId); + } + + return out; +} + +uint8_t *BuildMisc::_build_racer_acceleration(BuildInfo &info, size_t &outDataSize) { + size_t numberOfValues = _info.srcFile->length_of_array("/values"); + + outDataSize = sizeof(be_float) * numberOfValues; + outDataSize = DataHelper::align8(outDataSize); // Make sure the data is 16-byte aligned. + + uint8_t *out = new uint8_t[outDataSize]; + std::memset(out, 0, outDataSize); // zero out memory. + + be_float *values = reinterpret_cast(out); + + for(size_t i = 0; i < numberOfValues; i++) { + values[i] = info.srcFile->get_float("/values/" + std::to_string(i)); + } + + return out; +} + +uint8_t *BuildMisc::_build_track_ids(BuildInfo &info, size_t &outDataSize) { + size_t numberOfIds = _info.srcFile->length_of_array("/ids"); + outDataSize = DataHelper::align4(numberOfIds); + uint8_t *out = new uint8_t[outDataSize]; + std::memset(out, 0, outDataSize); // zero out memory. + + for(size_t i = 0; i < numberOfIds; i++) { + std::string ptr = "/ids/" + std::to_string(i); + if(info.srcFile->is_value_null(ptr)) { + out[i] = 0xFF; // Marks the end of the list for some files. + continue; + } + std::string levelBuildId = info.srcFile->get_string(ptr); + out[i] = AssetsHelper::get_asset_index(_settings, "ASSET_LEVEL_HEADERS", levelBuildId); + } + + return out; +} + +uint8_t *BuildMisc::_build_magic_codes(BuildInfo &info, size_t &outDataSize) { + size_t numberOfCheats = _info.srcFile->length_of_array("/cheats"); + + // The first two bytes are the total number of cheats + outDataSize = sizeof(be_int16_t); + + // Then comes the lookup table. + outDataSize += (numberOfCheats) * sizeof(be_int16_t) * 2; + + size_t offsetToText = outDataSize; + + // First loop to figure out the total size and offsets. + for(size_t i = 0; i < numberOfCheats; i++) { + std::string cheatPtr = "/cheats/" + std::to_string(i); + + // +1 for null terminator + size_t codeLen = _info.srcFile->length_of_string(cheatPtr + "/code") + 1; + size_t descLen = _info.srcFile->length_of_string(cheatPtr + "/description") + 1; + + outDataSize += codeLen + descLen; + } + + // Make sure cheats data is 16-byte aligned. + outDataSize = DataHelper::align16(outDataSize); + + uint8_t *out = new uint8_t[outDataSize]; + std::memset(out, 0, outDataSize); // zero out memory. + be_int16_t *cheatsTable = reinterpret_cast(&out[0]); + + // Set number of cheats. + cheatsTable[0] = numberOfCheats; + + CheatsTableEntry *entries = reinterpret_cast(&cheatsTable[1]); + + // Second loop to write the data for each cheat entry. + for(size_t i = 0; i < numberOfCheats; i++) { + std::string cheatPtr = "/cheats/" + std::to_string(i); + std::string code = _info.srcFile->get_string(cheatPtr + "/code"); + std::string description = _info.srcFile->get_string(cheatPtr + "/description"); + + entries[i].codeOffset = offsetToText; + offsetToText += code.size() + 1; // +1 for null terminator + entries[i].descOffset = offsetToText; + offsetToText += description.size() + 1; // +1 for null terminator + + char *codeOut = reinterpret_cast(&out[entries[i].codeOffset]); + char *descriptionOut = reinterpret_cast(&out[entries[i].descOffset]); + + // Copy strings to out. + std::strcpy(codeOut, code.c_str()); + std::strcpy(descriptionOut, description.c_str()); + } + + if(_settings.debugBuildKeepUncompressed) { + fs::path unencryptedCheatsPath = _settings.pathToBuild / _settings.dkrVersion / "debug/cheats" / info.dstPath.filename(); + FileHelper::write_binary_file(out, outDataSize, unencryptedCheatsPath, true); + } + + MiscHelper::process_cheats_encryption(out, outDataSize); // Encrypt the cheats data. + + return out; +} + +uint8_t *BuildMisc::_build_title_screen_demos(BuildInfo &info, size_t &outDataSize) { + size_t numberOfEntries = _info.srcFile->length_of_array("/entries"); + + size_t entriesSize = ((numberOfEntries + 1) * 3); + outDataSize = DataHelper::align8(entriesSize); + + uint8_t *out = new uint8_t[outDataSize]; + std::memset(out, 0, outDataSize); // zero out memory. + + TitleScreenDemos *demos = reinterpret_cast(out); + + for(size_t i = 0; i < numberOfEntries; i++) { + std::string ptr = "/entries/" + std::to_string(i); + std::string levelBuildId = _info.srcFile->get_string(ptr + "/level"); + demos[i].levelId = AssetsHelper::get_asset_index(_settings, "ASSET_LEVEL_HEADERS", levelBuildId); + + // Different default values for the title screen. + int defaultNumberOfPlayers = 0; + int defaultCutsceneId = 0; + if(levelBuildId != "ASSET_LEVEL_TITLESCREENSEQUENCE") { + defaultNumberOfPlayers = -2; + defaultCutsceneId = 100; + } + demos[i].numberOfPlayers = _info.srcFile->get_int(ptr + "/number-of-players", defaultNumberOfPlayers); + demos[i].cutsceneId = _info.srcFile->get_int(ptr + "/cutscene-id", defaultCutsceneId); + } + demos[numberOfEntries].levelId = 0xFF; // Mark end of data with 0xFF. + + return out; +} + +void BuildMisc::_preload_c_context() { + fs::path includeFolder = _settings.pathToRepo / "include/"; + + // Load all enums from these files. + fs::path enumPaths[] = { + includeFolder / "enums.h" + }; + + for(fs::path &enumPath : enumPaths) { + CEnumsHelper::load_enums_from_file(&_c_context, enumPath); + } +} \ No newline at end of file diff --git a/tools/dkr_assets_tool_src/builder/buildTypes/buildMisc.h b/tools/dkr_assets_tool_src/builder/buildTypes/buildMisc.h new file mode 100644 index 00000000..2a0080f2 --- /dev/null +++ b/tools/dkr_assets_tool_src/builder/buildTypes/buildMisc.h @@ -0,0 +1,32 @@ +#pragma once + +#include "builder/buildInfo.h" +#include "misc/settings.hpp" + +#include "fileTypes/misc.hpp" + +#include "helpers/debugHelper.h" +#include "helpers/fileHelper.h" +#include "helpers/jsonHelper.h" +#include "helpers/miscHelper.h" +#include "helpers/c/cContext.h" + +class BuildMisc { +public: + BuildMisc(DkrAssetsSettings &settings, BuildInfo &info); + ~BuildMisc(); +private: + DkrAssetsSettings &_settings; + BuildInfo &_info; + CContext _c_context; + + uint8_t *_build_binary(BuildInfo &info, size_t &outDataSize); + uint8_t *_build_racer_stat(BuildInfo &info, size_t &outDataSize); + uint8_t *_build_racer_acceleration(BuildInfo &info, size_t &outDataSize); + uint8_t *_build_track_ids(BuildInfo &info, size_t &outDataSize); + uint8_t *_build_magic_codes(BuildInfo &info, size_t &outDataSize); + uint8_t *_build_title_screen_demos(BuildInfo &info, size_t &outDataSize); + uint8_t *_build_boss_data(BuildInfo &info, size_t &outDataSize); + + void _preload_c_context(); // For enums +}; diff --git a/tools/dkr_assets_tool_src/builder/buildTypes/buildObjectAnimation.cpp b/tools/dkr_assets_tool_src/builder/buildTypes/buildObjectAnimation.cpp new file mode 100644 index 00000000..cd51f575 --- /dev/null +++ b/tools/dkr_assets_tool_src/builder/buildTypes/buildObjectAnimation.cpp @@ -0,0 +1,15 @@ +#include "buildObjectAnimation.h" + +BuildObjectAnimation::BuildObjectAnimation(DkrAssetsSettings &settings, BuildInfo &info) : _settings(settings), _info(info) { + std::string rawPath = info.srcFile->get_string("/raw"); + + DebugHelper::assert(!rawPath.empty(), "(BuildObjectAnimation::BuildObjectAnimation) \"raw\" not specified!"); + + // Copy file from rawPath to destination path. + FileHelper::copy(_info.localDirectory / rawPath, info.dstPath); +} + +BuildObjectAnimation::~BuildObjectAnimation() { + +} + diff --git a/tools/dkr_assets_tool_src/builder/buildTypes/buildObjectAnimation.h b/tools/dkr_assets_tool_src/builder/buildTypes/buildObjectAnimation.h new file mode 100644 index 00000000..c9a48505 --- /dev/null +++ b/tools/dkr_assets_tool_src/builder/buildTypes/buildObjectAnimation.h @@ -0,0 +1,19 @@ +#pragma once + +#include "builder/buildInfo.h" +#include "misc/settings.hpp" + +#include "fileTypes/fonts.hpp" + +#include "helpers/debugHelper.h" +#include "helpers/fileHelper.h" +#include "helpers/jsonHelper.h" + +class BuildObjectAnimation { +public: + BuildObjectAnimation(DkrAssetsSettings &settings, BuildInfo &info); + ~BuildObjectAnimation(); +private: + DkrAssetsSettings &_settings; + BuildInfo &_info; +}; diff --git a/tools/dkr_assets_tool_src/builder/buildTypes/buildObjectHeader.cpp b/tools/dkr_assets_tool_src/builder/buildTypes/buildObjectHeader.cpp new file mode 100644 index 00000000..1f98cd46 --- /dev/null +++ b/tools/dkr_assets_tool_src/builder/buildTypes/buildObjectHeader.cpp @@ -0,0 +1,229 @@ +#include "buildObjectHeader.h" + +#include + +#include "helpers/assetsHelper.h" +#include "helpers/stringHelper.h" +#include "helpers/dataHelper.h" +#include "fileTypes/objectHeader.hpp" + +BuildObjectHeader::BuildObjectHeader(DkrAssetsSettings &settings, BuildInfo &info) : _settings(settings), _info(info) { + _preload_c_context(); + + // Get the counts for each section. + size_t numberOfModels = _info.srcFile->length_of_array("/models"); + size_t numberOfVehicleParts = _info.srcFile->length_of_array("/vehicle-parts"); + size_t numberOfParticles = _info.srcFile->length_of_array("/particles"); + size_t numberOfJunkBytes = _info.srcFile->length_of_array("/junk-data"); + + // Calculate size & offsets to the different sections. + size_t outSize = sizeof(ObjectHeader); + size_t offsetToModels = outSize; + outSize += numberOfModels * sizeof(be_int32_t); // model ids + size_t offsetToVehiclePartIds = outSize; + outSize += numberOfVehicleParts * sizeof(be_int32_t); // Vehicle part ids + size_t offsetToVehiclePartIndices = outSize; + outSize += DataHelper::align8(numberOfVehicleParts * sizeof(uint8_t)); // Vehicle part indices + size_t offsetToParticles = outSize; + outSize += numberOfParticles * sizeof(ObjectHeaderParticleData); // Particles + size_t offsetToJunkData = outSize; + outSize += numberOfJunkBytes; // random bytes + + std::vector out(outSize); + + // Make pointers to the different sections based on the offsets. + ObjectHeader *objectHeader = reinterpret_cast(&out[0]); + be_int32_t *modelIds = reinterpret_cast(&out[offsetToModels]); + be_int32_t *vehiclePartIds = reinterpret_cast(&out[offsetToVehiclePartIds]); + uint8_t *vehiclePartIndices = &out[offsetToVehiclePartIndices]; + ObjectHeaderParticleData *particles = reinterpret_cast(&out[offsetToParticles]); + uint8_t *junkData = &out[offsetToJunkData]; + + std::string modelType = _info.srcFile->get_string("/model-type"); + + /** Object Header **/ + + // Offsets to data + objectHeader->modelIds = offsetToModels; + objectHeader->vehiclePartIds = offsetToVehiclePartIds; + objectHeader->vehiclePartIndices = offsetToVehiclePartIndices; + objectHeader->objectParticles = offsetToParticles; + objectHeader->unk20 = offsetToJunkData; + objectHeader->unk24 = offsetToJunkData; + + // Behavior + if(_info.srcFile->has("/behavior")) { + std::string behavior = _info.srcFile->get_string("/behavior"); + objectHeader->behaviorId = _c_context.get_int_value_of_symbol(behavior); + } else { + objectHeader->behaviorId = -1; + } + + // Model Type + objectHeader->modelType = _c_context.get_int_value_of_symbol(modelType); + + // Flags + objectHeader->flags = _string_to_flags(); + + // Internal Name + std::string internalName = _info.srcFile->get_string("/internal-name"); + std::strncpy(objectHeader->internalName, internalName.c_str(), internalName.size()); + + // Floats + objectHeader->shadowScale = _info.srcFile->get_float("/shadow-scale"); + objectHeader->scale = _info.srcFile->get_float("/scale"); + objectHeader->shadeBrightness = _info.srcFile->get_float("/shade-brightness"); + objectHeader->shadeAmbient = _info.srcFile->get_float("/shade-ambient"); + + // Unknowns + objectHeader->unk0 = _info.srcFile->get_int("/unknown/unk0"); + objectHeader->unk8 = _info.srcFile->get_float("/unknown/unk8"); + objectHeader->unk34 = _info.srcFile->get_int("/unknown/unk34"); + objectHeader->unk38 = _info.srcFile->get_int("/unknown/unk38"); + objectHeader->unk3A = _info.srcFile->get_int("/unknown/unk3A"); + objectHeader->unk3B = _info.srcFile->get_int("/unknown/unk3B"); + objectHeader->unk3C = _info.srcFile->get_int("/unknown/unk3C"); + objectHeader->unk3D = _info.srcFile->get_int("/unknown/unk3D"); + objectHeader->unk42 = _info.srcFile->get_int("/unknown/unk42"); + objectHeader->unk44 = _info.srcFile->get_int("/unknown/unk44"); + objectHeader->unk46 = _info.srcFile->get_int("/unknown/unk46"); + objectHeader->unk48 = _info.srcFile->get_int("/unknown/unk48"); + objectHeader->unk4A = _info.srcFile->get_int("/unknown/unk4A"); + objectHeader->unk4C = _info.srcFile->get_int("/unknown/unk4C"); + objectHeader->unk50 = _info.srcFile->get_int("/unknown/unk50"); + objectHeader->unk52 = _info.srcFile->get_int("/unknown/unk52"); + objectHeader->unk58 = _info.srcFile->get_int("/unknown/unk58"); + objectHeader->unk59 = _info.srcFile->get_int("/unknown/unk59"); + objectHeader->unk5B = _info.srcFile->get_int("/unknown/unk5B"); + objectHeader->unk5C = _info.srcFile->get_int("/unknown/unk5C"); + objectHeader->unk5D = _info.srcFile->get_int("/unknown/unk5D"); + objectHeader->unk5E = _info.srcFile->get_int("/unknown/unk5E"); + objectHeader->unk5F = _info.srcFile->get_int("/unknown/unk5F"); + objectHeader->unk70 = _info.srcFile->get_int("/unknown/unk70"); + objectHeader->unk71 = _info.srcFile->get_int("/unknown/unk71"); + objectHeader->unk72 = _info.srcFile->get_int("/unknown/unk72"); + objectHeader->unk73 = _info.srcFile->get_int("/unknown/unk73"); + objectHeader->unk74 = _info.srcFile->get_int("/unknown/unk74"); + objectHeader->unk75 = _info.srcFile->get_int("/unknown/unk75"); + objectHeader->unk76 = _info.srcFile->get_int("/unknown/unk76"); + objectHeader->unk77 = _info.srcFile->get_int("/unknown/unk77"); + + // Other + objectHeader->shadowGroup = _info.srcFile->get_int("/shadow-group"); + objectHeader->waterEffectGroup = _info.srcFile->get_int("/water-effect-group"); + objectHeader->shadeAngleY = _info.srcFile->get_int("/shade-angle-y"); + objectHeader->shadeAngleZ = _info.srcFile->get_int("/shade-angle-z"); + objectHeader->drawDistance = _info.srcFile->get_int("/draw-distance"); + + + objectHeader->numberOfModelIds = numberOfModels; + objectHeader->numberOfVehicleParts = numberOfVehicleParts; + objectHeader->numberOfParticles = numberOfParticles; + + + /** Model IDs **/ + std::string assetSection; + + switch(objectHeader->modelType) { + case OBJECT_MODEL_TYPE_3D_MODEL: + assetSection = "ASSET_OBJECT_MODELS"; + break; + case OBJECT_MODEL_TYPE_MISC: + assetSection = "ASSET_TEXTURES_2D"; + break; + default: + assetSection = "ASSET_SPRITES"; + break; + } + + for(size_t i = 0; i < numberOfModels; i++) { + std::string modelBuildId = _info.srcFile->get_string("/models/" + std::to_string(i)); + modelIds[i] = AssetsHelper::get_asset_index(_settings, assetSection, modelBuildId); + } + + /** Vehicle Parts **/ + for(size_t i = 0; i < numberOfVehicleParts; i++) { + vehiclePartIds[i] = _info.srcFile->get_int("/vehicle-parts/" + std::to_string(i)); + vehiclePartIndices[i] = _info.srcFile->get_int("/vehicle-part-indices/" + std::to_string(i)); + } + + if(_info.srcFile->has("/vehicle-part-indices-junk-bytes")) { + size_t numberOfJunkVehiclePartsIndexBytes = _info.srcFile->length_of_array("/vehicle-part-indices-junk-bytes"); + for(size_t i = 0; i < numberOfJunkVehiclePartsIndexBytes; i++) { + vehiclePartIndices[i + numberOfVehicleParts] = _info.srcFile->get_int("/vehicle-part-indices-junk-bytes/" + std::to_string(i)); + } + } + + /** Particles **/ + for(size_t i = 0; i < numberOfParticles; i++) { + std::string ptr = "/particles/" + std::to_string(i); + + // Not sure what this special case actually is. Just that the args are different. + bool isSpecialCase = _info.srcFile->get_bool(ptr + "/special-case"); + if(isSpecialCase) { + particles[i].lower = _info.srcFile->get_int(ptr + "/junk-data"); // Not actually used I think. + particles[i].upper_w.s0_s = -1; // Marks this as the special case + particles[i].upper_w.s1_b.b0 = _info.srcFile->get_int(ptr + "/arg1"); + particles[i].upper_w.s1_b.b1 = _info.srcFile->get_int(ptr + "/arg2"); + } else { + particles[i].upper_w.s0_b.b0 = _info.srcFile->get_int(ptr + "/arg1"); + particles[i].upper_w.s0_b.b1 = _info.srcFile->get_int(ptr + "/arg2"); + particles[i].upper_w.s1_s = _info.srcFile->get_int(ptr + "/arg3"); + particles[i].lower_w.s0_s = _info.srcFile->get_int(ptr + "/arg4"); + particles[i].lower_w.s1_s = _info.srcFile->get_int(ptr + "/arg5"); + } + } + + /** Junk Data **/ + for(size_t i = 0; i < numberOfJunkBytes; i++) { + junkData[i] = _info.srcFile->get_int("/junk-data/" + std::to_string(i)); + } + + // Write Object Header. + FileHelper::write_binary_file(out, _info.dstPath, true); +} + +BuildObjectHeader::~BuildObjectHeader() { + +} + +be_uint16_t BuildObjectHeader::_string_to_flags() { + size_t flagCount = _info.srcFile->length_of_array("/flags"); + + if(flagCount < 1) { + return 0; + } + + uint16_t result = 0; + + for(size_t i = 0; i < flagCount; i++) { + std::string curFlag = _info.srcFile->get_string_uppercase("/flags/" + std::to_string(i)); + uint16_t flagVal; + if(StringHelper::starts_with(curFlag, "FLAG_")) { + std::string flagHexVal = curFlag.substr(5); + flagVal = std::stoi(flagHexVal, 0, 16); + } else { + DebugHelper::assert(OBJECT_HEADER_FLAGS.has_key(curFlag), + "(BuildObjectHeader::_string_to_flags) Invalid object header flag: \"", curFlag, "\""); + flagVal = OBJECT_HEADER_FLAGS.get_value(curFlag); + } + + result |= flagVal; + } + + return result; +} + +void BuildObjectHeader::_preload_c_context() { + fs::path includeFolder = _settings.pathToRepo / "include/"; + + // Load all enums from these files. + fs::path enumPaths[] = { + includeFolder / "object_behaviors.h", + includeFolder / "enums.h" + }; + + for(fs::path &enumPath : enumPaths) { + CEnumsHelper::load_enums_from_file(&_c_context, enumPath); + } +} diff --git a/tools/dkr_assets_tool_src/builder/buildTypes/buildObjectHeader.h b/tools/dkr_assets_tool_src/builder/buildTypes/buildObjectHeader.h new file mode 100644 index 00000000..595c2c02 --- /dev/null +++ b/tools/dkr_assets_tool_src/builder/buildTypes/buildObjectHeader.h @@ -0,0 +1,24 @@ +#pragma once + +#include "builder/buildInfo.h" +#include "misc/settings.hpp" + +#include "fileTypes/fonts.hpp" + +#include "helpers/debugHelper.h" +#include "helpers/fileHelper.h" +#include "helpers/jsonHelper.h" +#include "helpers/c/cContext.h" + +class BuildObjectHeader { +public: + BuildObjectHeader(DkrAssetsSettings &settings, BuildInfo &info); + ~BuildObjectHeader(); +private: + DkrAssetsSettings &_settings; + BuildInfo &_info; + CContext _c_context; + + be_uint16_t _string_to_flags(); + void _preload_c_context(); +}; diff --git a/tools/dkr_assets_tool_src/builder/buildTypes/buildObjectMap.cpp b/tools/dkr_assets_tool_src/builder/buildTypes/buildObjectMap.cpp new file mode 100644 index 00000000..cbe412ab --- /dev/null +++ b/tools/dkr_assets_tool_src/builder/buildTypes/buildObjectMap.cpp @@ -0,0 +1,183 @@ +#include "buildObjectMap.h" + +#include "fileTypes/levelObjectMap.hpp" + +#include "helpers/assetsHelper.h" +#include "helpers/dataHelper.h" +#include "helpers/gzipHelper.h" + +#include "helpers/c/cStructGltfHelper.h" + +BuildObjectMap::BuildObjectMap(DkrAssetsSettings &settings, BuildInfo &info) : _settings(settings), _info(info) { + _preload_c_context(); + + _transTable = AssetsHelper::get_asset_json(_settings, "ASSET_LEVEL_OBJECT_TRANSLATION_TABLE"); + _objBehaviorToEntryTable = AssetsHelper::get_meta_file(_settings, "objects/obj_beh_to_entry.meta.json"); + + if(info.srcFile->is_value_null("/objects")) { + FileHelper::write_empty_file(_info.dstPath, true); + return; + } + + fs::path gltfPath = info.localDirectory / info.srcFile->get_string("/objects"); + + GltfFile gltf(gltfPath); + + // _calculate_size() also fills the `_objectIdToStructCache` map. + size_t dataSize = _calculate_size(gltf); + + size_t outSize = DataHelper::align8(dataSize + sizeof(LevelObjectMapHeader)); + + std::vector out(outSize); + + LevelObjectMap *objectMap = reinterpret_cast(&out[0]); + + // Set number of bytes. + objectMap->header.fileSize = dataSize; + uint8_t *bytes = &objectMap->entriesData[0]; + + int numberOfNodes = gltf.get_node_count(); + + // Node 0 is the root node, so we want to start at node 1. + for(int i = 1; i < numberOfNodes; i++) { + std::string objectBuildId = gltf.get_node_extra(i, "id", ""); + + int id = _transTable->get_index_of_elem_in_array("/table", objectBuildId); + + DebugHelper::assert_(id >= 0, "(BuildObjectMap::BuildObjectMap) ", objectBuildId, " is not in the level-object translation table!"); + + CStruct *entryStruct = _objectIdToStructCache[objectBuildId]; + size_t entrySize = _objectIdStructSizeCache[objectBuildId]; + + // TODO: Increase this limit? + DebugHelper::assert_(entrySize < 128, "(BuildObjectMap::BuildObjectMap) Entry for ", objectBuildId, " is too big! 127 bytes is the maximum."); + + bytes[0] = (id & 0xFF); // First byte is the lower 8 bits of the id. + bytes[1] = ((id >> 8) << 7) | entrySize; // Upper-most bit is the 9th bit of the id, lower 7 bits is the length. + + // Assumption: entryStruct is LevelObjectEntryCommon + CStruct *entryCommon = entryStruct; + + // Check assumption by seeing if the first entry is a LevelObjectEntryCommon + if(entryStruct->get_entry(0)->type == "LevelObjectEntryCommon") { + // Assumption was wrong, so fix it! + entryCommon = _c_context.get_struct("LevelObjectEntryCommon"); + } + + _set_obj_position(gltf, bytes, entryCommon, i); + + if(entryCommon != entryStruct) { + for(size_t entry = 0; entry < entryStruct->entry_count(); entry++) { + CStructEntry *structMember = entryStruct->get_entry(entry); + CStructGltfHelper::put_gltf_node_extra_into_struct_entry(structMember, gltf, i, bytes); + } + } + + bytes += entrySize; + } + + if(_settings.debugBuildKeepUncompressed) { + // Have the uncompressed binary in a seperate directory in the build folder. + fs::path outUncompressedPath = _settings.pathToBuild / _settings.dkrVersion / "debug/objectMaps" / (_info.dstPath.stem().string() + ".bin"); + FileHelper::write_binary_file(out, outUncompressedPath, true); + } + + // Note: `out` becomes garbled after this. + std::vector compressedOut = GzipHelper::compress_gzip(out); + + FileHelper::write_binary_file(compressedOut, _info.dstPath, true); +} + +BuildObjectMap::~BuildObjectMap() { + +} + +void BuildObjectMap::_set_obj_position(GltfFile &gltf, uint8_t *bytes, CStruct *entryCommon, int nodeIndex) { + CStructEntry *memberX = entryCommon->get_entry(2); + CStructEntry *memberY = entryCommon->get_entry(3); + CStructEntry *memberZ = entryCommon->get_entry(4); + + double scaledX, scaledY, scaledZ; + gltf.get_node_position(nodeIndex, scaledX, scaledY, scaledZ); + + int xPos = _settings.adjust_from_model_scale(scaledX); + int yPos = _settings.adjust_from_model_scale(scaledY); + int zPos = _settings.adjust_from_model_scale(scaledZ); + + memberX->set_integer_to_data(bytes, xPos); + memberY->set_integer_to_data(bytes, yPos); + memberZ->set_integer_to_data(bytes, zPos); +} + +size_t BuildObjectMap::_calculate_size(GltfFile &gltf) { + size_t out = 0; + + int numberOfNodes = gltf.get_node_count(); + + + + // Node 0 is the root node, so we want to start at node 1. + for(int i = 1; i < numberOfNodes; i++) { + std::string objectBuildId = gltf.get_node_extra(i, "id", ""); + + DebugHelper::assert_(!objectBuildId.empty(), "(BuildObjectMap::_calculate_size) id was not defined in node ", i); + + // First check if we have already calcuated the size of this object build id. + if(_objectIdStructSizeCache.find(objectBuildId) != _objectIdStructSizeCache.end()) { + out += _objectIdStructSizeCache[objectBuildId]; + continue; + } + + // Get behavior from object id. + JsonFile *objJson = AssetsHelper::get_asset_json(_settings, "ASSET_OBJECTS", objectBuildId); + std::string objBehavior = objJson->get_string("/behavior"); + + DebugHelper::assert_( + !objBehavior.empty(), + "(BuildObjectMap::_calculate_size) Object \"", objectBuildId, "\" does not specify a behavior!" + ); + + std::string entryStructName = _objBehaviorToEntryTable->get_string("/" + objBehavior); + DebugHelper::assert_( + !entryStructName.empty(), + "(ExtractObjectMap::ExtractObjectMap) The behavior \"", objBehavior, "\" does not specify an entry struct!" + ); + + CStruct *entryStruct = _c_context.get_struct(entryStructName); + + // Save struct pointer to cache. + _objectIdToStructCache[objectBuildId] = entryStruct; + + size_t byteSize = entryStruct->get_byte_size(); + + // Save size to cache. + _objectIdStructSizeCache[objectBuildId] = byteSize; + + out += byteSize; + } + + return out; +} + +void BuildObjectMap::_preload_c_context() { + fs::path includeFolder = _settings.pathToRepo / "include/"; + + // Load all structs from these files. + fs::path structPaths[] = { + includeFolder / "level_object_entries.h", + }; + + for(fs::path &structPath : structPaths) { + CStructHelper::load_structs_from_file(&_c_context, structPath); + } + + // Load all enums from these files. + fs::path enumPaths[] = { + includeFolder / "enums.h", + includeFolder / "object_behaviors.h", + }; + + for(fs::path &enumPath : enumPaths) { + CEnumsHelper::load_enums_from_file(&_c_context, enumPath); + } +} diff --git a/tools/dkr_assets_tool_src/builder/buildTypes/buildObjectMap.h b/tools/dkr_assets_tool_src/builder/buildTypes/buildObjectMap.h new file mode 100644 index 00000000..23046633 --- /dev/null +++ b/tools/dkr_assets_tool_src/builder/buildTypes/buildObjectMap.h @@ -0,0 +1,37 @@ +#pragma once + +#include + +#include "builder/buildInfo.h" +#include "misc/settings.hpp" + +#include "fileTypes/fonts.hpp" + +#include "helpers/debugHelper.h" +#include "helpers/fileHelper.h" +#include "helpers/jsonHelper.h" +#include "helpers/gltf/gltfHelper.h" +#include "helpers/c/cContext.h" +#include "helpers/c/cStructHelper.h" + +class BuildObjectMap { +public: + BuildObjectMap(DkrAssetsSettings &settings, BuildInfo &info); + ~BuildObjectMap(); +private: + DkrAssetsSettings &_settings; + BuildInfo &_info; + CContext _c_context; // C Code context. (For loading enums & structs) + + // Both are populated in _calculate_size() + std::unordered_map _objectIdStructSizeCache; + std::unordered_map _objectIdToStructCache; + + JsonFile *_transTable; + JsonFile *_objBehaviorToEntryTable; + + void _set_obj_position(GltfFile &gltf, uint8_t *bytes, CStruct *entryCommon, int nodeIndex); + + size_t _calculate_size(GltfFile &gltf); + void _preload_c_context(); +}; diff --git a/tools/dkr_assets_tool_src/builder/buildTypes/buildObjectModel.cpp b/tools/dkr_assets_tool_src/builder/buildTypes/buildObjectModel.cpp new file mode 100644 index 00000000..0b6a4ef5 --- /dev/null +++ b/tools/dkr_assets_tool_src/builder/buildTypes/buildObjectModel.cpp @@ -0,0 +1,15 @@ +#include "buildObjectModel.h" + +BuildObjectModel::BuildObjectModel(DkrAssetsSettings &settings, BuildInfo &info) : _settings(settings), _info(info) { + std::string rawPath = info.srcFile->get_string("/raw"); + + DebugHelper::assert(!rawPath.empty(), "(BuildObjectModel::BuildObjectModel) \"raw\" not specified!"); + + // Copy file from rawPath to destination path. + FileHelper::copy(_info.localDirectory / rawPath, info.dstPath); +} + +BuildObjectModel::~BuildObjectModel() { + +} + diff --git a/tools/dkr_assets_tool_src/builder/buildTypes/buildObjectModel.h b/tools/dkr_assets_tool_src/builder/buildTypes/buildObjectModel.h new file mode 100644 index 00000000..125c0bb8 --- /dev/null +++ b/tools/dkr_assets_tool_src/builder/buildTypes/buildObjectModel.h @@ -0,0 +1,19 @@ +#pragma once + +#include "builder/buildInfo.h" +#include "misc/settings.hpp" + +#include "fileTypes/fonts.hpp" + +#include "helpers/debugHelper.h" +#include "helpers/fileHelper.h" +#include "helpers/jsonHelper.h" + +class BuildObjectModel { +public: + BuildObjectModel(DkrAssetsSettings &settings, BuildInfo &info); + ~BuildObjectModel(); +private: + DkrAssetsSettings &_settings; + BuildInfo &_info; +}; diff --git a/tools/dkr_assets_tool_src/builder/buildTypes/buildParticle.cpp b/tools/dkr_assets_tool_src/builder/buildTypes/buildParticle.cpp new file mode 100644 index 00000000..9f6a5ca5 --- /dev/null +++ b/tools/dkr_assets_tool_src/builder/buildTypes/buildParticle.cpp @@ -0,0 +1,15 @@ +#include "buildParticle.h" + +BuildParticle::BuildParticle(DkrAssetsSettings &settings, BuildInfo &info) : _settings(settings), _info(info) { + std::string rawPath = info.srcFile->get_string("/raw"); + + DebugHelper::assert(!rawPath.empty(), "(BuildParticle::BuildParticle) \"raw\" not specified!"); + + // Copy file from rawPath to destination path. + FileHelper::copy(_info.localDirectory / rawPath, info.dstPath); +} + +BuildParticle::~BuildParticle() { + +} + diff --git a/tools/dkr_assets_tool_src/builder/buildTypes/buildParticle.h b/tools/dkr_assets_tool_src/builder/buildTypes/buildParticle.h new file mode 100644 index 00000000..0ebebfde --- /dev/null +++ b/tools/dkr_assets_tool_src/builder/buildTypes/buildParticle.h @@ -0,0 +1,19 @@ +#pragma once + +#include "builder/buildInfo.h" +#include "misc/settings.hpp" + +#include "fileTypes/fonts.hpp" + +#include "helpers/debugHelper.h" +#include "helpers/fileHelper.h" +#include "helpers/jsonHelper.h" + +class BuildParticle { +public: + BuildParticle(DkrAssetsSettings &settings, BuildInfo &info); + ~BuildParticle(); +private: + DkrAssetsSettings &_settings; + BuildInfo &_info; +}; diff --git a/tools/dkr_assets_tool_src/builder/buildTypes/buildParticleBehavior.cpp b/tools/dkr_assets_tool_src/builder/buildTypes/buildParticleBehavior.cpp new file mode 100644 index 00000000..7ea40612 --- /dev/null +++ b/tools/dkr_assets_tool_src/builder/buildTypes/buildParticleBehavior.cpp @@ -0,0 +1,15 @@ +#include "buildParticleBehavior.h" + +BuildParticleBehavior::BuildParticleBehavior(DkrAssetsSettings &settings, BuildInfo &info) : _settings(settings), _info(info) { + std::string rawPath = info.srcFile->get_string("/raw"); + + DebugHelper::assert(!rawPath.empty(), "(BuildParticleBehavior::BuildParticleBehavior) \"raw\" not specified!"); + + // Copy file from rawPath to destination path. + FileHelper::copy(_info.localDirectory / rawPath, _info.dstPath); +} + +BuildParticleBehavior::~BuildParticleBehavior() { + +} + diff --git a/tools/dkr_assets_tool_src/builder/buildTypes/buildParticleBehavior.h b/tools/dkr_assets_tool_src/builder/buildTypes/buildParticleBehavior.h new file mode 100644 index 00000000..950b1f14 --- /dev/null +++ b/tools/dkr_assets_tool_src/builder/buildTypes/buildParticleBehavior.h @@ -0,0 +1,19 @@ +#pragma once + +#include "builder/buildInfo.h" +#include "misc/settings.hpp" + +#include "fileTypes/fonts.hpp" + +#include "helpers/debugHelper.h" +#include "helpers/fileHelper.h" +#include "helpers/jsonHelper.h" + +class BuildParticleBehavior { +public: + BuildParticleBehavior(DkrAssetsSettings &settings, BuildInfo &info); + ~BuildParticleBehavior(); +private: + DkrAssetsSettings &_settings; + BuildInfo &_info; +}; diff --git a/tools/dkr_assets_tool_src/builder/buildTypes/buildSprite.cpp b/tools/dkr_assets_tool_src/builder/buildTypes/buildSprite.cpp new file mode 100644 index 00000000..571aba8c --- /dev/null +++ b/tools/dkr_assets_tool_src/builder/buildTypes/buildSprite.cpp @@ -0,0 +1,41 @@ +#include "buildSprite.h" + +#include "fileTypes/sprite.hpp" +#include "helpers/dataHelper.h" +#include "helpers/assetsHelper.h" + +BuildSprite::BuildSprite(DkrAssetsSettings &settings, BuildInfo &info) : _settings(settings), _info(info) { + size_t numberOfTextures = _info.srcFile->length_of_array("/frame-tex-count"); + + size_t outSize = sizeof(SpriteHeader) + numberOfTextures + 1; + outSize = DataHelper::align16(outSize); + + std::vector out(outSize); + + SpriteHeader *spriteHeader = reinterpret_cast(&out[0]); + + std::string texBuildId = _info.srcFile->get_string("/start-texture"); + DebugHelper::assert(!texBuildId.empty(), "(BuildSprite::BuildSprite) [/start-texture] was not defined!"); + + spriteHeader->startTextureIndex = AssetsHelper::get_asset_index(_settings, "ASSET_TEXTURES_2D", texBuildId); + spriteHeader->unk4 = _info.srcFile->get_int("/unk4"); + spriteHeader->unk6 = _info.srcFile->get_int("/unk6"); + spriteHeader->unk8 = 0; // Set in-game, always zero in ROM. + spriteHeader->numberOfFrames = numberOfTextures; + + std::string frameTexCountPtr = "/frame-tex-count"; + uint8_t *data = &out[sizeof(SpriteHeader)]; + + uint8_t output = 0; + for(size_t i = 0; i < numberOfTextures + 1; i++) { + data[i] = output; + output += _info.srcFile->get_int(frameTexCountPtr + "/" + std::to_string(i)); + } + + FileHelper::write_binary_file(out, _info.dstPath, true); +} + +BuildSprite::~BuildSprite() { + +} + diff --git a/tools/dkr_assets_tool_src/builder/buildTypes/buildSprite.h b/tools/dkr_assets_tool_src/builder/buildTypes/buildSprite.h new file mode 100644 index 00000000..9bdec0a1 --- /dev/null +++ b/tools/dkr_assets_tool_src/builder/buildTypes/buildSprite.h @@ -0,0 +1,19 @@ +#pragma once + +#include "builder/buildInfo.h" +#include "misc/settings.hpp" + +#include "fileTypes/fonts.hpp" + +#include "helpers/debugHelper.h" +#include "helpers/fileHelper.h" +#include "helpers/jsonHelper.h" + +class BuildSprite { +public: + BuildSprite(DkrAssetsSettings &settings, BuildInfo &info); + ~BuildSprite(); +private: + DkrAssetsSettings &_settings; + BuildInfo &_info; +}; diff --git a/tools/dkr_assets_tool_src/builder/buildTypes/buildTTGhost.cpp b/tools/dkr_assets_tool_src/builder/buildTypes/buildTTGhost.cpp new file mode 100644 index 00000000..59d022ab --- /dev/null +++ b/tools/dkr_assets_tool_src/builder/buildTypes/buildTTGhost.cpp @@ -0,0 +1,65 @@ +#include "buildTTGhost.h" + +#include // for std::round + +#include "fileTypes/ttGhost.hpp" +#include "helpers/assetsHelper.h" +#include "helpers/dataHelper.h" + +BuildTTGhost::BuildTTGhost(DkrAssetsSettings &settings, BuildInfo &info) : _settings(settings), _info(info) { + _preload_c_context(); + + size_t numberOfNodes = _info.srcFile->length_of_array("/nodes"); + + size_t outSize = sizeof(GhostHeader) + (sizeof(GhostNode) * numberOfNodes); + + // Ghost Data must be 16-byte aligned. + outSize = DataHelper::align16(outSize); + + std::vector out(outSize); + + GhostHeader *ghostHeader = reinterpret_cast(&out[0]); + GhostNode *ghostNodes = reinterpret_cast(&out[sizeof(GhostHeader)]); + + std::string level = _info.srcFile->get_string("/header/level"); + ghostHeader->levelId = AssetsHelper::get_asset_index(_settings, "ASSET_LEVEL_HEADERS", level); + + std::string vehicle = _info.srcFile->get_string("/header/vehicle"); + ghostHeader->vehicleId = _c_context.get_int_value_of_symbol(vehicle); + + // Default character ID is 9 if not specified. + ghostHeader->characterId = _info.srcFile->get_int("/header/character", 0x09); + + ghostHeader->time = std::round(_info.srcFile->get_float("/header/time") * GHOST_TIME_FPS); + + ghostHeader->nodeCount = numberOfNodes; + + for(size_t i = 0; i < numberOfNodes; i++) { + std::string ptr = "/nodes/" + std::to_string(i); + ghostNodes[i].x = _info.srcFile->get_int(ptr + "/x"); + ghostNodes[i].y = _info.srcFile->get_int(ptr + "/y"); + ghostNodes[i].z = _info.srcFile->get_int(ptr + "/z"); + ghostNodes[i].zRotation = _info.srcFile->get_int(ptr + "/rz"); + ghostNodes[i].xRotation = _info.srcFile->get_int(ptr + "/rx"); + ghostNodes[i].yRotation = _info.srcFile->get_int(ptr + "/ry"); + } + + FileHelper::write_binary_file(out, _info.dstPath, true); +} + +BuildTTGhost::~BuildTTGhost() { + +} + +void BuildTTGhost::_preload_c_context() { + fs::path includeFolder = _settings.pathToRepo / "include/"; + + // Load all enums from these files. + fs::path enumPaths[] = { + includeFolder / "enums.h", + }; + + for(fs::path &enumPath : enumPaths) { + CEnumsHelper::load_enums_from_file(&_c_context, enumPath); + } +} diff --git a/tools/dkr_assets_tool_src/builder/buildTypes/buildTTGhost.h b/tools/dkr_assets_tool_src/builder/buildTypes/buildTTGhost.h new file mode 100644 index 00000000..b2899355 --- /dev/null +++ b/tools/dkr_assets_tool_src/builder/buildTypes/buildTTGhost.h @@ -0,0 +1,24 @@ +#pragma once + +#include "builder/buildInfo.h" +#include "misc/settings.hpp" + +#include "fileTypes/fonts.hpp" + +#include "helpers/debugHelper.h" +#include "helpers/fileHelper.h" +#include "helpers/jsonHelper.h" +#include "helpers/c/cContext.h" + +class BuildTTGhost { +public: + BuildTTGhost(DkrAssetsSettings &settings, BuildInfo &info); + ~BuildTTGhost(); +private: + DkrAssetsSettings &_settings; + BuildInfo &_info; + + CContext _c_context; // C Code context. (For loading enums & structs) + + void _preload_c_context(); +}; diff --git a/tools/dkr_assets_tool_src/builder/buildTypes/buildTexture.cpp b/tools/dkr_assets_tool_src/builder/buildTypes/buildTexture.cpp new file mode 100644 index 00000000..05d9e079 --- /dev/null +++ b/tools/dkr_assets_tool_src/builder/buildTypes/buildTexture.cpp @@ -0,0 +1,146 @@ +#include "buildTexture.h" + +#include // for std::round + +#include "helpers/dataHelper.h" +#include "helpers/imageHelper.h" +#include "helpers/gzipHelper.h" +#include "fileTypes/texture.hpp" + +BuildTexture::BuildTexture(DkrAssetsSettings &settings, BuildInfo &info) : _settings(settings), _info(info) { + std::vector out(_calculate_out_size()); + + int numberOfTextures = _info.srcFile->length_of_array("/images"); + std::string format = _info.srcFile->get_string_uppercase("/format", DEFAULT_TEXTURE_FORMAT); + + bool isCompressed = _info.srcFile->get_bool("/compressed"); + bool isFlipped = _info.srcFile->get_bool("/flipped-image", false); + int frameAdvanceDelay = std::round(_info.srcFile->get_float("/frame-advance-delay", 0) * TEXTURE_FPS); + std::string renderMode = _info.srcFile->get_string("/render-mode", "OPAQUE"); + + int spriteX = _info.srcFile->get_int("/sprite-x", 0); + int spriteY = _info.srcFile->get_int("/sprite-y", 0); + + bool writeSize = _info.srcFile->get_bool("/write-size"); + + uint8_t formatVal = DataHelper::vector_index_of(TEXTURE_FORMAT_INT_TO_STRING, format); + uint8_t renderModeVal = DataHelper::vector_index_of(TEXTURE_RENDER_MODES, renderMode); + + size_t currentOffset = 0; + + bool wrapSClamped = _info.srcFile->get_string_lowercase("/flags/wrap-s", "wrap") == "clamp"; + bool wrapTClamped = _info.srcFile->get_string_lowercase("/flags/wrap-t", "wrap") == "clamp"; + bool antiAliased = _info.srcFile->get_bool("/flags/anti-aliased"); + bool semiTransparent = _info.srcFile->get_bool("/flags/semi-transparent"); + bool cutout = _info.srcFile->get_bool("/flags/cutout"); + bool interlaced = _info.srcFile->get_bool("/flags/interlaced"); + + // TODO: Make flags not hardcoded! + be_int16_t flags = ( + ((int)antiAliased << 0) | + ((int)semiTransparent << 2) | + ((int)cutout << 4) | + ((int)wrapSClamped << 6) | + ((int)wrapTClamped << 7) | + ((int)interlaced << 10) + ); + + for(int i = 0; i < numberOfTextures; i++) { + TextureHeader *header = reinterpret_cast(&out[currentOffset]); + + header->format = (renderModeVal << 4) | formatVal; + header->spriteX = spriteX; + header->spriteY = spriteY; + header->numberOfInstances = 1; + header->numOfTextures = numberOfTextures; + header->frameAdvanceDelay = frameAdvanceDelay; + header->flags = flags; + + currentOffset += sizeof(TextureHeader); + uint8_t *textureData = &out[currentOffset]; + + fs::path localImgPath = _info.srcFile->get_string("/images/" + std::to_string(i)); + + N64Image img(_info.localDirectory / localImgPath, format); + + int imgWidth = img.get_width(); + int imgHeight = img.get_height(); + + header->width = imgWidth; + header->height = imgHeight; + + if(writeSize) { + header->textureSize = DataHelper::align16(sizeof(TextureHeader) + ImageHelper::image_size(imgWidth, imgHeight, format)); + } else { + // ??? + header->isCompressed = 1; + } + + if(isFlipped) { + img.flip_vertically(); + } + + if(interlaced) { + img.interlace(); + } + + img.copy_to(textureData); + + currentOffset += img.size(); + } + + if(!writeSize) { + // Make sure `out` is 16-byte aligned. + while(out.size() % 16 != 0) { + out.push_back(0); + } + } + + if(_settings.debugBuildKeepUncompressed) { + // Have the uncompressed binary in a seperate directory in the build folder. + fs::path outUncompressedPath = _settings.pathToBuild / _settings.dkrVersion / "debug/textures" / (_info.dstPath.stem().string() + ".bin"); + FileHelper::write_binary_file(out, outUncompressedPath, true); + } + + if(isCompressed) { + std::vector compressedHeader; + + // Copy header from first texture into compressedHeader vector. + compressedHeader.insert(compressedHeader.end(), out.begin(), out.begin() + sizeof(TextureHeader)); + + TextureHeader *compressedTexHeader = reinterpret_cast(&compressedHeader[0]); + compressedTexHeader->isCompressed = 1; // Very important for this to be set for compressed textures! + + // out is garbled at this point, so don't use it after this point! + std::vector compressedOut = GzipHelper::compress_gzip(out); + + // Add the compressed header to the start of compressedOut + compressedOut.insert(compressedOut.begin(), compressedHeader.begin(), compressedHeader.end()); + + FileHelper::write_binary_file(compressedOut, _info.dstPath, true); + + return; + } + + FileHelper::write_binary_file(out, _info.dstPath, true); +} + +BuildTexture::~BuildTexture() { + +} + +size_t BuildTexture::_calculate_out_size() { + int numberOfTextures = _info.srcFile->length_of_array("/images"); + std::string format = _info.srcFile->get_string_uppercase("/format", DEFAULT_TEXTURE_FORMAT); + + size_t sizeOfAllImages = 0; + + for(int i = 0; i < numberOfTextures; i++) { + fs::path localImagePath = _info.srcFile->get_string("/images/" + std::to_string(i)); + fs::path filepath = _info.localDirectory / localImagePath; + + sizeOfAllImages += ImageHelper::image_size(filepath, format); + } + + return (numberOfTextures * sizeof(TextureHeader)) + sizeOfAllImages; +} diff --git a/tools/dkr_assets_tool_src/builder/buildTypes/buildTexture.h b/tools/dkr_assets_tool_src/builder/buildTypes/buildTexture.h new file mode 100644 index 00000000..affc1496 --- /dev/null +++ b/tools/dkr_assets_tool_src/builder/buildTypes/buildTexture.h @@ -0,0 +1,21 @@ +#pragma once + +#include "builder/buildInfo.h" +#include "misc/settings.hpp" + +#include "fileTypes/fonts.hpp" + +#include "helpers/debugHelper.h" +#include "helpers/fileHelper.h" +#include "helpers/jsonHelper.h" + +class BuildTexture { +public: + BuildTexture(DkrAssetsSettings &settings, BuildInfo &info); + ~BuildTexture(); +private: + DkrAssetsSettings &_settings; + BuildInfo &_info; + + size_t _calculate_out_size(); +}; diff --git a/tools/dkr_assets_tool_src/builder/builder.cpp b/tools/dkr_assets_tool_src/builder/builder.cpp new file mode 100644 index 00000000..1ce16ac1 --- /dev/null +++ b/tools/dkr_assets_tool_src/builder/builder.cpp @@ -0,0 +1,93 @@ +#include "builder.h" + +#include +#include +#include + +#include "helpers/stringHelper.h" +#include "helpers/jsonHelper.h" +#include "helpers/fileHelper.h" +#include "helpers/debugHelper.h" + +#include "builder/buildInfo.h" + +#include "buildTypes/buildAudio.h" +#include "buildTypes/buildBinary.h" +#include "buildTypes/buildTexture.h" +#include "buildTypes/buildFonts.h" +#include "buildTypes/buildGameText.h" +#include "buildTypes/buildLevelModel.h" +#include "buildTypes/buildLevelHeader.h" +#include "buildTypes/buildLevelObjectTranslationTable.h" +#include "buildTypes/buildMenuText.h" +#include "buildTypes/buildObjectAnimation.h" +#include "buildTypes/buildObjectHeader.h" +#include "buildTypes/buildObjectMap.h" +#include "buildTypes/buildObjectModel.h" +#include "buildTypes/buildParticle.h" +#include "buildTypes/buildParticleBehavior.h" +#include "buildTypes/buildSprite.h" +#include "buildTypes/buildTTGhost.h" +#include "buildTypes/buildMisc.h" + +// Hope this doesn't cause too much cringe. +#define BUILDER_ARGS DkrAssetsSettings &settings, BuildInfo &info +#define BUILDER_LAMDA(classConstructorCode) [](BUILDER_ARGS) { classConstructorCode(settings, info); } + +typedef std::function BuilderFunction; + +// Put build class constructors here with the type in the JSON file! +std::unordered_map builderMap = { + { "Binary", BUILDER_LAMDA(BuildBinary) }, + { "Fonts", BUILDER_LAMDA(BuildFonts) }, + { "LevelObjectTranslationTable", BUILDER_LAMDA(BuildLOTT) }, + { "Texture", BUILDER_LAMDA(BuildTexture) }, + { "LevelObjectMap", BUILDER_LAMDA(BuildObjectMap) }, + { "LevelModel", BUILDER_LAMDA(BuildLevelModel) }, + { "LevelHeader", BUILDER_LAMDA(BuildLevelHeader) }, + { "ObjectHeader", BUILDER_LAMDA(BuildObjectHeader) }, + { "ObjectModel", BUILDER_LAMDA(BuildObjectModel) }, + { "ObjectAnimation", BUILDER_LAMDA(BuildObjectAnimation) }, + { "TTGhost", BUILDER_LAMDA(BuildTTGhost) }, + { "GameText", BUILDER_LAMDA(BuildGameText) }, + { "MenuText", BUILDER_LAMDA(BuildMenuText) }, + { "Miscellaneous", BUILDER_LAMDA(BuildMisc) }, + { "Sprite", BUILDER_LAMDA(BuildSprite) }, + { "Audio", BUILDER_LAMDA(BuildAudio) }, + { "Particle", BUILDER_LAMDA(BuildParticle) }, + { "ParticleBehavior", BUILDER_LAMDA(BuildParticleBehavior) }, +}; + +DkrAssetBuilder::DkrAssetBuilder(DkrAssetsSettings &settings, const fs::path &srcPath, const fs::path &dstPath) { + settings.pathToAssets /= settings.dkrVersion + "/"; + + // Make sure the input file is a JSON file. + DebugHelper::assert_(StringHelper::ends_with(srcPath, ".json"), "(DkrAssetBuilder::DkrAssetBuilder) Input file is not a JSON file! Input file = \"", srcPath, "\""); + + JsonFile *jsonFile; + + // Get the file, and throw an error if it doesn't exist. + DebugHelper::assert_(JsonHelper::get().get_file(srcPath, &jsonFile), "(DkrAssetBuilder::DkrAssetBuilder) Could not find input file \"", srcPath, "\""); + + fs::path localDirectory = FileHelper::get_directory(srcPath); + + BuildInfo info(jsonFile, dstPath, localDirectory); + + // Make sure the json file has the "type" key. + DebugHelper::assert_(jsonFile->has("/type"), "(DkrAssetBuilder::DkrAssetBuilder) Input JSON file does not have a \"type\"! Input file = \"", srcPath, "\""); + + std::string type = jsonFile->get_string("/type"); + + // Check to make sure the builderMap has the given type. + if(builderMap.find(type) == builderMap.end()) { + // For now this is a warning, but maybe make it an error instead? + DebugHelper::warn("The input type \"", type, "\" is currently not implemented."); + return; + } + + // Call the class constructor of a type. + builderMap[type](settings, info); +} + +DkrAssetBuilder::~DkrAssetBuilder() { +} diff --git a/tools/dkr_assets_tool_src/builder/builder.h b/tools/dkr_assets_tool_src/builder/builder.h new file mode 100644 index 00000000..851510c1 --- /dev/null +++ b/tools/dkr_assets_tool_src/builder/builder.h @@ -0,0 +1,14 @@ +#pragma once + +#include +#include "misc/settings.hpp" + +// Converts a JSON file into raw asset data the game can read. +class DkrAssetBuilder { +public: + DkrAssetBuilder(DkrAssetsSettings &settings, const fs::path &srcPath, const fs::path &dstPath); + ~DkrAssetBuilder(); +private: + + +}; \ No newline at end of file diff --git a/tools/dkr_assets_tool_src/extract/assetTable.cpp b/tools/dkr_assets_tool_src/extract/assetTable.cpp new file mode 100644 index 00000000..2858805a --- /dev/null +++ b/tools/dkr_assets_tool_src/extract/assetTable.cpp @@ -0,0 +1,214 @@ +#include "assetTable.h" + +AssetTable::AssetTable(DkrExtractROM *rom, uint32_t offset, DkrAssetTableType type){ + _rom = rom; + _romOffset = offset; + switch(type) { + case DkrAssetTableType::FixedTable: + _parse_fixed_table(); + break; + case DkrAssetTableType::VariableTable: + _parse_variable_table(); + break; + case DkrAssetTableType::MenuTextTable: + _parse_menutext_table(); + break; + case DkrAssetTableType::GameTextTable: + _parse_gametext_table(); + break; + case DkrAssetTableType::TTGhostTable: + _parse_ttghost_table(); + break; + case DkrAssetTableType::MiscTable: + _parse_misc_table(); + break; + case DkrAssetTableType::AudioTable: + _parse_audio_table(); + break; + } +} + +AssetTable::~AssetTable() { + +} + + +size_t AssetTable::size() { + return _entries.size(); +} + +int32_t AssetTable::get_entry_offset(size_t entryIndex) { + if(entryIndex >= _entries.size()) { + DebugHelper::error("(AssetTable::get_entry_offset) Entry out of bounds! ", entryIndex); + } + return _entries[entryIndex].offset; +} + +int32_t AssetTable::get_entry_size(size_t entryIndex) { + if(entryIndex >= _entries.size()) { + DebugHelper::error("(AssetTable::get_entry_size) Entry out of bounds! ", entryIndex); + } + return _entries[entryIndex].length; +} + +// TODO: Reduce duplicate code. + +void AssetTable::_parse_fixed_table() { + uint32_t offset = _romOffset; + int numEntries = _rom->get_s32(offset); + offset += 4; + for(int i = 0; i < numEntries; i++) { + int32_t entryValue = _rom->get_s32(offset); + int32_t entrySize = _rom->get_s32(offset + 4) - entryValue; + + _entries.push_back({entryValue, entrySize}); + + offset += 4; + } +} + +void AssetTable::_parse_variable_table() { + uint32_t offset = _romOffset; + while(true) { + int32_t entryValue = (_rom->get_s32(offset)); + int32_t nextEntryValue = (_rom->get_s32(offset + 4)); + if(entryValue == -1 || nextEntryValue == -1) { + return; + } + int32_t entrySize = nextEntryValue - entryValue; + if(entryValue < 0) { + DebugHelper::error("(AssetTable::_parse_variable_table) Invalid table entry ", DebugHelper::to_hex(entryValue), " at rom offset ", DebugHelper::to_hex(offset)); + } + + _entries.push_back({entryValue, entrySize}); + + offset += 4; + } +} + +// Similar to _parse_variable_table, but it starts at index 1. (The 0th index tells how many text entries are in each language) +void AssetTable::_parse_menutext_table() { + uint32_t offset = _romOffset + 4; + while(true) { + int32_t entryValue = (_rom->get_s32(offset)); + int32_t nextEntryValue = (_rom->get_s32(offset + 4)); + if(entryValue == -1 || nextEntryValue == -1) { + return; + } + int32_t entrySize = nextEntryValue - entryValue; + + if(entryValue < 0) { + DebugHelper::error("(AssetTable::_parse_menutext_table) Invalid table entry ", DebugHelper::to_hex(entryValue), " at rom offset ", DebugHelper::to_hex(offset)); + } + + _entries.push_back({entryValue, entrySize}); + + offset += 4; + } +} + +// Similar to _parse_variable_table, but some entries might have the highest bit set to indicate that it is dialog instead of a textbox. +// So we want to disregard the negative value check. +void AssetTable::_parse_gametext_table() { + uint32_t offset = _romOffset; + while(true) { + int32_t entryValue = (_rom->get_s32(offset)); + int32_t nextEntryValue = (_rom->get_s32(offset + 4)); + if(entryValue == -1 || nextEntryValue == -1) { + return; + } + int32_t entrySize = (nextEntryValue & 0x7FFFFFFF) - (entryValue & 0x7FFFFFFF); + + _entries.push_back({entryValue, entrySize}); + + offset += 4; + } +} + +// Similar to _parse_variable_table, but ttghosts are 8 bytes per entry. We only care about the offsets though. +void AssetTable::_parse_ttghost_table() { + uint32_t offset = _romOffset; + while(true) { + + int32_t entryValue = (_rom->get_s32(offset + 4)); + int32_t nextEntryValue = (_rom->get_s32(offset + 12)); + if(entryValue == -1 || nextEntryValue == -1) { + return; + } + int32_t entrySize = nextEntryValue - entryValue; + + if(entryValue < 0) { + DebugHelper::error("(AssetTable::_parse_ttghost_table) Invalid table entry ", DebugHelper::to_hex(entryValue), " at rom offset ", DebugHelper::to_hex(offset)); + } + + _entries.push_back({entryValue, entrySize}); + + offset += 8; + } +} + +// Similar to _parse_variable_table, but each entry must be multiplied by 4. +void AssetTable::_parse_misc_table() { + uint32_t offset = _romOffset; + while(true) { + int32_t entryValue = (_rom->get_s32(offset)); + int32_t nextEntryValue = (_rom->get_s32(offset + 4)); + if(entryValue == -1 || nextEntryValue == -1) { + return; + } + int32_t entrySize = nextEntryValue - entryValue; + + entryValue *= 4; + entrySize *= 4; + + if(entryValue < 0) { + DebugHelper::error("(AssetTable::_parse_misc_table) Invalid table entry ", DebugHelper::to_hex(entryValue), " at rom offset ", DebugHelper::to_hex(offset)); + } + + _entries.push_back({entryValue, entrySize}); + + offset += 4; + } +} + +// Similar to _parse_variable_table, but the table itself doesn't start at index 0, so I have to manually add it. +void AssetTable::_parse_audio_table() { + uint32_t offset = _romOffset; + + int32_t firstEntrySize = _rom->get_s32(offset); + _entries.push_back({0, firstEntrySize}); + + while(true) { + int32_t entryValue = (_rom->get_s32(offset)); + int32_t nextEntryValue = (_rom->get_s32(offset + 4)); + if(entryValue == -1 || nextEntryValue == -1) { + return; + } + int32_t entrySize = nextEntryValue - entryValue; + + + if(entryValue < 0) { + DebugHelper::error("(AssetTable::_parse_audio_table) Invalid table entry ", DebugHelper::to_hex(entryValue), " at rom offset ", DebugHelper::to_hex(offset)); + } + + _entries.push_back({entryValue, entrySize}); + + offset += 4; + } +} + +std::unordered_map tableTypeMap = { + {"GameText", DkrAssetTableType::GameTextTable}, + {"MenuText", DkrAssetTableType::MenuTextTable}, + {"TTGhost", DkrAssetTableType::TTGhostTable}, + {"Miscellaneous", DkrAssetTableType::MiscTable}, + {"Audio", DkrAssetTableType::AudioTable}, +}; + +DkrAssetTableType AssetTable::table_type_from_section_type(const std::string §ionType) { + auto it = tableTypeMap.find(sectionType); + if(it != tableTypeMap.end()) { + return it->second; + } + return DkrAssetTableType::VariableTable; +} \ No newline at end of file diff --git a/tools/dkr_assets_tool_src/extract/assetTable.h b/tools/dkr_assets_tool_src/extract/assetTable.h new file mode 100644 index 00000000..e0fbebb9 --- /dev/null +++ b/tools/dkr_assets_tool_src/extract/assetTable.h @@ -0,0 +1,49 @@ +#pragma once + +#include +#include + +#include "helpers/debugHelper.h" +#include "rom.h" + +enum DkrAssetTableType { + FixedTable, // Starts with the length + VariableTable, // Ends with -1 + MenuTextTable, + GameTextTable, + TTGhostTable, + MiscTable, + AudioTable, +}; + +struct DkrTableEntryInfo { + int32_t offset; + int32_t length; +}; + +class AssetTable { +public: + AssetTable(DkrExtractROM *rom, uint32_t offset, DkrAssetTableType type = DkrAssetTableType::VariableTable); + ~AssetTable(); + + size_t size(); + + int32_t get_entry_offset(size_t entryIndex); + int32_t get_entry_size(size_t entryIndex); + + static DkrAssetTableType table_type_from_section_type(const std::string §ionType); + +private: + void _parse_fixed_table(); + void _parse_variable_table(); + void _parse_menutext_table(); + void _parse_gametext_table(); + void _parse_ttghost_table(); + void _parse_misc_table(); + void _parse_audio_table(); + + DkrExtractROM *_rom; + uint32_t _romOffset; + + std::vector _entries; +}; diff --git a/tools/dkr_assets_tool_src/extract/config.cpp b/tools/dkr_assets_tool_src/extract/config.cpp new file mode 100644 index 00000000..39756043 --- /dev/null +++ b/tools/dkr_assets_tool_src/extract/config.cpp @@ -0,0 +1,281 @@ +#include "config.h" + +#define INVALID_CONFIG_STR "" +#define INVALID_CONFIG_INT -1 + +DkrExtractConfig::DkrExtractConfig(std::string filepath){ + _filepath = filepath; + _isValid = _load_config(); +} + +DkrExtractConfig::~DkrExtractConfig() { +} + +bool DkrExtractConfig::is_valid() { + return _isValid; +} + +std::string DkrExtractConfig::get_dkr_version() { + if(!_isValid) { + return INVALID_CONFIG_STR; + } + return _configJson->get_string("/subfolder"); +} + +std::string DkrExtractConfig::get_name() { + if(!_isValid) { + return INVALID_CONFIG_STR; + } + return _configJson->get_string("/config-name"); +} + +std::string DkrExtractConfig::get_md5() { + if(!_isValid) { + return INVALID_CONFIG_STR; + } + return _configJson->get_string("/checksum-md5"); +} + +int DkrExtractConfig::get_revision() { + if(!_isValid) { + return INVALID_CONFIG_INT; + } + return _configJson->get_int("/revision"); +} + +bool DkrExtractConfig::_load_config() { + if(!JsonHelper::get().get_file(_filepath, &_configJson)) { + DebugHelper::warn("Could not load config: ", _filepath); + return false; + } + return true; +} + +void DkrExtractConfig::parse() { + DebugHelper::DebugTimer timer; + _parse_code_sections(); + _parse_asset_sections(); + DebugHelper::info_verbose("Took ", timer.elapsed(), " to parse config file"); +} + +std::string DkrExtractConfig::get_build_id_of_section(int sectionIndex) { + return assetSections[sectionIndex].buildId; +} + + +// Use AssetsHelper::get_build_id_of_index() instead. +/* +std::string DkrExtractConfig::get_build_id_of_file_from_section(std::string sectionBuildId, int fileIndex) { + // Make sure the build ID is valid. + DebugHelper::assert(_sectionIdToIndex.find(sectionBuildId) != _sectionIdToIndex.end(), + "(DkrExtractConfig::get_build_id_of_file_from_section) Section Build ID \"", sectionBuildId, "\" was not defined."); + + DkrExtractAssetSection &assetSection = assetSections[_sectionIdToIndex[sectionBuildId]]; + DkrExtractAssetSectionFile *file; + + if(fileIndex >= 0) { + file = assetSection.get_asset_section_file(fileIndex); + } else { + file = assetSection.get_single_file(); + } + + if(file != nullptr) { + return file->buildId; + } + + // file is null, so get a generic id. + if(fileIndex >= 0) { + return sectionBuildId + "_" + std::to_string(fileIndex); + } else { + return sectionBuildId; // Single files just use the build id of the section. + } +} +*/ + +// Returns the build id of the section that the table belongs to. Throws an error if it doesn't exist. +std::string DkrExtractConfig::get_build_id_of_section_from_table_id(std::string tableBuildId) { + // Make sure the build ID is valid. + DebugHelper::assert(_sectionIdToIndex.find(tableBuildId) != _sectionIdToIndex.end(), + "(DkrExtractConfig::get_build_id_of_section_from_table_id) Table Build ID \"", tableBuildId, "\" was not defined."); + + int tableIndex = _sectionIdToIndex[tableBuildId]; + + for(size_t i = 0; i < assetSections.size(); i++) { + if(assetSections[i].table == tableIndex) { + return assetSections[i].buildId; + } + } + + DebugHelper::error("(DkrExtractConfig::get_build_id_of_section_from_table_id) Could not find a section that uses the table \"", + tableBuildId, "\""); + + return std::string(); +} + +std::string DkrExtractConfig::get_folder_path_to_section(std::string sectionBuildId) { + // Make sure the build ID is valid. + DebugHelper::assert(_sectionIdToIndex.find(sectionBuildId) != _sectionIdToIndex.end(), + "(DkrExtractConfig::get_build_id_of_file_from_section) Section Build ID \"", sectionBuildId, "\" was not defined."); + + DkrExtractAssetSection &assetSection = assetSections[_sectionIdToIndex[sectionBuildId]]; + return assetSection.folder; +} + +std::string DkrExtractConfig::get_path_to_file(std::string sectionBuildId, int fileIndex) { + // Make sure the build ID is valid. + DebugHelper::assert(_sectionIdToIndex.find(sectionBuildId) != _sectionIdToIndex.end(), + "(DkrExtractConfig::get_build_id_of_file_from_section) Section Build ID \"", sectionBuildId, "\" was not defined."); + + DkrExtractAssetSection &assetSection = assetSections[_sectionIdToIndex[sectionBuildId]]; + DkrExtractAssetSectionFile *file; + + if(fileIndex >= 0) { + file = assetSection.get_asset_section_file(fileIndex); + } else { + file = assetSection.get_single_file(); + } + + DebugHelper::assert(file != nullptr, "(std::string get_path_to_file) File ", fileIndex, " was not specified."); + + return assetSection.folder / file->folder / file->filename; +} + +// May return nullptr +DkrExtractAssetSectionFile *DkrExtractAssetSection::get_asset_section_file(int index) { + for(DkrExtractAssetSectionFile &file : files) { + if(file.index == index) { + return &file; + } + } + return nullptr; +} + +// May return nullptr +DkrExtractAssetSectionFile *DkrExtractAssetSection::get_single_file() { + DebugHelper::assert(files.size() < 2, "(DkrExtractAssetSection::get_single_file) Section \"", type, "\" has more than one file!"); + + if(files.empty()) { + return nullptr; + } + + return &files[0]; +} + +void DkrExtractConfig::get_default_object_entries_order_array(std::vector &out) { + size_t len = _configJson->length_of_array("/assets/misc/default-object-entries-order"); + for(size_t i = 0; i < len; i++) { + out.push_back(_configJson->get_string("/assets/misc/default-object-entries-order/" + std::to_string(i))); + } +} + +void DkrExtractConfig::_parse_code_sections() { + int numOfCodeSections = _configJson->length_of_array("/code/sections"); + for(int i = 0; i < numOfCodeSections; i++) { + DkrExtractCodeSection codeSection; + codeSection.type = _configJson->get_string("/code/sections/" + std::to_string(i) + "/type"); + codeSection.folder = _configJson->get_string("/code/sections/" + std::to_string(i) + "/folder"); + FileHelper::format_folder_string(codeSection.folder); + DebugHelper::info_verbose("code section: ", codeSection.type, ", ", codeSection.folder); + + int numOfCodeFilesInSection = _configJson->length_of_array("/code/sections/" + std::to_string(i) + "/files"); + for(int j = 0; j < numOfCodeFilesInSection; j++) { + DkrExtractCodeSectionFile codeFile; + codeFile.filename = _configJson->get_string("/code/sections/" + std::to_string(i) + "/files/" + std::to_string(j) + "/filename"); + std::string lengthAsHex = _configJson->get_string("/code/sections/" + std::to_string(i) + "/files/" + std::to_string(j) + "/length"); + codeFile.length = std::stoi(lengthAsHex, 0, 16); + DebugHelper::info_verbose(" code file: ", codeFile.filename, ", ", DebugHelper::to_hex(codeFile.length)); + codeSection.files.push_back(codeFile); + } + + codeSections.push_back(codeSection); + } +} + +void DkrExtractConfig::_parse_asset_sections() { + int numOfAssetSections = _configJson->length_of_array("/assets/sections"); + for(int i = 0; i < numOfAssetSections; i++) { + DkrExtractAssetSection assetSection; + + assetSection.buildId = _configJson->get_string("/assets/sections/" + std::to_string(i) + "/build-id"); + assetSection.type = _configJson->get_string("/assets/sections/" + std::to_string(i) + "/type"); + assetSection.folder = _configJson->get_path("/assets/sections/" + std::to_string(i) + "/folder"); + assetSection.table = _configJson->get_int("/assets/sections/" + std::to_string(i) + "/table"); + + assetSection.isDeferred = _configJson->get_bool("/assets/sections/" + std::to_string(i) + "/defer", false); + + if(assetSection.isDeferred) { + std::string deferInfoPtr = "/assets/sections/" + std::to_string(i) + "/defer-info"; + assetSection.deferInfo.fromSection = _configJson->get_string(deferInfoPtr + "/from-section"); + assetSection.deferInfo.idPostfix = _configJson->get_string(deferInfoPtr + "/id-postfix"); + assetSection.deferInfo.outputPath = _configJson->get_path(deferInfoPtr + "/output-path"); + } + + // Defaults to group 0 if not specified. + assetSection.group = _configJson->get_int("/assets/sections/" + std::to_string(i) + "/group", 0); + + assetSection.filesDefaultFolder = _configJson->get_path("/assets/sections/" + std::to_string(i) + "/files-default-folder"); + assetSection.defaultBuildIdPrefix = _configJson->get_string("/assets/sections/" + std::to_string(i) + "/default-build-id-prefix"); + + bool isTexture = (assetSection.type == "Texture"); + bool isTable = (assetSection.type == "Table"); + bool isFonts = (assetSection.type == "Fonts"); + bool isMenuText = (assetSection.type == "MenuText"); + bool isMisc = (assetSection.type == "Miscellaneous"); + + if(isTexture) { + assetSection.specific.textures.flipTexturesByDefault = _configJson->get_bool( "/assets/sections/" + std::to_string(i) + "/flip-textures-by-default"); + } else if(isTable) { + assetSection.specific.tableData.forSection = _configJson->get_string( "/assets/sections/" + std::to_string(i) + "/for"); + } else if(isFonts) { + _configJson->get_array( "/assets/sections/" + std::to_string(i) + "/font-names", assetSection.specific.fonts.fontNames); + } else if(isMenuText) { + _configJson->get_array( "/assets/sections/" + std::to_string(i) + "/language-order", assetSection.specific.menuText.languageOrder); + _configJson->get_array( "/assets/sections/" + std::to_string(i) + "/menu-text-build-ids", assetSection.specific.menuText.menuTextBuildIds); + } + + DebugHelper::info_verbose("asset section: ", assetSection.buildId, ",", + assetSection.type, ",", + assetSection.folder, ",", + assetSection.table, ",", + assetSection.filesDefaultFolder, ",", + assetSection.defaultBuildIdPrefix); + + if(_configJson->has("/assets/sections/" + std::to_string(i) + "/files")) { + int numOfAssetFilesInSection = _configJson->length_of_array("/assets/sections/" + std::to_string(i) + "/files"); + for(int j = 0; j < numOfAssetFilesInSection; j++) { + + std::string filePtr = "/assets/sections/" + std::to_string(i) + "/files/" + std::to_string(j); + + DkrExtractAssetSectionFile assetFile; + assetFile.section = &assetSection; + assetFile.index = _configJson->get_int(filePtr + "/index", -1); + assetFile.filename = _configJson->get_string(filePtr + "/filename", ""); + assetFile.buildId = _configJson->get_string(filePtr + "/build-id", ""); + assetFile.folder = _configJson->get_path(filePtr + "/folder", ""); + + if(isTexture) { + assetFile.specific.texture.flipTex = _configJson->get_bool(filePtr + "/flip-tex", assetSection.specific.textures.flipTexturesByDefault); + } else if(isMenuText) { + assetFile.specific.menuText.language = _configJson->get_string("/assets/sections/" + std::to_string(i) + "/language-order/" + std::to_string(j)); + } else if(isMisc) { + // Set to "Binary" by default if not specified. + assetFile.specific.misc.miscType = _configJson->get_string(filePtr + "/misc-type", "Binary"); + } + + DebugHelper::info_verbose(" asset file: ", assetFile.index, ",", assetFile.filename, ",", assetFile.buildId, ",", assetFile.folder); + assetSection.files.push_back(assetFile); + } + } + + assetSections.push_back(assetSection); + } + _populate_sectionIdToIndex_map(); +} + +void DkrExtractConfig::_populate_sectionIdToIndex_map() { + for(size_t i = 0; i < assetSections.size(); i++) { + DkrExtractAssetSection &assetSection = assetSections[i]; + _sectionIdToIndex[assetSection.buildId] = i; + } +} + diff --git a/tools/dkr_assets_tool_src/extract/config.h b/tools/dkr_assets_tool_src/extract/config.h new file mode 100644 index 00000000..8f23800d --- /dev/null +++ b/tools/dkr_assets_tool_src/extract/config.h @@ -0,0 +1,153 @@ +#pragma once + +#include +#include +#include + +#include "helpers/jsonHelper.h" +#include "helpers/debugHelper.h" +#include "helpers/fileHelper.h" + + +/*******************************************************/ + +struct DkrExtractCodeSectionFile { + std::string filename; + uint32_t length; +}; + +struct DkrExtractCodeSection { + std::string type; + fs::path folder; // directory to extract to + std::vector files; +}; + +/*******************************************************/ + +struct DkrExtractAssetSectionFileMenuText { + std::string language; +}; + +struct DkrExtractAssetSectionFileTexture { + bool flipTex = false; // Should the texture be flipped vertically? (No by default) +}; + +struct DkrExtractAssetSectionFileMisc { + std::string miscType; // Defaults to "Binary" +}; + +// TODO: Refactor this into a union. +struct DkrExtractAssetSectionFileSpecific { // section specific info + DkrExtractAssetSectionFileTexture texture; + DkrExtractAssetSectionFileMenuText menuText; + DkrExtractAssetSectionFileMisc misc; +}; + +struct DkrExtractAssetSection; + +struct DkrExtractAssetSectionFile { + // Pointer to the section this belong to. Wish this was a reference instead, but it ended up being a big hassle. + struct DkrExtractAssetSection *section = nullptr; + int index; + std::string buildId; // Id for the file. + std::string filename; + fs::path folder; // directory to extract to + DkrExtractAssetSectionFileSpecific specific; +}; + +/************************/ + +struct DkrExtractTexturesSection { + bool flipTexturesByDefault; +}; + +struct DkrExtractTableSection { + std::string forSection; +}; + +struct DkrExtractFontsSection { + std::vector fontNames; +}; + +struct DkrExtractMenuTextSection { + // Set in extractor.c + size_t numberOfTextEntries; // Number of entries per each language. + // Set in config.c + std::vector languageOrder; + std::vector menuTextBuildIds; +}; + +// TODO: Refactor this into a union. +struct DkrExtractAssetSectionSpecific { // section specific info + DkrExtractTexturesSection textures; + DkrExtractTableSection tableData; + DkrExtractFontsSection fonts; + DkrExtractMenuTextSection menuText; +}; + +struct DeferInfo { + std::string fromSection; + std::string idPostfix; + std::string outputPath; +}; + +struct DkrExtractAssetSection { + std::string buildId; // Id for the section. + std::string type; + fs::path folder; // directory to extract to + int table; + int group; // Extraction group. (Need to delay some groups to make sure things are in the correct order). + std::string filesDefaultFolder; + std::string defaultBuildIdPrefix; + DkrExtractAssetSectionSpecific specific; + std::vector files; + bool isDeferred; + DeferInfo deferInfo; + + // May return null + DkrExtractAssetSectionFile *get_asset_section_file(int index); + // May return null + DkrExtractAssetSectionFile *get_single_file(); +}; + +/*******************************************************/ + +class DkrExtractConfig { +public: + DkrExtractConfig(std::string filepath); + ~DkrExtractConfig(); + + std::string get_dkr_version(); + std::string get_name(); + std::string get_md5(); + int get_revision(); + bool is_valid(); + void parse(); + + std::vector codeSections; + std::vector assetSections; + + std::string get_build_id_of_section(int sectionIndex); + + // Use AssetsHelper::get_build_id_of_index() instead. + //std::string get_build_id_of_file_from_section(std::string sectionBuildId, int fileIndex=-1); + + std::string get_folder_path_to_section(std::string sectionBuildId); + std::string get_path_to_file(std::string sectionBuildId, int fileIndex=-1); + + // Retrives the build id of the section that the table represents. + std::string get_build_id_of_section_from_table_id(std::string tableBuildId); + + void get_default_object_entries_order_array(std::vector &out); +private: + JsonFile *_configJson; + bool _isValid; + fs::path _filepath; + bool _load_config(); + + void _parse_code_sections(); + void _parse_asset_sections(); + + std::unordered_map _sectionIdToIndex; + void _populate_sectionIdToIndex_map(); +}; diff --git a/tools/dkr_assets_tool_src/extract/extractInfo.cpp b/tools/dkr_assets_tool_src/extract/extractInfo.cpp new file mode 100644 index 00000000..994c2a5a --- /dev/null +++ b/tools/dkr_assets_tool_src/extract/extractInfo.cpp @@ -0,0 +1,137 @@ +#include "extractInfo.h" +#include + +void DeferredExtractions::add_extraction(std::string key, ExtractInfo newExtract) { + if(_extractions.find(key) == _extractions.end()) { + _extractions[key] = std::vector(); + } + _extractions[key].push_back(newExtract); +} + +ExtractInfo &DeferredExtractions::get_extraction(std::string key, size_t index) { + DebugHelper::assert(_extractions.find(key) != _extractions.end(), + "(DeferredExtractions::get_extraction) \"", key, "\" not in map."); + DebugHelper::assert(index < _extractions[key].size(), + "(DeferredExtractions::get_extraction) index ", index, " for key \"", key, "\" is out of range."); + return _extractions[key][index]; +} + +/*****************************************************/ + +ExtractInfo::ExtractInfo(std::string &type, fs::path filename, fs::path folder, DkrExtractROM *rom, DkrExtractConfig *config, CContext *ctx, uint32_t dataOffset, size_t dataLength, size_t fileIndex) +: rom(rom), config(config), c_context(ctx), _type(type), _filename(filename), _folder(folder), _dataOffset(dataOffset), _dataLength(dataLength), _fileIndex(fileIndex), _isAsset(false) +{ + _check_params(); +} + +ExtractInfo::ExtractInfo(std::string &type, fs::path filename, fs::path folder, DkrExtractROM *rom, DkrExtractConfig *config, CContext *ctx, uint32_t dataOffset, size_t dataLength, size_t fileIndex, DkrExtractAssetSection *assetSection) +: assetSection(assetSection), rom(rom), config(config), c_context(ctx), _type(type), _filename(filename), _folder(folder), _dataOffset(dataOffset), _dataLength(dataLength), _fileIndex(fileIndex), _isAsset(true) +{ + if(_filename.empty()) { + DebugHelper::error("No filename was set for the type \"", _type, "\" in the folder \"", folder, "\""); + } + _check_params(); +} + +ExtractInfo::~ExtractInfo(){ + +} + +void ExtractInfo::set_tag(const std::string &key, const std::any value) { + _tags[key] = value; +} + +/* +void ExtractInfo::set_tag_as_array(const std::string &key, size_t numElements) { + _tags[key] = std::vector(numElements); +} + +void ExtractInfo::add_elem_to_tag_array(const std::string &key, ExtractInfoTagValue elem, int32_t index) { + std::vector &arr = std::get>(_tags[key]); + if(index < 0) { + arr.push_back(elem); + return; + } + arr[index] = elem; +} +*/ + +bool ExtractInfo::is_asset() { + return _isAsset; +} + +std::string ExtractInfo::get_type() { + return _type; +} + +fs::path ExtractInfo::get_folder() { + return _folder; +} + +fs::path ExtractInfo::get_filename(const char *extension) { + fs::path out = _filename; + if(extension[0] != '\0') { + out.replace_extension(extension); + } + return out; +} + +uint32_t ExtractInfo::get_data_offset() { + return _dataOffset; +} + +size_t ExtractInfo::get_data_size() { + return _dataLength; +} + +size_t ExtractInfo::get_file_index() { + return _fileIndex; +} + +fs::path ExtractInfo::get_out_filepath(const char *extension) { + fs::path out = _folder / _filename; + if(assetSection != nullptr) { + out = assetSection->folder / out; + } + if(extension[0] != '\0') { + out.replace_extension(extension); + } + return out; +} + +fs::path ExtractInfo::get_out_folder() { + fs::path out = _folder; + if(assetSection != nullptr) { + out = assetSection->folder / out; + } + return out; +} + +void ExtractInfo::get_data_from_rom(std::vector &out) { + rom->get_data(_dataOffset, _dataLength, out); +} + +void ExtractInfo::write_rom_data_to_file(fs::path finalFilepath, uint32_t offset, int32_t length) { + if(length < 0) { + length = (int32_t)_dataLength; + if(length < 1) { + DebugHelper::info_verbose("Auto-set length to ", _dataLength); + } + } + if(length < 1) { + DebugHelper::error("(ExtractInfo::write_rom_data_to_file) Invalid length of ", length, " for path ", finalFilepath); + } + + if((size_t)(offset + length) > _dataLength) { + DebugHelper::error("(ExtractInfo::write_rom_data_to_file) Out of bounds! (offset + length) was larger than dataLength for path ", finalFilepath); + } + + rom->write_rom_section_to_binary_file(finalFilepath, _dataOffset + offset, length); +} + +void ExtractInfo::_check_params() { + if(_type == "GameText") { + _tags["dialog"] = (_dataOffset & 0x80000000) != 0; + _dataOffset &= 0x7FFFFFFF; + } +} diff --git a/tools/dkr_assets_tool_src/extract/extractInfo.h b/tools/dkr_assets_tool_src/extract/extractInfo.h new file mode 100644 index 00000000..fa1309d2 --- /dev/null +++ b/tools/dkr_assets_tool_src/extract/extractInfo.h @@ -0,0 +1,94 @@ +#pragma once + +#include +#include +#include +#include + +#include "helpers/fileHelper.h" +#include "helpers/debugHelper.h" +#include "rom.h" +#include "config.h" + +#include "helpers/c/cContext.h" + +class ExtractInfo; + +class DeferredExtractions { +public: + static DeferredExtractions& get() { + static DeferredExtractions instance; + return instance; + } + + void add_extraction(std::string key, ExtractInfo newExtract); + ExtractInfo &get_extraction(std::string key, size_t index); +private: + std::unordered_map> _extractions; +}; + +class ExtractInfo { +public: + // Code file info + ExtractInfo(std::string &type, fs::path filename, fs::path folder, DkrExtractROM *rom, DkrExtractConfig *config, CContext *ctx, + uint32_t dataOffset, size_t dataLength, size_t fileIndex); + // Asset file info + ExtractInfo(std::string &type, fs::path filename, fs::path folder, DkrExtractROM *rom, DkrExtractConfig *config, CContext *ctx, + uint32_t dataOffset, size_t dataLength, size_t fileIndex, DkrExtractAssetSection *assetSection); + ~ExtractInfo(); + + void set_tag(const std::string &key, const std::any elem); + //void set_tag_as_array(const std::string &key, size_t numElements=1); + //void add_elem_to_tag_array(const std::string &key, const ExtractInfoTagValue elem, int32_t index=-1); + + template + T get_tag(const std::string &key, T defaultValue) { + if(_tags.find(key) == _tags.end()) { + return defaultValue; + } + + return std::any_cast(_tags[key]); + } + + // There may or may not be a pointer to a DkrExtractAssetSection. Code sections will not have it for obvious reasons. + // TODO: I think I'm just being lazy here. Probably needs to be refactored. + DkrExtractAssetSection *assetSection = nullptr; + + DkrExtractROM *rom; + DkrExtractConfig *config; + + CContext *c_context; // C Code context. (For loading enums & structs) + + bool is_asset(); + + std::string get_type(); + fs::path get_folder(); + fs::path get_filename(const char *extension = "\0"); + fs::path get_out_filepath(const char *extension = "\0"); + fs::path get_out_folder(); + + uint32_t get_data_offset(); + size_t get_data_size(); + + size_t get_file_index(); + + void get_data_from_rom(std::vector &out); + + void write_rom_data_to_file(fs::path finalFilepath, uint32_t offset=0, int32_t length=-1); + +private: + + std::string _type; + fs::path _filename; + fs::path _folder; + uint32_t _dataOffset; + size_t _dataLength; + + size_t _fileIndex; + + bool _isAsset; + + std::unordered_map _tags; + + void _check_params(); +}; diff --git a/tools/dkr_assets_tool_src/extract/extractTypes/extractAudio.cpp b/tools/dkr_assets_tool_src/extract/extractTypes/extractAudio.cpp new file mode 100644 index 00000000..d3090bd0 --- /dev/null +++ b/tools/dkr_assets_tool_src/extract/extractTypes/extractAudio.cpp @@ -0,0 +1,28 @@ +#include "extractAudio.h" + +#include "helpers/jsonHelper.h" + +ExtractAudio::ExtractAudio(DkrAssetsSettings &settings, ExtractInfo &info) : _settings(settings), _info(info) { + fs::path _outFilepath = _settings.pathToAssets / _info.get_out_filepath(".json"); + DebugHelper::info_custom("Extracting Audio", YELLOW_TEXT, _outFilepath); + + WritableJsonFile jsonFile(_outFilepath); + + jsonFile.set_string("/type", "Audio"); + + fs::path _outRawFilepath = _settings.pathToAssets / _info.get_out_filepath(".bin"); + + if(_info.get_data_size() == 0) { // File 12 is empty for some reason. ¯\_(ツ)_/¯ + jsonFile.set_null("/raw"); + } else { + jsonFile.set_path("/raw", _info.get_filename(".bin")); + _info.write_rom_data_to_file(_outRawFilepath); + } + + + jsonFile.save(); + +} + +ExtractAudio::~ExtractAudio() { +} diff --git a/tools/dkr_assets_tool_src/extract/extractTypes/extractAudio.h b/tools/dkr_assets_tool_src/extract/extractTypes/extractAudio.h new file mode 100644 index 00000000..88d16027 --- /dev/null +++ b/tools/dkr_assets_tool_src/extract/extractTypes/extractAudio.h @@ -0,0 +1,13 @@ +#pragma once + +#include "extract/extractInfo.h" +#include "misc/settings.hpp" + +class ExtractAudio { +public: + ExtractAudio(DkrAssetsSettings &settings, ExtractInfo &info); + ~ExtractAudio(); +private: + DkrAssetsSettings &_settings; + ExtractInfo &_info; +}; diff --git a/tools/dkr_assets_tool_src/extract/extractTypes/extractBinary.cpp b/tools/dkr_assets_tool_src/extract/extractTypes/extractBinary.cpp new file mode 100644 index 00000000..b9a797b9 --- /dev/null +++ b/tools/dkr_assets_tool_src/extract/extractTypes/extractBinary.cpp @@ -0,0 +1,31 @@ +#include "extractBinary.h" + +ExtractBinary::ExtractBinary(DkrAssetsSettings &settings, ExtractInfo &info) : _settings(settings), _info(info) { + if(_info.is_asset()) { + _extract_as_asset(); + } else { + _extract_as_code(); + } +} +ExtractBinary::~ExtractBinary() { +} + +void ExtractBinary::_extract_as_asset() { + fs::path _outRawFilepath = _settings.pathToAssets / _info.get_out_filepath(".bin"); + fs::path _outFilepath = _settings.pathToAssets / _info.get_out_filepath(".json"); + DebugHelper::info_custom("Extracting Asset Binary", YELLOW_TEXT, _outFilepath); + + WritableJsonFile jsonFile(_outFilepath); + jsonFile.set_path("/raw", _info.get_filename(".bin")); + jsonFile.set_string("/type", "Binary"); + + jsonFile.save(); + + _info.write_rom_data_to_file(_outRawFilepath); +} + +void ExtractBinary::_extract_as_code() { + fs::path _outFilepath = _settings.pathToRepo / _info.get_out_filepath(".bin"); + DebugHelper::info_custom("Extracting Code Binary", YELLOW_TEXT, _outFilepath); + _info.write_rom_data_to_file(_outFilepath); +} diff --git a/tools/dkr_assets_tool_src/extract/extractTypes/extractBinary.h b/tools/dkr_assets_tool_src/extract/extractTypes/extractBinary.h new file mode 100644 index 00000000..4bac8e92 --- /dev/null +++ b/tools/dkr_assets_tool_src/extract/extractTypes/extractBinary.h @@ -0,0 +1,21 @@ +#pragma once + +#include +#include "extract/extractInfo.h" +#include "misc/settings.hpp" + +#include "helpers/debugHelper.h" +#include "helpers/fileHelper.h" +#include "helpers/jsonHelper.h" + +class ExtractBinary { +public: + ExtractBinary(DkrAssetsSettings &settings, ExtractInfo &info); + ~ExtractBinary(); +private: + DkrAssetsSettings &_settings; + ExtractInfo &_info; + + void _extract_as_asset(); + void _extract_as_code(); +}; diff --git a/tools/dkr_assets_tool_src/extract/extractTypes/extractFonts.cpp b/tools/dkr_assets_tool_src/extract/extractTypes/extractFonts.cpp new file mode 100644 index 00000000..ef987427 --- /dev/null +++ b/tools/dkr_assets_tool_src/extract/extractTypes/extractFonts.cpp @@ -0,0 +1,86 @@ +#include "extractFonts.h" + +#include "helpers/assetsHelper.h" +#include "helpers/stringHelper.h" + +#include "fileTypes/fonts.hpp" + +ExtractFonts::ExtractFonts(DkrAssetsSettings &settings, ExtractInfo &info) : _settings(settings), _info(info) { + fs::path _outFilepath = _settings.pathToAssets / _info.get_out_filepath(".json"); + DebugHelper::info_custom("Extracting Font", YELLOW_TEXT, _outFilepath); + + WritableJsonFile jsonFile(_outFilepath); + jsonFile.set_string("/type", "Fonts"); + + std::vector rawBytes; + _info.get_data_from_rom(rawBytes); + + FontData *fontsData = reinterpret_cast(&rawBytes[0]); + + for(int i = 0; i < (int)fontsData->numberOfFonts; i++) { + FontFile &font = fontsData->fonts[i]; + + std::string fontName(font.name); + std::string fontBuildId = info.assetSection->buildId + "_" + fontName; + StringHelper::make_uppercase(fontBuildId); + fs::path fontLocalPath = FONTS_SUBDIRECTORY / (fontName + ".meta.json"); + fs::path _outFontFilepath = _settings.pathToAssets / _info.get_out_folder() / fontLocalPath; + + jsonFile.set_string("/fonts-order/" + std::to_string(i), fontBuildId); + jsonFile.set_string("/fonts/" + fontBuildId, fontLocalPath); + + WritableJsonFile fontJsonFont(_outFontFilepath); + + fontJsonFont.set_string("/name", fontName); + fontJsonFont.set_int("/fixed-width", font.fixedWidth); + fontJsonFont.set_int("/y-offset", font.yOffset); + fontJsonFont.set_int("/special-character-width", font.specialCharacterWidth); + fontJsonFont.set_int("/tab-width", font.tabWidth); + + fontJsonFont.set_string("/encoding/type", "ASCII"); + + fontJsonFont.set_string("/junk-text", font.junkText); + + for(int j = 0; j < FONTS_NUMBER_OF_TEXTURE_INDICES; j++) { + if(font.textureIndices[j] == -1) { + fontJsonFont.set_null("/textures/" + std::to_string(j) + ""); + continue; + } + std::string texBuildId = AssetsHelper::get_build_id_of_index(_settings, "ASSET_TEXTURES_2D", font.textureIndices[j]); + fontJsonFont.set_string("/textures/" + std::to_string(j) + "", texBuildId); + } + + for(int j = FONTS_START_CHAR; j < FONTS_START_CHAR + FONTS_NUMBER_OF_CHARACTERS; j++) { + FontCharacter &charInfo = font.characters[j - FONTS_START_CHAR]; + + std::string charPtr = "/characters/"; + + if(j == '~') { + charPtr += "~0"; // Tilde + } else if(j == '/') { + charPtr += "~1"; // Frontslash + } else if(j == 127) { + charPtr += "DEL"; // Delete + } else { + charPtr += (char)j; + } + + fontJsonFont.set_int(charPtr + "/tex-index", charInfo.texIndex); + fontJsonFont.set_int_if_not_zero(charPtr + "/char-width", charInfo.charWidth); + fontJsonFont.set_int_if_not_zero(charPtr + "/offset/x", charInfo.offsetX); + fontJsonFont.set_int_if_not_zero(charPtr + "/offset/y", charInfo.offsetY); + fontJsonFont.set_int(charPtr + "/uv/u", charInfo.texU); + fontJsonFont.set_int(charPtr + "/uv/v", charInfo.texV); + fontJsonFont.set_int_if_not_zero(charPtr + "/tex-size/width", charInfo.texWidth); + fontJsonFont.set_int_if_not_zero(charPtr + "/tex-size/height", charInfo.texHeight); + + } + + fontJsonFont.save(); + } + + jsonFile.save(); +} + +ExtractFonts::~ExtractFonts() { +} diff --git a/tools/dkr_assets_tool_src/extract/extractTypes/extractFonts.h b/tools/dkr_assets_tool_src/extract/extractTypes/extractFonts.h new file mode 100644 index 00000000..2a2b5043 --- /dev/null +++ b/tools/dkr_assets_tool_src/extract/extractTypes/extractFonts.h @@ -0,0 +1,18 @@ +#pragma once + +#include +#include "extract/extractInfo.h" +#include "misc/settings.hpp" + +#include "helpers/debugHelper.h" +#include "helpers/fileHelper.h" +#include "helpers/jsonHelper.h" + +class ExtractFonts { +public: + ExtractFonts(DkrAssetsSettings &settings, ExtractInfo &info); + ~ExtractFonts(); +private: + DkrAssetsSettings &_settings; + ExtractInfo &_info; +}; diff --git a/tools/dkr_assets_tool_src/extract/extractTypes/extractGameText.cpp b/tools/dkr_assets_tool_src/extract/extractTypes/extractGameText.cpp new file mode 100644 index 00000000..0062a01e --- /dev/null +++ b/tools/dkr_assets_tool_src/extract/extractTypes/extractGameText.cpp @@ -0,0 +1,164 @@ +#include "extractGameText.h" + +#include "fileTypes/gameText.hpp" + +#include "helpers/jsonHelper.h" +#include "helpers/fileHelper.h" +#include "helpers/assetsHelper.h" + +ExtractGameText::ExtractGameText(DkrAssetsSettings &settings, ExtractInfo &info) : _settings(settings), _info(info) { + _outFilepath = _settings.pathToAssets / _info.get_out_filepath(".json"); + DebugHelper::info_custom("Extracting Game Text", YELLOW_TEXT, _outFilepath); + + std::vector rawBytes; + _info.get_data_from_rom(rawBytes); + + bool isDialog = _info.get_tag("dialog", false); + + WritableJsonFile jsonFile(_outFilepath); + + jsonFile.set_string("/text-type", isDialog ? "Dialog" : "Textbox"); + jsonFile.set_string("/type", "GameText"); + + if(isDialog) { + _extract_dialog(jsonFile, rawBytes); + } else { + _extract_textbox(jsonFile, rawBytes); + } + + jsonFile.save(); +} + +ExtractGameText::~ExtractGameText() { +} + +void ExtractGameText::_extract_dialog(WritableJsonFile &jsonFile, std::vector &rawBytes) { + fs::path _outRawFilepath = _settings.pathToAssets / _info.get_out_filepath(".bin"); + jsonFile.set_path("/raw", _info.get_filename(".bin")); + FileHelper::write_binary_file(rawBytes, _outRawFilepath, true); +} + +void ExtractGameText::_extract_textbox(WritableJsonFile &jsonFile, std::vector &rawBytes) { + int currentPage = 0; + int commandCount = 0; + std::string topPtr = "/pages"; + std::string middlePtr = topPtr + "/" + std::to_string(currentPage); + + bool end = false; + + size_t offset = 0; + size_t dataLength = rawBytes.size(); + + while((offset < dataLength) && !end) { + uint8_t command = rawBytes[offset++]; + std::string ptr = middlePtr + "/" + std::to_string(commandCount++); + + switch(command) { + case 0: // End of textbox commands + end = true; + break; + case 1: // Next page + currentPage++; + middlePtr = topPtr + "/" + std::to_string(currentPage); + ptr = middlePtr + "/" + std::to_string(commandCount); + commandCount = 0; + break; + case 2: // Unused + break; + case 3: // Set Font + { + SetFontCommand *fontCmd = reinterpret_cast(&rawBytes[offset]); + JsonFile *fontsFile = AssetsHelper::get_asset_json(_settings, "ASSET_FONTS"); + std::string fontBuildId = fontsFile->get_string("/fonts-order/" + std::to_string(fontCmd->fontId)); + DebugHelper::assert(!fontBuildId.empty(), "(ExtractGameText::_extract_textbox) Invalid font id: ", fontCmd->fontId); + jsonFile.set_string(ptr + "/command", TEXTBOX_COMMANDS[command]); + jsonFile.set_string(ptr + "/value", fontBuildId); + offset += sizeof(SetFontCommand); + break; + } + case 4: // Set Border + { + SetBorderCommand *borderCmd = reinterpret_cast(&rawBytes[offset]); + jsonFile.set_string(ptr + "/command", TEXTBOX_COMMANDS[command]); + jsonFile.set_int(ptr + "/value/left", borderCmd->left); + jsonFile.set_int(ptr + "/value/top", borderCmd->top); + jsonFile.set_int(ptr + "/value/right", borderCmd->right); + jsonFile.set_int(ptr + "/value/bottom", borderCmd->bottom); + offset += sizeof(SetBorderCommand); + break; + } + case 5: // Set Colour + { + SetColourCommand *colourCmd = reinterpret_cast(&rawBytes[offset]); + jsonFile.set_string(ptr + "/command", TEXTBOX_COMMANDS[command]); + jsonFile.set_int(ptr + "/value/red", colourCmd->red); + jsonFile.set_int(ptr + "/value/green", colourCmd->green); + jsonFile.set_int(ptr + "/value/blue", colourCmd->blue); + jsonFile.set_int(ptr + "/value/alpha", colourCmd->alpha); + offset += sizeof(SetColourCommand); + break; + } + case 6: // Set Alignment + { + SetAlignmentCommand *alignCmd = reinterpret_cast(&rawBytes[offset]); + jsonFile.set_string(ptr + "/command", TEXTBOX_COMMANDS[command]); + jsonFile.set_string(ptr + "/value", (alignCmd->value == 0) ? "center" : "left"); + offset += sizeof(SetAlignmentCommand); + break; + } + case 7: // Currently unknown + { + Unknown7Command *unk7Cmd = reinterpret_cast(&rawBytes[offset]); + jsonFile.set_string(ptr + "/command", TEXTBOX_COMMANDS[command]); + jsonFile.set_int(ptr + "/value", unk7Cmd->value); + offset += sizeof(Unknown7Command); + break; + } + case 8: // Add Vertical Spacing + { + AddVerticalSpacingCommand *vertSpacingCmd = reinterpret_cast(&rawBytes[offset]); + jsonFile.set_string(ptr + "/command", TEXTBOX_COMMANDS[command]); + jsonFile.set_int(ptr + "/value", vertSpacingCmd->value); + offset += sizeof(AddVerticalSpacingCommand); + break; + } + case 9: // Set Line Height + { + SetLineHeightCommand *lineHeightCmd = reinterpret_cast(&rawBytes[offset]); + jsonFile.set_string(ptr + "/command", TEXTBOX_COMMANDS[command]); + jsonFile.set_int(ptr + "/value", lineHeightCmd->value); + offset += sizeof(SetLineHeightCommand); + break; + } + case 10: // Set Timer + { + SetTimerCommand *timerCmd = reinterpret_cast(&rawBytes[offset]); + jsonFile.set_string(ptr + "/command", TEXTBOX_COMMANDS[command]); + jsonFile.set_int(ptr + "/value", timerCmd->value); + offset += sizeof(SetTimerCommand); + break; + } + case 11: // Allow User Input + { + AllowUserInputCommand *userInputCmd = reinterpret_cast(&rawBytes[offset]); + jsonFile.set_string(ptr + "/command", TEXTBOX_COMMANDS[command]); + jsonFile.set_int(ptr + "/value", userInputCmd->value); + offset += sizeof(AllowUserInputCommand); + break; + } + default: + { + char *text = reinterpret_cast(&rawBytes[--offset]); + jsonFile.set_string(ptr + "/command", "Text"); + jsonFile.set_string(ptr + "/value", text); + while(rawBytes[offset] != 0) { + offset++; + } + offset++; + break; + } + } + } +} + + diff --git a/tools/dkr_assets_tool_src/extract/extractTypes/extractGameText.h b/tools/dkr_assets_tool_src/extract/extractTypes/extractGameText.h new file mode 100644 index 00000000..622f0c71 --- /dev/null +++ b/tools/dkr_assets_tool_src/extract/extractTypes/extractGameText.h @@ -0,0 +1,17 @@ +#pragma once + +#include "extract/extractInfo.h" +#include "misc/settings.hpp" + +class ExtractGameText { +public: + ExtractGameText(DkrAssetsSettings &settings, ExtractInfo &info); + ~ExtractGameText(); +private: + DkrAssetsSettings &_settings; + ExtractInfo &_info; + fs::path _outFilepath; + + void _extract_dialog(WritableJsonFile &jsonFile, std::vector &rawBytes); + void _extract_textbox(WritableJsonFile &jsonFile, std::vector &rawBytes); +}; diff --git a/tools/dkr_assets_tool_src/extract/extractTypes/extractLevelHeader.cpp b/tools/dkr_assets_tool_src/extract/extractTypes/extractLevelHeader.cpp new file mode 100644 index 00000000..b80010be --- /dev/null +++ b/tools/dkr_assets_tool_src/extract/extractTypes/extractLevelHeader.cpp @@ -0,0 +1,264 @@ +#include "extractLevelHeader.h" + +#include +#include + +#include "helpers/debugHelper.h" +#include "helpers/assetsHelper.h" +#include "helpers/jsonHelper.h" +#include "helpers/stringHelper.h" +#include "helpers/c/cContext.h" + +ExtractLevelHeader::ExtractLevelHeader(DkrAssetsSettings &settings, ExtractInfo &info) : _settings(settings), _info(info) { + fs::path _outFilepath = _settings.pathToAssets / _info.get_out_filepath(".json"); + DebugHelper::info_custom("Extracting Level Header", YELLOW_TEXT, _outFilepath); + + std::vector rawBytes; + _info.get_data_from_rom(rawBytes); + + LevelHeader *header = reinterpret_cast(&rawBytes[0]); + + WritableJsonFile jsonFile(_outFilepath); + jsonFile.set_string("/type", "LevelHeader"); + + // Name + _extract_name(jsonFile, "/name"); + + // World ID + std::string worldId = _info.c_context->get_symbol_of_enum_int("World", header->world); + jsonFile.set_string("/world", worldId); + + // Course Height + jsonFile.set_float("/course-height", header->courseHeight); + + // Track ID + std::string levelModelId = AssetsHelper::get_build_id_of_index(_settings, "ASSET_LEVEL_MODELS", header->geometry); + jsonFile.set_string("/model", levelModelId); + + // Object Maps + std::string collectablesMap = AssetsHelper::get_build_id_of_index(_settings, "ASSET_LEVEL_OBJECT_MAPS", header->collectablesObjMap); + std::string objMap2 = AssetsHelper::get_build_id_of_index(_settings, "ASSET_LEVEL_OBJECT_MAPS", header->objectMap2); + jsonFile.set_string("/map-collectables", collectablesMap); + jsonFile.set_string("/map-2", objMap2); + + // Other + jsonFile.set_int_if_not_zero("/max-velocity", header->velocityCap); + jsonFile.set_int("/fov", header->cameraFOV); + jsonFile.set_int_if_not_value("/lap-count", header->laps, 3); + + // Pulsing light data + be_int32_t pulsatingLightsOffset = header->pulseLightData; + if(pulsatingLightsOffset != -1) { + std::string pulseId = AssetsHelper::get_build_id_of_index(_settings, "ASSET_MISC", pulsatingLightsOffset); + jsonFile.set_string("/pulsating-lights", pulseId); + } + + // Race Type + std::string raceTypeId = _info.c_context->get_symbol_of_enum_int("RaceType", header->raceType); + jsonFile.set_string("/race-type", raceTypeId); + + // Audio related + jsonFile.set_int("/music", header->music); + jsonFile.set_int("/instruments", header->instruments); + + // Misc assets + for(size_t i = 0; i < 7; i++) { + if(header->miscAssets[i] == -1) { + continue; + } + + std::string miscAssetId = AssetsHelper::get_build_id_of_index(_settings, + "ASSET_MISC", header->miscAssets[i]); + + jsonFile.set_string("/misc-assets/" + std::to_string(i), miscAssetId); + } + + // Vehicle info + std::string defaultVehicle = _info.c_context->get_symbol_of_enum_int("Vehicle", header->vehicle); + jsonFile.set_string("/default-vehicle", defaultVehicle); + _extract_enum_bitfield(jsonFile, "/avaliable-vehicles", "Vehicle", header->avaliableVehicles); + + // AI levels + _extract_ai_levels(jsonFile, "/ai-levels/adv1", header->adv1AiLevels); + _extract_ai_levels(jsonFile, "/ai-levels/adv2", header->adv2AiLevels); + + // Weather + _extract_weather(jsonFile, "/weather", header->weather); + + // Fog + _extract_fog(jsonFile, "/fog", header->fog); + + // Background related stuff + if(header->skybox >= 0) { + std::string skyboxObjId = AssetsHelper::get_build_id_of_index(_settings, "ASSET_OBJECTS", header->skybox); + jsonFile.set_string("/background/skybox/id", skyboxObjId); + } + if(header->specialSky != 0) { + jsonFile.set_int("/background/skybox/special-sky", header->specialSky); + jsonFile.set_int("/background/skybox/special-sky-texture", header->specialSkyTexture); + } + jsonFile.set_int("/background/colour/red", header->bgColour[0]); + jsonFile.set_int("/background/colour/green", header->bgColour[1]); + jsonFile.set_int("/background/colour/blue", header->bgColour[2]); + jsonFile.set_int("/background/multiplayer/gradient-colour/bottom/red", header->bgColourBottom[0]); + jsonFile.set_int("/background/multiplayer/gradient-colour/bottom/green", header->bgColourBottom[1]); + jsonFile.set_int("/background/multiplayer/gradient-colour/bottom/blue", header->bgColourBottom[2]); + jsonFile.set_int("/background/multiplayer/gradient-colour/top/red", header->bgColourTop[0]); + jsonFile.set_int("/background/multiplayer/gradient-colour/top/green", header->bgColourTop[1]); + jsonFile.set_int("/background/multiplayer/gradient-colour/top/blue", header->bgColourTop[2]); + + // Unknowns + jsonFile.set_int("/unknown/unk1", header->unk1); + jsonFile.set_int("/unknown/unk2", header->unk2); + jsonFile.set_int("/unknown/unk3", header->unk3); + + for(size_t i = 0; i < 4; i++) { + jsonFile.set_int("/unknown/unk4/" + std::to_string(i), header->unk4[i]); + } + + for(size_t i = 0; i < 10; i++) { + jsonFile.set_int("/unknown/unkC/" + std::to_string(i), header->unkC[i]); + } + + for(size_t i = 0; i < 10; i++) { + jsonFile.set_int("/unknown/unk16/" + std::to_string(i), header->unk16[i]); + } + + jsonFile.set_int("/unknown/unk2A", header->unk2A); + + for(size_t i = 0; i < 9; i++) { + jsonFile.set_int("/unknown/unk2B/" + std::to_string(i), header->unk2B[i]); + } + + for(size_t i = 0; i < 5; i++) { + jsonFile.set_int("/unknown/unk44/" + std::to_string(i), header->unk44[i]); + } + + for(size_t i = 0; i < 3; i++) { + jsonFile.set_int("/unknown/unk4F/" + std::to_string(i), header->unk4F[i]); + } + + jsonFile.set_int("/unknown/unk53", header->unk53); + + jsonFile.set_int("/unknown/unk56", header->unk56); + jsonFile.set_int("/unknown/unk57", header->unk57); + jsonFile.set_int("/unknown/unk58", header->unk58); + jsonFile.set_int("/unknown/unk59", header->unk59); + jsonFile.set_int("/unknown/unk5A", header->unk5A); + jsonFile.set_int("/unknown/unk5C", header->unk5C); + jsonFile.set_int("/unknown/unk5D", header->unk5D); + jsonFile.set_int("/unknown/unk5E", header->unk5E); + jsonFile.set_int("/unknown/unk60", header->unk60); + jsonFile.set_int("/unknown/unk62", header->unk62); + jsonFile.set_int("/unknown/unk64", header->unk64); + jsonFile.set_int("/unknown/unk66", header->unk66); + jsonFile.set_int("/unknown/unk68", header->unk68); + jsonFile.set_int("/unknown/unk6A", header->unk6A); + jsonFile.set_int("/unknown/unk6B", header->unk6B); + jsonFile.set_int("/unknown/unk6C", header->unk6C); + jsonFile.set_int("/unknown/unk6D", header->unk6D); + jsonFile.set_int("/unknown/unk6E", header->unk6E); + jsonFile.set_int("/unknown/unk70", header->unk70); + jsonFile.set_int("/unknown/unk71", header->unk71); + jsonFile.set_int("/unknown/unk72", header->unk72); + jsonFile.set_int("/unknown/unk73", header->unk73); + + jsonFile.set_int("/unknown/unkA0", header->unkA0); + jsonFile.set_int("/unknown/unkA2", header->unkA2); + jsonFile.set_int("/unknown/unkA3", header->unkA3); + + jsonFile.set_int("/unknown/unkA8", header->unkA8); + jsonFile.set_int("/unknown/unkAA", header->unkAA); + + jsonFile.set_int("/unknown/unkB0", header->unkB0); + jsonFile.set_int("/unknown/unkB2", header->unkB2); + jsonFile.set_int("/unknown/unkB3", header->unkB3); + jsonFile.set_int("/unknown/unkB4", header->unkB4); + jsonFile.set_int("/unknown/unkB5", header->unkB5); + jsonFile.set_int("/unknown/unkB6", header->unkB6); + jsonFile.set_int("/unknown/unkB7", header->unkB7); + jsonFile.set_int("/unknown/unkB8", header->unkB8); + jsonFile.set_int("/unknown/unkB9", header->unkB9); + jsonFile.set_int("/unknown/unkBC", header->unkBC); + jsonFile.set_int("/unknown/unkBD", header->unkBD); + jsonFile.set_int("/unknown/unkC4", header->unkC4); + + + jsonFile.save(); +} + +ExtractLevelHeader::~ExtractLevelHeader() { +} + +void ExtractLevelHeader::_extract_weather(WritableJsonFile &jsonFile, std::string ptr, LevelHeader_Weather &weather) { + jsonFile.set_int(ptr + "/enable", weather.enable); + jsonFile.set_int(ptr + "/type", weather.type); + jsonFile.set_int(ptr + "/intensity", weather.intensity); + jsonFile.set_int(ptr + "/opacity", weather.opacity); + jsonFile.set_int(ptr + "/velocity/x", weather.velocity[0]); + jsonFile.set_int(ptr + "/velocity/y", weather.velocity[1]); + jsonFile.set_int(ptr + "/velocity/z", weather.velocity[2]); +} + +void ExtractLevelHeader::_extract_ai_levels(WritableJsonFile &jsonFile, std::string ptr, LevelHeader_AiLevels &aiLevels) { + jsonFile.set_int(ptr + "/base", aiLevels.baseAiLevel); + jsonFile.set_int(ptr + "/silver-coins", aiLevels.silverCoinsAiLevel); + jsonFile.set_int(ptr + "/completed", aiLevels.completedAiLevel); + jsonFile.set_int(ptr + "/tracks-mode", aiLevels.tracksModeAiLevel); + jsonFile.set_int(ptr + "/trophy-race", aiLevels.trophyRaceAiLevel); +} + +void ExtractLevelHeader::_extract_fog(WritableJsonFile &jsonFile, std::string ptr, LevelHeader_Fog &fogInfo) { + jsonFile.set_int(ptr + "/near", fogInfo.near); + jsonFile.set_int(ptr + "/far", fogInfo.far); + jsonFile.set_int(ptr + "/colour/red", fogInfo.colour[0]); + jsonFile.set_int(ptr + "/colour/green", fogInfo.colour[1]); + jsonFile.set_int(ptr + "/colour/blue", fogInfo.colour[2]); +} + +void ExtractLevelHeader::_extract_name(WritableJsonFile &jsonFile, std::string ptr) { + ExtractInfo &levelNameExtract = DeferredExtractions::get().get_extraction("ASSET_LEVEL_NAMES", _info.get_file_index()); + + std::vector rawBytes; + levelNameExtract.get_data_from_rom(rawBytes); + + CEnum *languages = _info.c_context->get_enum("Language"); + + size_t numLanguages = languages->get_member_count(); + + size_t curOffset = 0; + + for(size_t i = 0; i < numLanguages; i++) { + std::string lang, levelNameInLang; + DebugHelper::assert(languages->get_symbol_of_value(i, lang), + "(ExtractLevelHeader::_extract_name) Index ", i, " is out of range."); + + // TODO: If a language (other than English) uses the same name as English, then don't bother exporting it. + + // Get the current language name. + curOffset = StringHelper::get_ascii_from_data(rawBytes, curOffset, levelNameInLang); + + jsonFile.set_string(ptr + "/" + lang, levelNameInLang); + } +} + +template +void ExtractLevelHeader::_extract_enum_bitfield(WritableJsonFile &jsonFile, std::string ptr, std::string enumName, T value) { + size_t numBits = sizeof(T) * 8; + + size_t count = 0; + for(size_t i = 0; i < numBits; i++) { + size_t bitFlag = 1 << i; + if((value & bitFlag) == 0) { // Make sure the bit is set. + continue; + } + + std::string enumSymbol = _info.c_context->get_symbol_of_enum_int(enumName, i); + + jsonFile.set_string(ptr + "/" + std::to_string(count), enumSymbol); + + count++; + } +} + + diff --git a/tools/dkr_assets_tool_src/extract/extractTypes/extractLevelHeader.h b/tools/dkr_assets_tool_src/extract/extractTypes/extractLevelHeader.h new file mode 100644 index 00000000..693ebe21 --- /dev/null +++ b/tools/dkr_assets_tool_src/extract/extractTypes/extractLevelHeader.h @@ -0,0 +1,23 @@ +#pragma once + +#include "extract/extractInfo.h" +#include "misc/settings.hpp" + +#include "fileTypes/levelHeader.hpp" + +class ExtractLevelHeader { +public: + ExtractLevelHeader(DkrAssetsSettings &settings, ExtractInfo &info); + ~ExtractLevelHeader(); +private: + DkrAssetsSettings &_settings; + ExtractInfo &_info; + + void _extract_weather(WritableJsonFile &jsonFile, std::string ptr, LevelHeader_Weather &weather); + void _extract_ai_levels(WritableJsonFile &jsonFile, std::string ptr, LevelHeader_AiLevels &aiLevels); + void _extract_fog(WritableJsonFile &jsonFile, std::string ptr, LevelHeader_Fog &fogInfo); + void _extract_name(WritableJsonFile &jsonFile, std::string ptr); + + template + void _extract_enum_bitfield(WritableJsonFile &jsonFile, std::string ptr, std::string enumName, T value); +}; diff --git a/tools/dkr_assets_tool_src/extract/extractTypes/extractLevelModel.cpp b/tools/dkr_assets_tool_src/extract/extractTypes/extractLevelModel.cpp new file mode 100644 index 00000000..ff04df0a --- /dev/null +++ b/tools/dkr_assets_tool_src/extract/extractTypes/extractLevelModel.cpp @@ -0,0 +1,29 @@ +#include "extractLevelModel.h" + +#include +#include + +#include "helpers/debugHelper.h" +#include "helpers/jsonHelper.h" +#include "helpers/stringHelper.h" +#include "helpers/c/cContext.h" + +ExtractLevelModel::ExtractLevelModel(DkrAssetsSettings &settings, ExtractInfo &info) : _settings(settings), _info(info) { + fs::path _outFilepath = _settings.pathToAssets / _info.get_out_filepath(".json"); + DebugHelper::info_custom("Extracting Level Model", YELLOW_TEXT, _outFilepath); + + std::vector rawBytes; + _info.get_data_from_rom(rawBytes); + + WritableJsonFile jsonFile(_outFilepath); + jsonFile.set_string("/type", "LevelModel"); + + std::string _outRawFilepath = _settings.pathToAssets / _info.get_out_filepath(".bin"); + jsonFile.set_path("/raw", _info.get_filename(".bin")); + _info.write_rom_data_to_file(_outRawFilepath); + + jsonFile.save(); +} + +ExtractLevelModel::~ExtractLevelModel() { +} diff --git a/tools/dkr_assets_tool_src/extract/extractTypes/extractLevelModel.h b/tools/dkr_assets_tool_src/extract/extractTypes/extractLevelModel.h new file mode 100644 index 00000000..d7e98729 --- /dev/null +++ b/tools/dkr_assets_tool_src/extract/extractTypes/extractLevelModel.h @@ -0,0 +1,13 @@ +#pragma once + +#include "extract/extractInfo.h" +#include "misc/settings.hpp" + +class ExtractLevelModel { +public: + ExtractLevelModel(DkrAssetsSettings &settings, ExtractInfo &info); + ~ExtractLevelModel(); +private: + DkrAssetsSettings &_settings; + ExtractInfo &_info; +}; diff --git a/tools/dkr_assets_tool_src/extract/extractTypes/extractLevelName.cpp b/tools/dkr_assets_tool_src/extract/extractTypes/extractLevelName.cpp new file mode 100644 index 00000000..30d817aa --- /dev/null +++ b/tools/dkr_assets_tool_src/extract/extractTypes/extractLevelName.cpp @@ -0,0 +1,42 @@ +#include "extractLevelName.h" + +#include +#include + +#include "helpers/debugHelper.h" +#include "helpers/jsonHelper.h" +#include "helpers/stringHelper.h" +#include "helpers/c/cContext.h" + +ExtractLevelName::ExtractLevelName(DkrAssetsSettings &settings, ExtractInfo &info) : _settings(settings), _info(info) { + fs::path _outFilepath = _settings.pathToAssets / _info.get_out_filepath(".json"); + DebugHelper::info_custom("Extracting Level Name", YELLOW_TEXT, _outFilepath); + + std::vector rawBytes; + _info.get_data_from_rom(rawBytes); + + WritableJsonFile jsonFile(_outFilepath); + jsonFile.set_string("/type", "LevelName"); + + CEnum *languages = _info.c_context->get_enum("Language"); + + size_t numLanguages = languages->get_member_count(); + + size_t curOffset = 0; + + for(size_t i = 0; i < numLanguages; i++) { + std::string lang, levelNameInLang; + DebugHelper::assert(languages->get_symbol_of_value(i, lang), + "(ExtractLevelName::ExtractLevelName) Index ", i, " is out of range."); + + // Get the current language name. + curOffset = StringHelper::get_ascii_from_data(rawBytes, curOffset, levelNameInLang); + + jsonFile.set_string("/languages/" + lang, levelNameInLang); + } + + jsonFile.save(); +} + +ExtractLevelName::~ExtractLevelName() { +} diff --git a/tools/dkr_assets_tool_src/extract/extractTypes/extractLevelName.h b/tools/dkr_assets_tool_src/extract/extractTypes/extractLevelName.h new file mode 100644 index 00000000..515e1623 --- /dev/null +++ b/tools/dkr_assets_tool_src/extract/extractTypes/extractLevelName.h @@ -0,0 +1,13 @@ +#pragma once + +#include "extract/extractInfo.h" +#include "misc/settings.hpp" + +class ExtractLevelName { +public: + ExtractLevelName(DkrAssetsSettings &settings, ExtractInfo &info); + ~ExtractLevelName(); +private: + DkrAssetsSettings &_settings; + ExtractInfo &_info; +}; diff --git a/tools/dkr_assets_tool_src/extract/extractTypes/extractLevelObjectTranslationTable.cpp b/tools/dkr_assets_tool_src/extract/extractTypes/extractLevelObjectTranslationTable.cpp new file mode 100644 index 00000000..1feec218 --- /dev/null +++ b/tools/dkr_assets_tool_src/extract/extractTypes/extractLevelObjectTranslationTable.cpp @@ -0,0 +1,54 @@ +#include "extractLevelObjectTranslationTable.h" + +#include + +// Defines LOTT_ENTRY and LOTT_SIZE +#include "fileTypes/levelObjectTranslationTable.hpp" + +#include "helpers/jsonHelper.h" +#include "helpers/fileHelper.h" +#include "helpers/assetsHelper.h" + +ExtractLOTT::ExtractLOTT(DkrAssetsSettings &settings, ExtractInfo &info) : _settings(settings), _info(info) { + fs::path _outFilepath = _settings.pathToAssets / _info.get_out_filepath(".json"); + DebugHelper::info_custom("Extracting Level Object Translation Table", YELLOW_TEXT, _outFilepath); + + WritableJsonFile jsonFile(_outFilepath); + jsonFile.set_string("/type", "LevelObjectTranslationTable"); + + std::vector rawBytes; + _info.get_data_from_rom(rawBytes); + + // Make sure the table bytes are formatted correctly. + DebugHelper::assert( + (rawBytes.size() / sizeof(LOTT_ENTRY)) == LOTT_SIZE, + "(ExtractLOTT::ExtractLOTT) LevelObjectTranslationTable data has an invalid size", + ". Raw binary size = ", rawBytes.size(), + ", Entry size = ", sizeof(LOTT_ENTRY), + ", Table size = ", LOTT_SIZE + ); + + // Convert the raw bytes into an array of entries. + LOTT_ENTRY *objectIndices = reinterpret_cast(&rawBytes[0]); + + // This just shortens the table so that new entries can be merged in. (NULLs will be filled when built) + size_t lastEntry = LOTT_SIZE; + while((lastEntry > 0) && (objectIndices[lastEntry - 1] == LOTT_SIZE)) { + lastEntry--; + } + + for(size_t i = 0; i < lastEntry; i++) { + LOTT_ENTRY entry = objectIndices[i]; + if(entry == LOTT_SIZE) { // Check if the entry is empty, and set it to null if so. + jsonFile.set_null("/table/" + std::to_string(i)); + continue; + } + std::string objectBuildId = AssetsHelper::get_build_id_of_index(_settings, "ASSET_OBJECTS", entry); + jsonFile.set_string("/table/" + std::to_string(i), objectBuildId); + } + + jsonFile.save(); +} + +ExtractLOTT::~ExtractLOTT() { +} diff --git a/tools/dkr_assets_tool_src/extract/extractTypes/extractLevelObjectTranslationTable.h b/tools/dkr_assets_tool_src/extract/extractTypes/extractLevelObjectTranslationTable.h new file mode 100644 index 00000000..5040575b --- /dev/null +++ b/tools/dkr_assets_tool_src/extract/extractTypes/extractLevelObjectTranslationTable.h @@ -0,0 +1,13 @@ +#pragma once + +#include "extract/extractInfo.h" +#include "misc/settings.hpp" + +class ExtractLOTT { +public: + ExtractLOTT(DkrAssetsSettings &settings, ExtractInfo &info); + ~ExtractLOTT(); +private: + DkrAssetsSettings &_settings; + ExtractInfo &_info; +}; diff --git a/tools/dkr_assets_tool_src/extract/extractTypes/extractMenuText.cpp b/tools/dkr_assets_tool_src/extract/extractTypes/extractMenuText.cpp new file mode 100644 index 00000000..a4f4a798 --- /dev/null +++ b/tools/dkr_assets_tool_src/extract/extractTypes/extractMenuText.cpp @@ -0,0 +1,50 @@ +#include "extractMenuText.h" + +#include "fileTypes/types.hpp" + +#include "helpers/jsonHelper.h" + +ExtractMenuText::ExtractMenuText(DkrAssetsSettings &settings, ExtractInfo &info) : _settings(settings), _info(info) { + fs::path _outFilepath = _settings.pathToAssets / _info.get_out_filepath(".json"); + DebugHelper::info_custom("Extracting Menu Text", YELLOW_TEXT, _outFilepath); + + std::vector rawBytes; + _info.get_data_from_rom(rawBytes); + + DkrExtractMenuTextSection &menuTextConfig = _info.assetSection->specific.menuText; + std::string language = _info.get_tag("language", ""); + + DebugHelper::assert(!language.empty(), "(ExtractMenuText::ExtractMenuText) Language not set for ", _outFilepath); + + WritableJsonFile jsonFile(_outFilepath); + + jsonFile.set_string("/language", language); + jsonFile.set_string("/type", "MenuText"); + + std::string sectionsPtr = "/sections"; + //std::string orderPtr = "/order"; + + be_uint32_t *offsets = reinterpret_cast(&rawBytes[0]); + + for(size_t i = 0; i < menuTextConfig.numberOfTextEntries; i++) { + be_uint32_t offsetToText = offsets[i]; + + if(offsetToText == 0xFFFFFFFF) { + //jsonFile.set_null(orderPtr + "/" + std::to_string(i)); + continue; + } + + char *text = reinterpret_cast(&rawBytes[offsetToText]); + + std::string textBuildId = menuTextConfig.menuTextBuildIds[i]; + + //jsonFile.set_string(orderPtr + "/" + std::to_string(i), textBuildId); + jsonFile.set_string(sectionsPtr + "/" + textBuildId, text); + } + + jsonFile.save(); +} + +ExtractMenuText::~ExtractMenuText() { +} + diff --git a/tools/dkr_assets_tool_src/extract/extractTypes/extractMenuText.h b/tools/dkr_assets_tool_src/extract/extractTypes/extractMenuText.h new file mode 100644 index 00000000..9ce3cec8 --- /dev/null +++ b/tools/dkr_assets_tool_src/extract/extractTypes/extractMenuText.h @@ -0,0 +1,13 @@ +#pragma once + +#include "extract/extractInfo.h" +#include "misc/settings.hpp" + +class ExtractMenuText { +public: + ExtractMenuText(DkrAssetsSettings &settings, ExtractInfo &info); + ~ExtractMenuText(); +private: + DkrAssetsSettings &_settings; + ExtractInfo &_info; +}; diff --git a/tools/dkr_assets_tool_src/extract/extractTypes/extractMisc.cpp b/tools/dkr_assets_tool_src/extract/extractTypes/extractMisc.cpp new file mode 100644 index 00000000..0cccbaa1 --- /dev/null +++ b/tools/dkr_assets_tool_src/extract/extractTypes/extractMisc.cpp @@ -0,0 +1,165 @@ +#include "extractMisc.h" + +#include "fileTypes/misc.hpp" + +#include "helpers/jsonHelper.h" +#include "helpers/fileHelper.h" +#include "helpers/assetsHelper.h" +#include "helpers/miscHelper.h" + +#include +#include +#include + +#define MISC_ARGS WritableJsonFile &jsonFile, std::vector &rawBytes +#define MISC_LAMDA(func) [this](MISC_ARGS) { func(jsonFile, rawBytes); } + +typedef void (*MiscFuncPtr)(MISC_ARGS); + +ExtractMisc::ExtractMisc(DkrAssetsSettings &settings, ExtractInfo &info) : _settings(settings), _info(info) { + fs::path _outFilepath = _settings.pathToAssets / _info.get_out_filepath(".json"); + DebugHelper::info_custom("Extracting Miscellaneous", YELLOW_TEXT, _outFilepath); + + _miscType = _info.get_tag("miscType", "Binary"); + + WritableJsonFile jsonFile(_outFilepath); + jsonFile.set_string("/type", "Miscellaneous"); + jsonFile.set_string("/misc-type", _miscType); + + std::vector rawBytes; + _info.get_data_from_rom(rawBytes); + + const std::unordered_map> miscFunctions = { + { "Binary", MISC_LAMDA(_extract_binary) }, + { "RacerStat", MISC_LAMDA(_extract_racer_stat) }, + { "RacerAcceleration", MISC_LAMDA(_extract_racer_acceleration) }, + { "TrackIds", MISC_LAMDA(_extract_track_ids) }, + { "MagicCodes", MISC_LAMDA(_extract_magic_codes) }, + { "TitleScreenDemos", MISC_LAMDA(_extract_title_screen_demos) }, + }; + + // Make sure the misc type has a function to extract it. + DebugHelper::assert(miscFunctions.find(_miscType) != miscFunctions.end(), + "(ExtractMisc::ExtractMisc) Misc type \"", _miscType, " has extract function associated with it."); + + // Call the specific _extract_* function based on misc type. + miscFunctions.at(_miscType)(jsonFile, rawBytes); + + jsonFile.save(); +} + +ExtractMisc::~ExtractMisc() { +} + +void ExtractMisc::_extract_binary(WritableJsonFile &jsonFile, std::vector &rawBytes) { + fs::path _outRawFilepath = _settings.pathToAssets / _info.get_out_filepath(".bin"); + jsonFile.set_string("/raw", _info.get_filename(".bin")); + FileHelper::write_binary_file(rawBytes, _outRawFilepath, true); +} + +void ExtractMisc::_extract_racer_stat(WritableJsonFile &jsonFile, std::vector &rawBytes) { + const int racerStatFloatRound = 2; // Round float to 2 decimal places. + + be_float *values = reinterpret_cast(&rawBytes[0]); + CEnum *characters = _info.c_context->get_enum("Character"); + + size_t numberOfFloats = rawBytes.size() / 4; + for(size_t i = 0; i < numberOfFloats; i++) { + std::string charId; + DebugHelper::assert(characters->get_symbol_of_value(i, charId), + "(ExtractMisc::_extract_racer_stat) Enum \"Character\" does not have the index: ", i); + jsonFile.set_float("/values/" + charId, values[i], racerStatFloatRound); + } +} + +void ExtractMisc::_extract_racer_acceleration(WritableJsonFile &jsonFile, std::vector &rawBytes) { + const int racerAccelFloatRound = 2; // Round float to 2 decimal places. + + be_float *floats = reinterpret_cast(&rawBytes[0]); + + size_t numFloats = rawBytes.size() / 4; + + for(size_t i = 0; i < numFloats; i++) { + if(i > 0 && floats[i] == 0.0f) { // The zero is most likely padding. + break; + } + std::string ptr = "/values/" + std::to_string(i); + jsonFile.set_float(ptr, floats[i], racerAccelFloatRound); + } +} + +void ExtractMisc::_extract_track_ids(WritableJsonFile &jsonFile, std::vector &rawBytes) { + size_t endPoint = rawBytes.size(); + + // Get last non-zero value as the real end point. (Avoid padding) + while(endPoint > 0 && rawBytes[endPoint - 1] == 0) { + endPoint--; + } + + for(size_t i = 0; i < endPoint; i++) { + std::string ptr = "/ids/" + std::to_string(i); + + if(rawBytes[i] == 0xFF) { // 0xFF is the end of an id list. + jsonFile.set_null(ptr); + continue; + } + + std::string levelBuildId = AssetsHelper::get_build_id_of_index(_settings, "ASSET_LEVEL_HEADERS", rawBytes[i]); + jsonFile.set_string(ptr, levelBuildId); + } +} + +void ExtractMisc::_extract_magic_codes(WritableJsonFile &jsonFile, std::vector &rawBytes) { + MiscHelper::process_cheats_encryption(rawBytes); // Decrypt the cheats data. + + if(_settings.debugExtractKeepUncompressed) { + fs::path unencryptedCheatsPath = _settings.pathToAssets / "debug/cheats" / _info.get_filename(".bin"); + FileHelper::write_binary_file(rawBytes, unencryptedCheatsPath, true); + } + + be_int16_t *cheatsTable = reinterpret_cast(&rawBytes[0]); + + size_t numberOfCheats = cheatsTable[0]; + + CheatsTableEntry *entries = reinterpret_cast(&cheatsTable[1]); + + std::string ptr = "/cheats"; + + for(size_t i = 0; i < numberOfCheats; i++) { + std::string cheatPtr = ptr + "/" + std::to_string(i); + + char *code = reinterpret_cast(&rawBytes[entries[i].codeOffset]); + char *description = reinterpret_cast(&rawBytes[entries[i].descOffset]); + + jsonFile.set_string(cheatPtr + "/code", code); + jsonFile.set_string(cheatPtr + "/description", description); + } + +} + +void ExtractMisc::_extract_title_screen_demos(WritableJsonFile &jsonFile, std::vector &rawBytes) { + TitleScreenDemos *demos = reinterpret_cast(&rawBytes[0]); + + size_t numberOfDemos = rawBytes.size() / 3; + + for(size_t i = 0; i < numberOfDemos; i++) { + if(demos[i].levelId == -1) { + break; + } + + std::string ptr = "/entries/" + std::to_string(i); + + std::string levelBuildId = AssetsHelper::get_build_id_of_index(_settings, "ASSET_LEVEL_HEADERS", demos[i].levelId); + + jsonFile.set_string(ptr + "/level", levelBuildId); + + // Different default values for the title screen. + if(levelBuildId == "ASSET_LEVEL_TITLESCREENSEQUENCE") { + jsonFile.set_int_if_not_zero(ptr + "/number-of-players", demos[i].numberOfPlayers); + jsonFile.set_int_if_not_zero(ptr + "/cutscene-id", demos[i].cutsceneId); + } else { + jsonFile.set_int_if_not_value(ptr + "/number-of-players", demos[i].numberOfPlayers, -2); + jsonFile.set_int_if_not_value(ptr + "/cutscene-id", demos[i].cutsceneId, 100); + } + } +} diff --git a/tools/dkr_assets_tool_src/extract/extractTypes/extractMisc.h b/tools/dkr_assets_tool_src/extract/extractTypes/extractMisc.h new file mode 100644 index 00000000..6577a711 --- /dev/null +++ b/tools/dkr_assets_tool_src/extract/extractTypes/extractMisc.h @@ -0,0 +1,22 @@ +#pragma once + +#include "extract/extractInfo.h" +#include "misc/settings.hpp" + +class ExtractMisc { +public: + ExtractMisc(DkrAssetsSettings &settings, ExtractInfo &info); + ~ExtractMisc(); +private: + DkrAssetsSettings &_settings; + ExtractInfo &_info; + + void _extract_binary(WritableJsonFile &jsonFile, std::vector &rawBytes); + void _extract_racer_stat(WritableJsonFile &jsonFile, std::vector &rawBytes); + void _extract_racer_acceleration(WritableJsonFile &jsonFile, std::vector &rawBytes); + void _extract_track_ids(WritableJsonFile &jsonFile, std::vector &rawBytes); + void _extract_magic_codes(WritableJsonFile &jsonFile, std::vector &rawBytes); + void _extract_title_screen_demos(WritableJsonFile &jsonFile, std::vector &rawBytes); + + std::string _miscType; +}; diff --git a/tools/dkr_assets_tool_src/extract/extractTypes/extractObjectAnimation.cpp b/tools/dkr_assets_tool_src/extract/extractTypes/extractObjectAnimation.cpp new file mode 100644 index 00000000..214667fa --- /dev/null +++ b/tools/dkr_assets_tool_src/extract/extractTypes/extractObjectAnimation.cpp @@ -0,0 +1,20 @@ +#include "extractObjectAnimation.h" + +#include "helpers/jsonHelper.h" + +ExtractObjectAnimation::ExtractObjectAnimation(DkrAssetsSettings &settings, ExtractInfo &info) : _settings(settings), _info(info) { + fs::path _outRawFilepath = _settings.pathToAssets / _info.get_out_filepath(".bin"); + fs::path _outFilepath = _settings.pathToAssets / _info.get_out_filepath(".json"); + DebugHelper::info_custom("Extracting Object Animation", YELLOW_TEXT, _outFilepath); + + WritableJsonFile jsonFile(_outFilepath); + jsonFile.set_path("/raw", _info.get_filename(".bin")); + jsonFile.set_string("/type", "ObjectAnimation"); + + jsonFile.save(); + + _info.write_rom_data_to_file(_outRawFilepath); +} + +ExtractObjectAnimation::~ExtractObjectAnimation() { +} diff --git a/tools/dkr_assets_tool_src/extract/extractTypes/extractObjectAnimation.h b/tools/dkr_assets_tool_src/extract/extractTypes/extractObjectAnimation.h new file mode 100644 index 00000000..c8341650 --- /dev/null +++ b/tools/dkr_assets_tool_src/extract/extractTypes/extractObjectAnimation.h @@ -0,0 +1,13 @@ +#pragma once + +#include "extract/extractInfo.h" +#include "misc/settings.hpp" + +class ExtractObjectAnimation { +public: + ExtractObjectAnimation(DkrAssetsSettings &settings, ExtractInfo &info); + ~ExtractObjectAnimation(); +private: + DkrAssetsSettings &_settings; + ExtractInfo &_info; +}; diff --git a/tools/dkr_assets_tool_src/extract/extractTypes/extractObjectHeader.cpp b/tools/dkr_assets_tool_src/extract/extractTypes/extractObjectHeader.cpp new file mode 100644 index 00000000..ab127533 --- /dev/null +++ b/tools/dkr_assets_tool_src/extract/extractTypes/extractObjectHeader.cpp @@ -0,0 +1,190 @@ +#include "extractObjectHeader.h" + +#include "helpers/stringHelper.h" +#include "helpers/assetsHelper.h" +#include "helpers/dataHelper.h" + +#include "fileTypes/objectHeader.hpp" + +#include + +ExtractObjectHeader::ExtractObjectHeader(DkrAssetsSettings &settings, ExtractInfo &info) : _settings(settings), _info(info) { + fs::path _outFilepath = _settings.pathToAssets / _info.get_out_filepath(".json"); + + DebugHelper::info_custom("Extracting Object", YELLOW_TEXT, _outFilepath); + + std::vector rawBytes; + _info.get_data_from_rom(rawBytes); + + ObjectHeader *objectHeader = reinterpret_cast(&rawBytes[0]); + + //DebugHelper::info(objectHeader->internalName); + WritableJsonFile jsonFile(_outFilepath); + jsonFile.set_string("/type", "ObjectHeader"); + + CEnum *objBehaviors = _info.c_context->get_enum("ObjectBehaviours"); + + int behaviorId = objectHeader->behaviorId; + + // Behavior + if(behaviorId >= 0) { + std::string objBehaviorStr; + DebugHelper::assert(objBehaviors->get_symbol_of_value(behaviorId, objBehaviorStr), + "(ExtractObjectHeader::ExtractObjectHeader) Could not find a symbol for the behavior id: ", behaviorId); + jsonFile.set_string("/behavior", objBehaviorStr); + } else { + jsonFile.set_null("/behavior"); + } + + // Model Type + std::string modelTypeName = "ObjectModelType"; + std::string modelType = _info.c_context->get_symbol_of_enum_int(modelTypeName, objectHeader->modelType); + jsonFile.set_string("/model-type", modelType); + + // Flags + _flags_to_string(jsonFile, objectHeader->flags); + + // Internal Name + jsonFile.set_string("/internal-name", objectHeader->internalName); + + // Floats + jsonFile.set_float("/shadow-scale", objectHeader->shadowScale); + jsonFile.set_float("/scale", objectHeader->scale); + jsonFile.set_float("/shade-brightness", objectHeader->shadeBrightness); + jsonFile.set_float("/shade-ambient", objectHeader->shadeAmbient); + + // Unknowns + jsonFile.set_int("/unknown/unk0", objectHeader->unk0); + jsonFile.set_float("/unknown/unk8", objectHeader->unk8); + jsonFile.set_int("/unknown/unk34", objectHeader->unk34); + jsonFile.set_int("/unknown/unk38", objectHeader->unk38); + jsonFile.set_int("/unknown/unk3A", objectHeader->unk3A); + jsonFile.set_int("/unknown/unk3B", objectHeader->unk3B); + jsonFile.set_int("/unknown/unk3C", objectHeader->unk3C); + jsonFile.set_int("/unknown/unk3D", objectHeader->unk3D); + jsonFile.set_int("/unknown/unk42", objectHeader->unk42); + jsonFile.set_int("/unknown/unk44", objectHeader->unk44); + jsonFile.set_int("/unknown/unk46", objectHeader->unk46); + jsonFile.set_int("/unknown/unk48", objectHeader->unk48); + jsonFile.set_int("/unknown/unk4A", objectHeader->unk4A); + jsonFile.set_int("/unknown/unk4C", objectHeader->unk4C); + jsonFile.set_int("/unknown/unk50", objectHeader->unk50); + jsonFile.set_int("/unknown/unk52", objectHeader->unk52); + //jsonFile.set_int("/unknown/unk56", objectHeader->unk56); // vehiclePartIds count. + //jsonFile.set_int("/unknown/unk57", objectHeader->unk57); // particle count. + jsonFile.set_int("/unknown/unk58", objectHeader->unk58); + jsonFile.set_int("/unknown/unk59", objectHeader->unk59); + jsonFile.set_int("/unknown/unk5B", objectHeader->unk5B); + jsonFile.set_int("/unknown/unk5C", objectHeader->unk5C); + jsonFile.set_int("/unknown/unk5D", objectHeader->unk5D); + jsonFile.set_int("/unknown/unk5E", objectHeader->unk5E); + jsonFile.set_int("/unknown/unk5F", objectHeader->unk5F); + jsonFile.set_int("/unknown/unk70", objectHeader->unk70); + jsonFile.set_int("/unknown/unk71", objectHeader->unk71); + jsonFile.set_int("/unknown/unk72", objectHeader->unk72); + jsonFile.set_int("/unknown/unk73", objectHeader->unk73); + jsonFile.set_int("/unknown/unk74", objectHeader->unk74); + jsonFile.set_int("/unknown/unk75", objectHeader->unk75); + jsonFile.set_int("/unknown/unk76", objectHeader->unk76); + jsonFile.set_int("/unknown/unk77", objectHeader->unk77); + + // Other + jsonFile.set_int("/shadow-group", objectHeader->shadowGroup); + jsonFile.set_int("/water-effect-group", objectHeader->waterEffectGroup); + jsonFile.set_int("/shade-angle-y", objectHeader->shadeAngleY); + jsonFile.set_int("/shade-angle-z", objectHeader->shadeAngleZ); + jsonFile.set_int("/draw-distance", objectHeader->drawDistance); + + // Always zero? + //jsonFile.set_int("/num-light-sources", objectHeader->numLightSources); + + be_int32_t *modelIds = reinterpret_cast(&rawBytes[objectHeader->modelIds]); + be_int32_t *vehiclePartIds = reinterpret_cast(&rawBytes[objectHeader->vehiclePartIds]); + uint8_t *vehiclePartIndices = reinterpret_cast(&rawBytes[objectHeader->vehiclePartIndices]); + ObjectHeaderParticleData *particles = reinterpret_cast(&rawBytes[objectHeader->objectParticles]); + + for(int i = 0; i < objectHeader->numberOfModelIds; i++) { + std::string modelBuildId; + switch(objectHeader->modelType) { + case OBJECT_MODEL_TYPE_3D_MODEL: + modelBuildId = AssetsHelper::get_build_id_of_index(_settings, "ASSET_OBJECT_MODELS", modelIds[i]); + break; + case OBJECT_MODEL_TYPE_MISC: + modelBuildId = AssetsHelper::get_build_id_of_index(_settings, "ASSET_TEXTURES_2D", modelIds[i]); + break; + default: + modelBuildId = AssetsHelper::get_build_id_of_index(_settings, "ASSET_SPRITES", modelIds[i]); + break; + } + jsonFile.set_string("/models/" + std::to_string(i), modelBuildId); + } + + for(int i = 0; i < objectHeader->numberOfVehicleParts; i++) { + jsonFile.set_int("/vehicle-parts/" + std::to_string(i), vehiclePartIds[i]); + jsonFile.set_int("/vehicle-part-indices/" + std::to_string(i), vehiclePartIndices[i]); + } + + // There are some junk bytes at the end of the vehicle part indices. + size_t numberOfJunkVehiclePartsIndexBytes = DataHelper::align8(objectHeader->numberOfVehicleParts) - objectHeader->numberOfVehicleParts; + for(int i = 0; i < numberOfJunkVehiclePartsIndexBytes; i++) { + jsonFile.set_int("/vehicle-part-indices-junk-bytes/" + std::to_string(i), vehiclePartIndices[objectHeader->numberOfVehicleParts + i]); + } + + for(int i = 0; i < objectHeader->numberOfParticles; i++) { + std::string ptr = "/particles/" + std::to_string(i); + if(particles[i].upper_w.s0_s == -1) { // This seems to be a special case? + jsonFile.set_bool(ptr + "/special-case", true); + jsonFile.set_int(ptr + "/junk-data", particles[i].lower); + jsonFile.set_int(ptr + "/arg1", particles[i].upper_w.s1_b.b0); + jsonFile.set_int(ptr + "/arg2", particles[i].upper_w.s1_b.b1); + } else { + //jsonFile.set_bool(ptr + "/special-case", false); + jsonFile.set_int(ptr + "/arg1", particles[i].upper_w.s0_b.b0); + jsonFile.set_int(ptr + "/arg2", particles[i].upper_w.s0_b.b1); + jsonFile.set_int(ptr + "/arg3", particles[i].upper_w.s1_s); + jsonFile.set_int(ptr + "/arg4", particles[i].lower_w.s0_s); + jsonFile.set_int(ptr + "/arg5", particles[i].lower_w.s1_s); + } + } + + size_t offsetToJunkBytes = objectHeader->objectParticles + (objectHeader->numberOfParticles * sizeof(ObjectHeaderParticleData)); + size_t numberOfJunkBytes = rawBytes.size() - offsetToJunkBytes; + + for(size_t i = 0; i < numberOfJunkBytes; i++) { + jsonFile.set_int("/junk-data/"+std::to_string(i), rawBytes[offsetToJunkBytes + i]); + } + + jsonFile.save(); +} + +ExtractObjectHeader::~ExtractObjectHeader() { + +} + +void ExtractObjectHeader::_flags_to_string(WritableJsonFile &jsonFile, be_uint16_t flags) { + if(flags == 0) { + return; + } + + size_t numberOfBits = sizeof(be_uint16_t) * 8; + + int count = 0; + + for(size_t i = 0; i < numberOfBits; i++) { + int flag = 1 << i; + + if(!(flag & flags)) { + continue; + } + + std::string ptr = "/flags/" + std::to_string(count); + + if(OBJECT_HEADER_FLAGS.has_value(flag)) { + jsonFile.set_string(ptr, OBJECT_HEADER_FLAGS.get_key(flag)); + } else { + jsonFile.set_string(ptr, "FLAG_" + StringHelper::to_hex(flag, 4)); + } + + count++; + } +} \ No newline at end of file diff --git a/tools/dkr_assets_tool_src/extract/extractTypes/extractObjectHeader.h b/tools/dkr_assets_tool_src/extract/extractTypes/extractObjectHeader.h new file mode 100644 index 00000000..93d141bb --- /dev/null +++ b/tools/dkr_assets_tool_src/extract/extractTypes/extractObjectHeader.h @@ -0,0 +1,18 @@ +#pragma once + +#include +#include "extract/extractInfo.h" +#include "misc/settings.hpp" + +#include "fileTypes/types.hpp" + +class ExtractObjectHeader { +public: + ExtractObjectHeader(DkrAssetsSettings &settings, ExtractInfo &info); + ~ExtractObjectHeader(); +private: + DkrAssetsSettings &_settings; + ExtractInfo &_info; + + void _flags_to_string(WritableJsonFile &jsonFile, be_uint16_t flags); +}; \ No newline at end of file diff --git a/tools/dkr_assets_tool_src/extract/extractTypes/extractObjectMap.cpp b/tools/dkr_assets_tool_src/extract/extractTypes/extractObjectMap.cpp new file mode 100644 index 00000000..7f0ecc8b --- /dev/null +++ b/tools/dkr_assets_tool_src/extract/extractTypes/extractObjectMap.cpp @@ -0,0 +1,155 @@ +#include "extractObjectMap.h" + +#include "fileTypes/levelObjectMap.hpp" + +#include "helpers/gzipHelper.h" +#include "helpers/assetsHelper.h" +#include "helpers/stringHelper.h" + +#include "helpers/c/cStructGltfHelper.h" + +ExtractObjectMap::ExtractObjectMap(DkrAssetsSettings &settings, ExtractInfo &info) : _settings(settings), _info(info) { + fs::path _outFilepath = _settings.pathToAssets / _info.get_out_filepath(".json"); + DebugHelper::info_custom("Extracting Level Object Map", YELLOW_TEXT, _outFilepath); + + JsonFile *transTable = AssetsHelper::get_asset_json(_settings, "ASSET_LEVEL_OBJECT_TRANSLATION_TABLE"); + JsonFile *objBehaviorToEntryTable = AssetsHelper::get_meta_file(_settings, "objects/obj_beh_to_entry.meta.json"); + + WritableJsonFile jsonFile(_outFilepath); + jsonFile.set_string("/type", "LevelObjectMap"); + + // Get the compressed data from the ROM. + std::vector compressedData; + _info.get_data_from_rom(compressedData); + + if(compressedData.empty()) { + jsonFile.set_null("/objects"); + jsonFile.save(); + return; + } + + fs::path localGltfPath = _info.get_filename(".gltf"); + fs::path gltfFilepath = _settings.pathToAssets / _info.get_out_filepath(".gltf"); + + WriteableGltfFile gltfFile("objects"); + + jsonFile.set_string("/objects", localGltfPath); + + // Decompress it + std::vector rawBytes = GzipHelper::decompress_gzip(compressedData); + + if(_settings.debugExtractKeepUncompressed) { + // Have the uncompressed binary in a seperate directory in the assets folder. + fs::path outUncompressedPath = _settings.pathToAssets / "debug/objectMaps" / _info.get_filename(".bin"); + FileHelper::write_binary_file(rawBytes, outUncompressedPath, true); + } + + //DebugHelper::info(rawBytes.size()); + + // Now we can read it. + LevelObjectMap *mapData = reinterpret_cast(&rawBytes[0]); + + size_t offset = sizeof(LevelObjectMapHeader); // Should start at offset 0x10 + size_t end = mapData->header.fileSize + sizeof(LevelObjectMapHeader); + uint8_t *bytes = &mapData->entriesData[0]; + + DebugHelper::assert_(offset == 16, "(ExtractObjectMap::ExtractObjectMap) Invalid size for LevelObjectMapHeader: ", offset); + + int currentObjectIndex = 0; + while(offset < end) { + int id = bytes[0] | ((bytes[1] >> 7) << 8); + size_t numBytes = (bytes[1] & 0x7F); + + DebugHelper::assert_(numBytes >= 8, "(ExtractObjectMap::ExtractObjectMap) Invalid number of bytes for object! offset = ", DebugHelper::to_hex(offset)); + + std::string objectBuildId = transTable->get_string("/table/" + std::to_string(id)); + + std::string objectIndex = "/objects/" + std::to_string(currentObjectIndex); + + //jsonFile.set_string(objectIndex + "/id", objectBuildId); + + // Get the object behavior for this object. + JsonFile *objJson = AssetsHelper::get_asset_json(_settings, "ASSET_OBJECTS", objectBuildId); + + std::string objInternalName = objJson->get_string("/internal-name", "NoName"); + std::string objBehavior = objJson->get_string("/behavior"); + + DebugHelper::assert_( + !objBehavior.empty(), + "(ExtractObjectMap::ExtractObjectMap) Object \"", objectBuildId, "\" does not specify a behavior!" + ); + + std::string entryStructName = objBehaviorToEntryTable->get_string("/" + objBehavior); + DebugHelper::assert_( + !entryStructName.empty(), + "(ExtractObjectMap::ExtractObjectMap) The behavior \"", objBehavior, "\" does not specify an entry struct!" + ); + + //DebugHelper::info(objectBuildId, "/", objBehavior, "/", entryStructName); + + CStruct *entryStruct = _info.c_context->get_struct(entryStructName); + size_t entryStructByteSize = entryStruct->get_byte_size(); + + DebugHelper::assert_( + entryStructByteSize == numBytes, + "(ExtractObjectMap::ExtractObjectMap) The struct \"", entryStructName, "\" is the incorrect byte size! Is ", + DebugHelper::to_hex(entryStructByteSize), " bytes, when it should be ", + DebugHelper::to_hex(numBytes), " bytes." + ); + + // Assumption: entryStruct is LevelObjectEntryCommon + CStruct *entryCommon = entryStruct; + + // Check assumption by seeing if the first entry is a LevelObjectEntryCommon + if(entryStruct->get_entry(0)->type == "LevelObjectEntryCommon") { + // Assumption was wrong, so fix it! + entryCommon = _info.c_context->get_struct("LevelObjectEntryCommon"); + } + + int gltfObjNode = gltfFile.new_node(objInternalName); + + gltfFile.set_node_extra(gltfObjNode, "id", objectBuildId); + + _get_obj_position(gltfFile, bytes, entryCommon, gltfObjNode, entryStructName); + + if(entryCommon != entryStruct) { + for(size_t i = 0; i < entryStruct->entry_count(); i++) { + CStructEntry *structMember = entryStruct->get_entry(i); + CStructGltfHelper::put_struct_entry_into_gltf_node_extra(structMember, gltfFile, gltfObjNode, bytes); + } + } + + currentObjectIndex++; + bytes += numBytes; + offset += numBytes; + } + + + gltfFile.save(gltfFilepath); + DebugHelper::assert_(FileHelper::path_exists(gltfFilepath), "(ExtractObjectMap::ExtractObjectMap) gltfPath ", gltfFilepath, " did not save!"); + jsonFile.save(); +} + +ExtractObjectMap::~ExtractObjectMap() { +} + +void ExtractObjectMap::_get_obj_position(WriteableGltfFile &gltfFile, uint8_t *bytes, CStruct *entryCommon, int nodeIndex, const std::string &entryStructName) { + CStructEntry *memberX = entryCommon->get_entry(2); + CStructEntry *memberY = entryCommon->get_entry(3); + CStructEntry *memberZ = entryCommon->get_entry(4); + + DebugHelper::assert_(memberX != nullptr, "(ExtractObjectMap::_get_obj_position) Could not find \"x\" in struct: ", entryStructName); + DebugHelper::assert_(memberY != nullptr, "(ExtractObjectMap::_get_obj_position) Could not find \"y\" in struct: ", entryStructName); + DebugHelper::assert_(memberZ != nullptr, "(ExtractObjectMap::_get_obj_position) Could not find \"z\" in struct: ", entryStructName); + + int16_t xPos = memberX->get_integer_from_data(bytes); + int16_t yPos = memberY->get_integer_from_data(bytes); + int16_t zPos = memberZ->get_integer_from_data(bytes); + + // Scale position based on user input. + double scaledX = _settings.adjust_to_model_scale(xPos); + double scaledY = _settings.adjust_to_model_scale(yPos); + double scaledZ = _settings.adjust_to_model_scale(zPos); + + gltfFile.set_node_position(nodeIndex, scaledX, scaledY, scaledZ); +} diff --git a/tools/dkr_assets_tool_src/extract/extractTypes/extractObjectMap.h b/tools/dkr_assets_tool_src/extract/extractTypes/extractObjectMap.h new file mode 100644 index 00000000..9adbf7da --- /dev/null +++ b/tools/dkr_assets_tool_src/extract/extractTypes/extractObjectMap.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include "extract/extractInfo.h" +#include "misc/settings.hpp" + +#include "helpers/debugHelper.h" +#include "helpers/fileHelper.h" +#include "helpers/jsonHelper.h" +#include "helpers/gltf/gltfHelper.h" +#include "helpers/c/cStructHelper.h" + +class ExtractObjectMap { +public: + ExtractObjectMap(DkrAssetsSettings &settings, ExtractInfo &info); + ~ExtractObjectMap(); +private: + DkrAssetsSettings &_settings; + ExtractInfo &_info; + + void _get_obj_position(WriteableGltfFile &gltfFile, uint8_t *bytes, CStruct *entryCommon, int nodeIndex, const std::string &entryStructName); +}; diff --git a/tools/dkr_assets_tool_src/extract/extractTypes/extractObjectModel.cpp b/tools/dkr_assets_tool_src/extract/extractTypes/extractObjectModel.cpp new file mode 100644 index 00000000..e58beece --- /dev/null +++ b/tools/dkr_assets_tool_src/extract/extractTypes/extractObjectModel.cpp @@ -0,0 +1,20 @@ +#include "extractObjectModel.h" + +#include "helpers/jsonHelper.h" + +ExtractObjectModel::ExtractObjectModel(DkrAssetsSettings &settings, ExtractInfo &info) : _settings(settings), _info(info) { + fs::path _outRawFilepath = _settings.pathToAssets / _info.get_out_filepath(".bin"); + fs::path _outFilepath = _settings.pathToAssets / _info.get_out_filepath(".json"); + DebugHelper::info_custom("Extracting Object Model", YELLOW_TEXT, _outFilepath); + + WritableJsonFile jsonFile(_outFilepath); + jsonFile.set_path("/raw", _info.get_filename(".bin")); + jsonFile.set_string("/type", "ObjectModel"); + + jsonFile.save(); + + _info.write_rom_data_to_file(_outRawFilepath); +} + +ExtractObjectModel::~ExtractObjectModel() { +} diff --git a/tools/dkr_assets_tool_src/extract/extractTypes/extractObjectModel.h b/tools/dkr_assets_tool_src/extract/extractTypes/extractObjectModel.h new file mode 100644 index 00000000..37634132 --- /dev/null +++ b/tools/dkr_assets_tool_src/extract/extractTypes/extractObjectModel.h @@ -0,0 +1,13 @@ +#pragma once + +#include "extract/extractInfo.h" +#include "misc/settings.hpp" + +class ExtractObjectModel { +public: + ExtractObjectModel(DkrAssetsSettings &settings, ExtractInfo &info); + ~ExtractObjectModel(); +private: + DkrAssetsSettings &_settings; + ExtractInfo &_info; +}; diff --git a/tools/dkr_assets_tool_src/extract/extractTypes/extractParticle.cpp b/tools/dkr_assets_tool_src/extract/extractTypes/extractParticle.cpp new file mode 100644 index 00000000..3314413b --- /dev/null +++ b/tools/dkr_assets_tool_src/extract/extractTypes/extractParticle.cpp @@ -0,0 +1,20 @@ +#include "extractParticle.h" + +#include "helpers/jsonHelper.h" + +ExtractParticle::ExtractParticle(DkrAssetsSettings &settings, ExtractInfo &info) : _settings(settings), _info(info) { + fs::path _outRawFilepath = _settings.pathToAssets / _info.get_out_filepath(".bin"); + fs::path _outFilepath = _settings.pathToAssets / _info.get_out_filepath(".json"); + DebugHelper::info_custom("Extracting Particle", YELLOW_TEXT, _outFilepath); + + WritableJsonFile jsonFile(_outFilepath); + jsonFile.set_path("/raw", _info.get_filename(".bin")); + jsonFile.set_string("/type", "Particle"); + + jsonFile.save(); + + _info.write_rom_data_to_file(_outRawFilepath); +} + +ExtractParticle::~ExtractParticle() { +} diff --git a/tools/dkr_assets_tool_src/extract/extractTypes/extractParticle.h b/tools/dkr_assets_tool_src/extract/extractTypes/extractParticle.h new file mode 100644 index 00000000..3123116a --- /dev/null +++ b/tools/dkr_assets_tool_src/extract/extractTypes/extractParticle.h @@ -0,0 +1,13 @@ +#pragma once + +#include "extract/extractInfo.h" +#include "misc/settings.hpp" + +class ExtractParticle { +public: + ExtractParticle(DkrAssetsSettings &settings, ExtractInfo &info); + ~ExtractParticle(); +private: + DkrAssetsSettings &_settings; + ExtractInfo &_info; +}; diff --git a/tools/dkr_assets_tool_src/extract/extractTypes/extractParticleBehavior.cpp b/tools/dkr_assets_tool_src/extract/extractTypes/extractParticleBehavior.cpp new file mode 100644 index 00000000..506ad92a --- /dev/null +++ b/tools/dkr_assets_tool_src/extract/extractTypes/extractParticleBehavior.cpp @@ -0,0 +1,20 @@ +#include "extractParticleBehavior.h" + +#include "helpers/jsonHelper.h" + +ExtractParticleBehavior::ExtractParticleBehavior(DkrAssetsSettings &settings, ExtractInfo &info) : _settings(settings), _info(info) { + fs::path _outRawFilepath = _settings.pathToAssets / _info.get_out_filepath(".bin"); + fs::path _outFilepath = _settings.pathToAssets / _info.get_out_filepath(".json"); + DebugHelper::info_custom("Extracting Particle Behavior", YELLOW_TEXT, _outFilepath); + + WritableJsonFile jsonFile(_outFilepath); + jsonFile.set_path("/raw", _info.get_filename(".bin")); + jsonFile.set_string("/type", "ParticleBehavior"); + + jsonFile.save(); + + _info.write_rom_data_to_file(_outRawFilepath); +} + +ExtractParticleBehavior::~ExtractParticleBehavior() { +} diff --git a/tools/dkr_assets_tool_src/extract/extractTypes/extractParticleBehavior.h b/tools/dkr_assets_tool_src/extract/extractTypes/extractParticleBehavior.h new file mode 100644 index 00000000..1c1fd98b --- /dev/null +++ b/tools/dkr_assets_tool_src/extract/extractTypes/extractParticleBehavior.h @@ -0,0 +1,13 @@ +#pragma once + +#include "extract/extractInfo.h" +#include "misc/settings.hpp" + +class ExtractParticleBehavior { +public: + ExtractParticleBehavior(DkrAssetsSettings &settings, ExtractInfo &info); + ~ExtractParticleBehavior(); +private: + DkrAssetsSettings &_settings; + ExtractInfo &_info; +}; diff --git a/tools/dkr_assets_tool_src/extract/extractTypes/extractSprite.cpp b/tools/dkr_assets_tool_src/extract/extractTypes/extractSprite.cpp new file mode 100644 index 00000000..050647ef --- /dev/null +++ b/tools/dkr_assets_tool_src/extract/extractTypes/extractSprite.cpp @@ -0,0 +1,39 @@ +#include "extractSprite.h" + +#include "fileTypes/sprite.hpp" + +#include "helpers/jsonHelper.h" +#include "helpers/assetsHelper.h" + +ExtractSprite::ExtractSprite(DkrAssetsSettings &settings, ExtractInfo &info) : _settings(settings), _info(info) { + fs::path _outFilepath = _settings.pathToAssets / _info.get_out_filepath(".json"); + DebugHelper::info_custom("Extracting Sprite", YELLOW_TEXT, _outFilepath); + + WritableJsonFile jsonFile(_outFilepath); + + std::vector rawBytes; + _info.get_data_from_rom(rawBytes); + + SpriteHeader *spriteHeader = reinterpret_cast(&rawBytes[0]); + + std::string texBuildId = AssetsHelper::get_build_id_of_index(_settings, "ASSET_TEXTURES_2D", spriteHeader->startTextureIndex); + + jsonFile.set_string("/type", "Sprite"); + jsonFile.set_string("/start-texture", texBuildId); + jsonFile.set_int("/unk4", spriteHeader->unk4); + jsonFile.set_int("/unk6", spriteHeader->unk6); + + std::string frameTexCountPtr = "/frame-tex-count"; + + uint8_t *data = &rawBytes[sizeof(SpriteHeader)]; + size_t numOfFrames = (size_t)spriteHeader->numberOfFrames; + + for(size_t i = 0; i < numOfFrames; i++) { + jsonFile.set_int(frameTexCountPtr + "/" + std::to_string(i), data[i + 1] - data[i]); + } + + jsonFile.save(); +} + +ExtractSprite::~ExtractSprite() { +} diff --git a/tools/dkr_assets_tool_src/extract/extractTypes/extractSprite.h b/tools/dkr_assets_tool_src/extract/extractTypes/extractSprite.h new file mode 100644 index 00000000..a251b607 --- /dev/null +++ b/tools/dkr_assets_tool_src/extract/extractTypes/extractSprite.h @@ -0,0 +1,13 @@ +#pragma once + +#include "extract/extractInfo.h" +#include "misc/settings.hpp" + +class ExtractSprite { +public: + ExtractSprite(DkrAssetsSettings &settings, ExtractInfo &info); + ~ExtractSprite(); +private: + DkrAssetsSettings &_settings; + ExtractInfo &_info; +}; diff --git a/tools/dkr_assets_tool_src/extract/extractTypes/extractTTGhost.cpp b/tools/dkr_assets_tool_src/extract/extractTypes/extractTTGhost.cpp new file mode 100644 index 00000000..cc3aca05 --- /dev/null +++ b/tools/dkr_assets_tool_src/extract/extractTypes/extractTTGhost.cpp @@ -0,0 +1,53 @@ +#include "extractTTGhost.h" + +#include "fileTypes/ttGhost.hpp" + +#include "helpers/jsonHelper.h" +#include "helpers/fileHelper.h" +#include "helpers/assetsHelper.h" + +ExtractTTGhost::ExtractTTGhost(DkrAssetsSettings &settings, ExtractInfo &info) : _settings(settings), _info(info) { + fs::path _outFilepath = _settings.pathToAssets / _info.get_out_filepath(".json"); + DebugHelper::info_custom("Extracting TTGhost", YELLOW_TEXT, _outFilepath); + + std::vector rawBytes; + _info.get_data_from_rom(rawBytes); + + GhostHeader *ghostHeader = reinterpret_cast(&rawBytes[0]); + + WritableJsonFile jsonFile(_outFilepath); + jsonFile.set_string("/type", "TTGhost"); + + std::string levelBuildId = AssetsHelper::get_build_id_of_index(_settings, "ASSET_LEVEL_HEADERS", ghostHeader->levelId); + + std::string vehicle = _info.c_context->get_symbol_of_enum_int("Vehicle", ghostHeader->vehicleId); + + jsonFile.set_string("/header/level", levelBuildId); + jsonFile.set_string("/header/vehicle", vehicle); + + // Default is assumed to be 9, since that seems to always be the case? + // TODO: Make this a enum string? + jsonFile.set_int_if_not_value("/header/character", ghostHeader->characterId, 9); + + jsonFile.set_float("/header/time", (double)ghostHeader->time / GHOST_TIME_FPS); + + size_t numberOfNodes = ghostHeader->nodeCount; + + GhostNode *ghostNodes = reinterpret_cast(&rawBytes[sizeof(GhostHeader)]); + + for(size_t i = 0; i < numberOfNodes; i++) { + std::string ptr = "/nodes/" + std::to_string(i); + + jsonFile.set_int(ptr + "/x", ghostNodes[i].x); + jsonFile.set_int(ptr + "/y", ghostNodes[i].y); + jsonFile.set_int(ptr + "/z", ghostNodes[i].z); + jsonFile.set_int(ptr + "/rz", ghostNodes[i].zRotation); + jsonFile.set_int(ptr + "/rx", ghostNodes[i].xRotation); + jsonFile.set_int(ptr + "/ry", ghostNodes[i].yRotation); + } + + jsonFile.save(); +} + +ExtractTTGhost::~ExtractTTGhost() { +} diff --git a/tools/dkr_assets_tool_src/extract/extractTypes/extractTTGhost.h b/tools/dkr_assets_tool_src/extract/extractTypes/extractTTGhost.h new file mode 100644 index 00000000..3a12f6e2 --- /dev/null +++ b/tools/dkr_assets_tool_src/extract/extractTypes/extractTTGhost.h @@ -0,0 +1,13 @@ +#pragma once + +#include "extract/extractInfo.h" +#include "misc/settings.hpp" + +class ExtractTTGhost { +public: + ExtractTTGhost(DkrAssetsSettings &settings, ExtractInfo &info); + ~ExtractTTGhost(); +private: + DkrAssetsSettings &_settings; + ExtractInfo &_info; +}; diff --git a/tools/dkr_assets_tool_src/extract/extractTypes/extractTexture.cpp b/tools/dkr_assets_tool_src/extract/extractTypes/extractTexture.cpp new file mode 100644 index 00000000..4bc7dc8d --- /dev/null +++ b/tools/dkr_assets_tool_src/extract/extractTypes/extractTexture.cpp @@ -0,0 +1,131 @@ +#include "extractTexture.h" + +#include "helpers/debugHelper.h" +#include "helpers/fileHelper.h" +#include "helpers/jsonHelper.h" +#include "helpers/gzipHelper.h" + +#include "fileTypes/texture.hpp" + +ExtractTexture::ExtractTexture(DkrAssetsSettings &settings, ExtractInfo &info) : _settings(settings), _info(info) { + fs::path _outFilepath = _settings.pathToAssets / _info.get_out_filepath(".json"); + DebugHelper::info_custom("Extracting Texture", YELLOW_TEXT, _outFilepath); + + _shouldFlipTexture = _info.get_tag("flipTex", _info.assetSection->specific.textures.flipTexturesByDefault); + + std::vector texHeaderBytes; + std::vector texData; + + info.rom->get_data(info.get_data_offset(), sizeof(TextureHeader), texHeaderBytes); + + TextureHeader *texHeader = reinterpret_cast(&texHeaderBytes[0]); + + size_t numImages = texHeader->numOfTextures; + bool isCompressed = (texHeader->isCompressed); + + if(isCompressed) { + // Get compressed data. (sets texData) + info.rom->get_data(info.get_data_offset() + sizeof(TextureHeader), info.get_data_size() - sizeof(TextureHeader), texData); + // Decompress it. + texData = GzipHelper::decompress_gzip(texData); + } else { + // Get data directly, since it isn't compressed. (sets texData) + info.rom->get_data(info.get_data_offset(), info.get_data_size(), texData); + } + + if(_settings.debugExtractKeepUncompressed) { + // Have the uncompressed binary in a seperate directory in the assets folder. + fs::path outUncompressedPath = _settings.pathToAssets / "debug/textures" / _info.get_filename(".bin"); + FileHelper::write_binary_file(texData, outUncompressedPath, true); + } + + N64Image **images = _generate_texture_images(texData, numImages); + + size_t renderMode = (texHeader->format >> 4) & 0xF; + + DebugHelper::assert(renderMode < TEXTURE_RENDER_MODES.size(), "(ExtractTexture::ExtractTexture) Invalid rendermode value: ", renderMode); + + WritableJsonFile jsonFile(_outFilepath); + + fs::path outFolder = _settings.pathToAssets / _info.get_out_folder(); + + if(numImages == 1) { + fs::path imgPath = _info.get_filename(".png"); + jsonFile.set_path("/images/0", imgPath); + images[0]->save(outFolder / imgPath); + DebugHelper::assert(FileHelper::path_exists(outFolder / imgPath), "Image did not save!!!!"); + } else { + std::string outImgFilename = _info.get_filename(); + for(size_t i = 0; i < numImages; i++) { + fs::path imgPath(outImgFilename + "_" + std::to_string(i) + ".png"); + jsonFile.set_path("/images/" + std::to_string(i), imgPath); + images[i]->save(outFolder / imgPath); + DebugHelper::assert(FileHelper::path_exists(outFolder / imgPath), "Image did not save!!!!"); + } + } + + jsonFile.set_string("/type", "Texture"); + jsonFile.set_string("/format", images[0]->get_format()); + jsonFile.set_string("/render-mode", TEXTURE_RENDER_MODES[renderMode]); + jsonFile.set_bool_if_true("/flipped-image", _shouldFlipTexture); + jsonFile.set_bool_if_true("/compressed", isCompressed); + + if(numImages > 1) { + jsonFile.set_float("/frame-advance-delay", texHeader->frameAdvanceDelay / TEXTURE_FPS, TEXTURE_TIME_ROUND_PLACES); + } + + // Write flags + jsonFile.set_bool_if_true("/flags/anti-aliased", texHeader->flags & 0x1); + jsonFile.set_bool_if_true("/flags/semi-transparent", texHeader->flags & 0x4); + jsonFile.set_bool_if_true("/flags/cutout", texHeader->flags & 0x10); + jsonFile.set_string("/flags/wrap-s", (texHeader->flags & 0x40) ? "Clamp" : "Wrap"); + jsonFile.set_string("/flags/wrap-t", (texHeader->flags & 0x80) ? "Clamp" : "Wrap"); + jsonFile.set_bool_if_true("/flags/interlaced", texHeader->flags & 0x400); + + if(texHeader->spriteX != 0 || texHeader->spriteY != 0) { + jsonFile.set_int("/sprite-x", texHeader->spriteX); + jsonFile.set_int("/sprite-y", texHeader->spriteY); + } + + jsonFile.set_bool_if_true("/write-size", texHeader->textureSize != 0); + + jsonFile.save(); + + // Cleanup + delete images; +} + +ExtractTexture::~ExtractTexture() { +} + +N64Image **ExtractTexture::_generate_texture_images(std::vector &texData, size_t numImages) { + N64Image **images = new N64Image*[numImages]; + + int curOffset = 0; + for(size_t i = 0; i < numImages; i++) { + TextureHeader *texHeader = reinterpret_cast(&texData[curOffset]); + std::string format = TEXTURE_FORMAT_INT_TO_STRING[texHeader->format & 0xF]; + + images[i] = new N64Image(texHeader->width, texHeader->height, format, true); + + uint8_t *texImage = &texData[curOffset] + sizeof(TextureHeader); + + size_t calcSize = ImageHelper::image_size(texHeader->width, texHeader->height, format); + + images[i]->write_from(texImage, calcSize); + + // deinterlace the texture to make the .png image less jumbled up. + if(texHeader->flags & 0x400) { + images[i]->interlace(); + } + + // Need to flip most 3d textures for convience. + if(_shouldFlipTexture) { + images[i]->flip_vertically(); + } + + curOffset += texHeader->textureSize; // Move onto next texture. + } + + return images; +} diff --git a/tools/dkr_assets_tool_src/extract/extractTypes/extractTexture.h b/tools/dkr_assets_tool_src/extract/extractTypes/extractTexture.h new file mode 100644 index 00000000..79bf6b35 --- /dev/null +++ b/tools/dkr_assets_tool_src/extract/extractTypes/extractTexture.h @@ -0,0 +1,19 @@ +#pragma once + +#include +#include "extract/extractInfo.h" +#include "misc/settings.hpp" + +#include "helpers/imageHelper.h" + +class ExtractTexture { +public: + ExtractTexture(DkrAssetsSettings &settings, ExtractInfo &info); + ~ExtractTexture(); +private: + DkrAssetsSettings &_settings; + ExtractInfo &_info; + bool _shouldFlipTexture = false; + + N64Image **_generate_texture_images(std::vector &texData, size_t numImages); +}; diff --git a/tools/dkr_assets_tool_src/extract/extractor.cpp b/tools/dkr_assets_tool_src/extract/extractor.cpp new file mode 100644 index 00000000..1b859886 --- /dev/null +++ b/tools/dkr_assets_tool_src/extract/extractor.cpp @@ -0,0 +1,509 @@ +#include "extractor.h" + +#include + +#include "helpers/stringHelper.h" +#include "helpers/jsonHelper.h" +#include "misc/constants.hpp" + +#include "helpers/c/cStructHelper.h" +#include "helpers/c/cEnumsHelper.h" + +#include "libs/ThreadPool.h" + +// Extract types +#include "extractTypes/extractAudio.h" +#include "extractTypes/extractBinary.h" +#include "extractTypes/extractTexture.h" +#include "extractTypes/extractFonts.h" +#include "extractTypes/extractGameText.h" +#include "extractTypes/extractLevelName.h" +#include "extractTypes/extractLevelModel.h" +#include "extractTypes/extractLevelHeader.h" +#include "extractTypes/extractLevelObjectTranslationTable.h" +#include "extractTypes/extractMenuText.h" +#include "extractTypes/extractObjectAnimation.h" +#include "extractTypes/extractObjectHeader.h" +#include "extractTypes/extractObjectMap.h" +#include "extractTypes/extractObjectModel.h" +#include "extractTypes/extractParticle.h" +#include "extractTypes/extractParticleBehavior.h" +#include "extractTypes/extractSprite.h" +#include "extractTypes/extractTTGhost.h" +#include "extractTypes/extractMisc.h" + +/************************ Hope this part doesn't cause too much cringe. **************************/ + +#define EXTRACTOR_ARGS DkrAssetsSettings &settings, ExtractInfo &info +#define EXTRACTOR_LAMDA(classConstructorCode) [](EXTRACTOR_ARGS) { classConstructorCode(settings, info); } + +typedef std::function ExtractorFunction; + +// Put type with the extract class here! +std::unordered_map extractorMap = { + { "Binary", EXTRACTOR_LAMDA(ExtractBinary) }, + { "Fonts", EXTRACTOR_LAMDA(ExtractFonts) }, + { "LevelObjectTranslationTable", EXTRACTOR_LAMDA(ExtractLOTT) }, + { "Texture", EXTRACTOR_LAMDA(ExtractTexture) }, + { "LevelObjectMap", EXTRACTOR_LAMDA(ExtractObjectMap) }, + { "LevelModel", EXTRACTOR_LAMDA(ExtractLevelModel) }, + { "LevelHeader", EXTRACTOR_LAMDA(ExtractLevelHeader) }, + { "ObjectHeader", EXTRACTOR_LAMDA(ExtractObjectHeader) }, + { "ObjectModel", EXTRACTOR_LAMDA(ExtractObjectModel) }, + { "ObjectAnimation", EXTRACTOR_LAMDA(ExtractObjectAnimation) }, + { "TTGhost", EXTRACTOR_LAMDA(ExtractTTGhost) }, + { "GameText", EXTRACTOR_LAMDA(ExtractGameText) }, + { "MenuText", EXTRACTOR_LAMDA(ExtractMenuText) }, + { "Miscellaneous", EXTRACTOR_LAMDA(ExtractMisc) }, + { "Sprite", EXTRACTOR_LAMDA(ExtractSprite) }, + { "Audio", EXTRACTOR_LAMDA(ExtractAudio) }, + { "Particle", EXTRACTOR_LAMDA(ExtractParticle) }, + { "ParticleBehavior", EXTRACTOR_LAMDA(ExtractParticleBehavior) }, +}; + +/*************************************************************************************************/ + +DkrExtract::DkrExtract(DkrAssetsSettings &settings) : _settings(settings) { + fs::path pathToVanillaAssets = _settings.pathToAssets / ".vanilla/"; + _settings.pathToAssets = pathToVanillaAssets / (settings.dkrVersion + "/"); + + // First find config + DebugHelper::info_verbose("Finding config..."); + _find_config(); + if(_config == nullptr) { + DebugHelper::error("Could not find a config file for DKR version: ", _settings.dkrVersion); + } + + // Then find a valid rom. + DebugHelper::info_verbose("Finding ROM..."); + _find_rom(_settings.pathToBaseroms, true); + if(_rom == nullptr) { + // If no rom was found in the baseroms directory, then try the root directory (non-recursively). + _find_rom(_settings.pathToRepo, false); + } + + if(_rom == nullptr) { + DebugHelper::error("Could not find a valid ROM file for DKR version: ", _settings.dkrVersion); + } + + DebugHelper::info_verbose("Parsing config..."); + // Parse the config. (Wanted to make sure there was a ROM before parsing the config) + _config->parse(); + + // Preload structs & enums into context. + _preload_c_context(); + + DebugHelper::info_verbose("Extracting..."); + // Finally, run the extraction! + _extract(); +} + +DkrExtract::~DkrExtract() { + if(_config != nullptr) { + delete _config; + } + if(_rom != nullptr) { + delete _rom; + } +} + +void DkrExtract::_find_config() { + std::vector configFiles = FileHelper::get_files_from_directory_with_extension(_settings.pathToConfigs, ".config.json", false); + DebugHelper::info_verbose("Number of configs: ", configFiles.size()); + for(size_t i = 0; i < configFiles.size(); i++) { + _config = new DkrExtractConfig(configFiles[i]); + if(_config->get_dkr_version() == _settings.dkrVersion) { + DebugHelper::info("Using config file: ", configFiles[i]); + return; + } + delete _config; + } + _config = nullptr; // Could not find the config. +} + +void DkrExtract::_find_rom(const std::string &directory, bool recursive) { + std::vector romFiles = FileHelper::get_files_from_directory(directory, recursive); + for(size_t i = 0; i < romFiles.size(); i++) { + _rom = new DkrExtractROM(romFiles[i]); + if(_rom->is_valid() && _config->get_md5() == _rom->get_calculated_md5()) { + DebugHelper::info("Using ROM file: ", romFiles[i]); + return; + } + delete _rom; + } + _rom = nullptr; // Could not find a rom. +} + +void DkrExtract::_extract() { + DebugHelper::DebugTimer timer; + uint32_t romOffset = 0; + DebugHelper::info_verbose("Getting code sections..."); + _get_code_extractions(romOffset); + DebugHelper::info_verbose("Getting asset sections..."); + _get_asset_extractions(romOffset); + DebugHelper::info_verbose("Creating main json file..."); + _generate_main_json_file(); + DebugHelper::info_verbose("Creating obj-behavior-to-entry json file..."); + _generate_obj_behavior_to_entry_json_file(); + DebugHelper::info_verbose("Took ", timer.elapsed(), " to initialize extract info."); + + DebugHelper::DebugTimer timer2; + + // extractions should be sorted by the group number. + for (auto &pair : extractions) { + std::vector &extracts = pair.second; + bool errorOccured = false; + std::exception_ptr ex; + { + ThreadPool pool(_settings.threadCount); + for(ExtractInfo &info : extracts) { + std::string type = info.get_type(); + // Check to make sure the builderMap has the given type. + if(extractorMap.find(type) == extractorMap.end()) { + // For now this is a warning, but maybe make it an error instead? + DebugHelper::warn("The input type \"", type, "\" is currently not implemented."); + continue; + } + pool.enqueue([this, type, &info = info, &errorOccured = errorOccured, &ex = ex] { + if(errorOccured) { + return; + } + // Call the class constructor of a type. + try { + extractorMap[type](_settings, (ExtractInfo &)info); + } catch (...) { + errorOccured = true; + ex = std::current_exception(); + } + }); + if(errorOccured) { + break; + } + } + } + if(errorOccured) { + std::rethrow_exception(ex); + } + + // ThreadPool's destructor will join the threads. + } + DebugHelper::info_verbose("Took ", timer.elapsed(), " to extract all assets."); +} + +// Group defaults to 0 if not specified. +void DkrExtract::_add_new_extraction(ExtractInfo &newExtract, int group) { + // Make sure the group exists in the map + if(extractions.find(group) == extractions.end()) { + extractions[group] = std::vector(); // New group + } + extractions[group].push_back(newExtract); +} + +void DkrExtract::_get_code_extractions(uint32_t &romOffset) { + for(DkrExtractCodeSection &codeSection : _config->codeSections) { + for(DkrExtractCodeSectionFile &codeFile : codeSection.files) { + if(codeSection.type == "NoExtract") { + DebugHelper::info_verbose(DebugHelper::to_hex(romOffset), ",", codeSection.type, ",\"", codeFile.filename, "\",", DebugHelper::to_hex(codeFile.length)); + romOffset += codeFile.length; + continue; + } + ExtractInfo newExtract(codeSection.type, codeFile.filename, codeSection.folder, _rom, _config, &_c_context, romOffset, codeFile.length, 0); + _add_new_extraction(newExtract); + DebugHelper::info_verbose(DebugHelper::to_hex(romOffset), ",", codeSection.type, ",\"", codeFile.filename, "\",\"", codeSection.folder, "\",", DebugHelper::to_hex(codeFile.length)); + romOffset += codeFile.length; + } + } +} + +// Note: sectionFile could be null. +void DkrExtract::_get_asset_section_file_info(DkrExtractAssetSection *assetSection, DkrExtractAssetSectionFile *sectionFile, size_t fileNum, uint32_t romOffset, size_t length) { + std::string filename = ""; + std::string buildId = ""; + std::string folder = ""; + if(sectionFile != nullptr) { + filename = sectionFile->filename; + buildId = sectionFile->buildId; + folder = sectionFile->folder; + } + if(buildId.empty()) { + buildId = assetSection->buildId + "_" + std::to_string(fileNum); + } + if(filename.empty()) { + filename = buildId; + StringHelper::make_lowercase(filename); + } + if(folder.empty()) { + folder = assetSection->filesDefaultFolder; + } + + ExtractInfo newExtract(assetSection->type, filename, folder, _rom, _config, &_c_context, romOffset, length, fileNum, assetSection); + + if(assetSection->type == "Texture") { + newExtract.set_tag("flipTex", (sectionFile != nullptr) ? sectionFile->specific.texture.flipTex : assetSection->specific.textures.flipTexturesByDefault); + } else if(assetSection->type == "MenuText") { + newExtract.set_tag("language", sectionFile->specific.menuText.language); + } else if(assetSection->type == "Miscellaneous") { + // miscType set to "Binary" if the file was not specified. + newExtract.set_tag("miscType", (sectionFile != nullptr) ? sectionFile->specific.misc.miscType : "Binary"); + } + + if(assetSection->isDeferred) { + // This will be extracted as a part of another file. + DeferredExtractions::get().add_extraction(assetSection->buildId, newExtract); + return; + } + + _add_new_extraction(newExtract, assetSection->group); +} + +void DkrExtract::_get_asset_files_from_table(DkrExtractAssetSection *assetSection, int sectionOffset, int tableSectionOffset) { + DebugHelper::info_verbose("Section offset = ", DebugHelper::to_hex(sectionOffset)); + + // Get the table type from a section type name. + DkrAssetTableType tableType = AssetTable::table_type_from_section_type(assetSection->type); + + AssetTable assetSectionTable(_rom, tableSectionOffset, tableType); + + if(tableType == DkrAssetTableType::MenuTextTable) { + // First entry determines the number of text entries for each language. + assetSection->specific.menuText.numberOfTextEntries = _rom->get_s32(tableSectionOffset); + } + + size_t numFilesInSection = assetSectionTable.size(); + + for(size_t fileIndex = 0; fileIndex < numFilesInSection; fileIndex++) { + uint32_t offset = sectionOffset + assetSectionTable.get_entry_offset(fileIndex); + uint32_t fileLength = assetSectionTable.get_entry_size(fileIndex); + _get_asset_section_file_info(assetSection, assetSection->get_asset_section_file(fileIndex), fileIndex, offset, fileLength); + } + + _generate_section_json_file(assetSection, &assetSectionTable); +} + +void DkrExtract::_get_single_asset_info(DkrExtractAssetSection *assetSection, uint32_t romOffset, size_t length) { + DkrExtractAssetSectionFile *sectionFile = assetSection->get_single_file(); + + std::string filename = ""; + std::string buildId = ""; + std::string folder = ""; + if(sectionFile != nullptr) { + filename = sectionFile->filename; + buildId = sectionFile->buildId; + folder = sectionFile->folder; + } + if(buildId.empty()) { + buildId = assetSection->buildId; + } + if(filename.empty()) { + filename = buildId; + StringHelper::make_lowercase(filename); + } + if(folder.empty()) { + folder = assetSection->filesDefaultFolder; + } + + ExtractInfo newExtract(assetSection->type, filename, folder, _rom, _config, &_c_context, romOffset, length, 0, assetSection); + + if(assetSection->isDeferred) { + // This will be extracted as a part of another file. + DeferredExtractions::get().add_extraction(assetSection->buildId, newExtract); + return; + } + + _add_new_extraction(newExtract, assetSection->group); +} + +void DkrExtract::_get_asset_extractions(uint32_t &romOffset) { + AssetTable mainAssetsTable(_rom, romOffset, DkrAssetTableType::FixedTable); + + size_t numAssetSections = mainAssetsTable.size(); + + // Assets start past the main table. + romOffset += (numAssetSections + 2) * 4; + + DebugHelper::assert_(_config->assetSections.size() == numAssetSections, + "(DkrExtract::_get_asset_extractions) Number of assets in config does not match the ROM! Num assets in config: ", + _config->assetSections.size(), ", in ROM: ", numAssetSections); + + for(size_t sectionIndex = 0; sectionIndex < numAssetSections; sectionIndex++) { + DkrExtractAssetSection *assetSection = &_config->assetSections[sectionIndex]; + + if(assetSection->type == "Empty") { + // Don't bother extracting empty sections. + continue; + } + + int sectionOffset = romOffset + mainAssetsTable.get_entry_offset(sectionIndex); + + if(assetSection->table != -1) { + int tableSectionOffset = romOffset + mainAssetsTable.get_entry_offset(assetSection->table); + _get_asset_files_from_table(assetSection, sectionOffset, tableSectionOffset); + continue; + } + + if(assetSection->type == "Table") { + continue; + } + + size_t sectionLength = mainAssetsTable.get_entry_offset(sectionIndex + 1) - mainAssetsTable.get_entry_offset(sectionIndex); + _get_single_asset_info(assetSection, sectionOffset, sectionLength); + _generate_section_json_file(assetSection); + } +} + +// sectionTable is nullptr when the asset section doesn't have a table (Is a single file) +void DkrExtract::_generate_section_json_file(DkrExtractAssetSection *assetSection, AssetTable *sectionTable) { + if(assetSection->isDeferred) { + return; + } + + std::string buildIdAsFilename = assetSection->buildId; + StringHelper::make_lowercase(buildIdAsFilename); + fs::path outFilename = _settings.pathToAssets / (buildIdAsFilename + ".meta.json"); + + WritableJsonFile jsonFile(outFilename); + + jsonFile.set_string("/folder", assetSection->folder); + jsonFile.set_string("/type", assetSection->type); + + if(assetSection->type == "MenuText") { + std::string orderPtr = "/menu-text-build-ids"; + size_t numIds = assetSection->specific.menuText.menuTextBuildIds.size(); + for(size_t i = 0; i < numIds; i++) { + jsonFile.set_string(orderPtr + "/" + std::to_string(i), assetSection->specific.menuText.menuTextBuildIds[i]); + } + } + + if(sectionTable == nullptr) { + // This section does not have a table. + DkrExtractAssetSectionFile *sectionFile = assetSection->get_single_file(); + if(sectionFile == nullptr) { + jsonFile.set_string("/filename", buildIdAsFilename + ".json"); + } else { + jsonFile.set_string("/filename", sectionFile->filename + ".json"); + } + jsonFile.save(); + return; + } + + // This section has a table. + jsonFile.set_string("/table", _config->get_build_id_of_section(assetSection->table)); + + std::string orderPtr = "/files/order/"; + std::string sectionsPtr = "/files/sections/"; + + for(size_t i = 0; i < sectionTable->size(); i++) { + DkrExtractAssetSectionFile *sectionFile = assetSection->get_asset_section_file(i); + std::string fileBuildId; + fs::path fileFilepath; + if(sectionFile == nullptr) { + fileBuildId = assetSection->buildId + "_" + std::to_string(i); + std::string temp = fileBuildId + ".json"; + StringHelper::make_lowercase(temp); + fileFilepath = temp; + if(!assetSection->filesDefaultFolder.empty()) { + fileFilepath = assetSection->filesDefaultFolder / fileFilepath; + } + } else { + fileBuildId = sectionFile->buildId; + fileFilepath = sectionFile->filename + ".json"; + if(!sectionFile->folder.empty()) { + fileFilepath = sectionFile->folder / fileFilepath; + } else if(!assetSection->filesDefaultFolder.empty()) { + fileFilepath = assetSection->filesDefaultFolder / fileFilepath; + } + } + + jsonFile.set_string(orderPtr + std::to_string(i), fileBuildId); + jsonFile.set_string(sectionsPtr + fileBuildId + "/filename", fileFilepath); + } + + jsonFile.save(); +} + +// Creates the "assets.meta.json" file +void DkrExtract::_generate_main_json_file() { + fs::path outFilename = _settings.pathToAssets / "assets.meta.json"; + WritableJsonFile jsonFile(outFilename); + + jsonFile.set_int("/@revision", DKRAT_REVISION_MAJOR); + jsonFile.set_int("/@revision-minor", DKRAT_REVISION_MINOR); + jsonFile.set_string("/@version", _settings.dkrVersion); + + for(size_t i = 0; i < _config->assetSections.size(); i++) { + DkrExtractAssetSection *assetSection = &_config->assetSections[i]; + + jsonFile.set_string("/assets/order/" + std::to_string(i), assetSection->buildId); + std::string sectionStr = "/assets/sections/" + assetSection->buildId; + + if(assetSection->type == "Table") { + std::string forId = _config->get_build_id_of_section_from_table_id(assetSection->buildId); + jsonFile.set_string(sectionStr + "/for", forId); + } else if (assetSection->type == "Empty") { + // Do nothing. + } else { + std::string filename = assetSection->buildId; + if(assetSection->isDeferred) { + jsonFile.set_bool(sectionStr + "/deferred", true); + jsonFile.set_string(sectionStr + "/defer-info/from-section", assetSection->deferInfo.fromSection); + jsonFile.set_string(sectionStr + "/defer-info/id-postfix", assetSection->deferInfo.idPostfix); + jsonFile.set_string(sectionStr + "/defer-info/output-path", assetSection->deferInfo.outputPath); + } else { + StringHelper::make_lowercase(filename); + filename += ".meta.json"; + jsonFile.set_string(sectionStr + "/filename", filename); + } + } + jsonFile.set_string(sectionStr + "/type", assetSection->type); + } + + jsonFile.save(); +} + +void DkrExtract::_generate_obj_behavior_to_entry_json_file() { + fs::path outFilename = _settings.pathToAssets / "objects/obj_beh_to_entry.meta.json"; + WritableJsonFile jsonFile(outFilename); + + CEnum *objBehaviors = _c_context.get_enum("ObjectBehaviours"); + + std::vector defaultObjEntriesOrder; + _config->get_default_object_entries_order_array(defaultObjEntriesOrder); + + for(int i = 0; i < 128; i++) { + std::string symbol; + objBehaviors->get_symbol_of_value(i, symbol); + + CStruct *entryStruct = _c_context.get_struct(defaultObjEntriesOrder[i]); + DebugHelper::assert_(entryStruct != nullptr, + "(DkrExtract::_generate_obj_behavior_to_entry_json_file) Could not find struct \"", defaultObjEntriesOrder[i], "\""); + + jsonFile.set_string("/" + symbol, defaultObjEntriesOrder[i]); + } + + jsonFile.save(); +} + +// Preload structs & enums into context. +void DkrExtract::_preload_c_context() { + fs::path includeFolder = _settings.pathToRepo / "include/"; + + // Load all structs from these files. + fs::path structPaths[] = { + includeFolder / "level_object_entries.h", + }; + + for(fs::path &structPath : structPaths) { + CStructHelper::load_structs_from_file(&_c_context, structPath); + } + + // Load all enums from these files. + fs::path enumPaths[] = { + includeFolder / "enums.h", + includeFolder / "object_behaviors.h", + }; + + for(fs::path &enumPath : enumPaths) { + CEnumsHelper::load_enums_from_file(&_c_context, enumPath); + } + +} diff --git a/tools/dkr_assets_tool_src/extract/extractor.h b/tools/dkr_assets_tool_src/extract/extractor.h new file mode 100644 index 00000000..32ccec1f --- /dev/null +++ b/tools/dkr_assets_tool_src/extract/extractor.h @@ -0,0 +1,61 @@ +#pragma once + +#include +#include +#include + +#include "misc/settings.hpp" + +#include "helpers/fileHelper.h" +#include "helpers/debugHelper.h" + +#include "config.h" +#include "rom.h" +#include "extractInfo.h" +#include "assetTable.h" + +#include "helpers/c/cContext.h" + + +class DkrExtract { +public: + DkrExtract(DkrAssetsSettings &settings); + ~DkrExtract(); + +private: + DkrExtractConfig *_config = nullptr; + DkrExtractROM *_rom = nullptr; + DkrAssetsSettings &_settings; + + // The int is the group number, need to extract different sections first before others. + // (Example being extracting the LevelObjectTranslationTable before any LevelObjectMaps) + // This NEEDS to be a std::map, not a std::unordered_map. + std::map> extractions; + + void _find_config(); + void _find_rom(const std::string &directory, bool recursive); + + void _extract(); + + void _add_new_extraction(ExtractInfo &info, int group=0); + + void _get_code_extractions(uint32_t &romOffset); + void _get_asset_extractions(uint32_t &romOffset); + + void _get_asset_files_from_table(DkrExtractAssetSection *assetSection, int sectionOffset, int tableSectionOffset); + + void _get_single_asset_info(DkrExtractAssetSection *assetSection, uint32_t romOffset, size_t length); + + void _get_asset_section_file_info(DkrExtractAssetSection *assetSection, DkrExtractAssetSectionFile *sectionFile, + size_t fileNum, uint32_t romOffset, size_t length); + + void _generate_section_json_file(DkrExtractAssetSection *assetSection, AssetTable *sectionTable = nullptr); + + void _generate_main_json_file(); + + void _generate_obj_behavior_to_entry_json_file(); + + void _preload_c_context(); + + CContext _c_context; +}; diff --git a/tools/dkr_assets_tool_src/extract/rom.cpp b/tools/dkr_assets_tool_src/extract/rom.cpp new file mode 100644 index 00000000..a6f0295d --- /dev/null +++ b/tools/dkr_assets_tool_src/extract/rom.cpp @@ -0,0 +1,163 @@ +#include +#include +#include "libs/md5.hpp" +#include "rom.h" + +DkrExtractROM::DkrExtractROM(fs::path filepath) { + _filepath = filepath; + _bytes = FileHelper::read_binary_file(filepath); + _romSize = _bytes.size(); // ROM shouldn't change size. + if(_bytes.size() < 4) { + return; + } + _detect_and_fix_rom_endianness(); + if(!_isValid) { + return; + } + _calculate_md5_checksum(); +} + +DkrExtractROM::~DkrExtractROM() { + +} + +std::string DkrExtractROM::get_calculated_md5() { + return _md5; +} + +bool DkrExtractROM::is_valid() { + return _isValid; +} + +void DkrExtractROM::_detect_and_fix_rom_endianness() { + bool convertedToBigEndian = false; + + if(_bytes[0] == 0x80 && _bytes[1] == 0x37) { // Detect big endian + // Do nothing + } else if(_bytes[0] == 0x37 && _bytes[1] == 0x80) { // Detect mixed endian (byteswapped) + FileHelper::byteswap(_bytes); // Convert to big endian + convertedToBigEndian = true; + } else if(_bytes[0] == 0x40 && _bytes[1] == 0x12) { // Detect little endian + FileHelper::endianswap(_bytes); // Convert to big endian + convertedToBigEndian = true; + } else { + _isValid = false; // Not a valid N64 ROM + return; + } + + _isValid = true; + + if(convertedToBigEndian) { + // First overwrite baserom bytes, so that it stays big-endian. + FileHelper::write_binary_file(_bytes, _filepath); + + // Then rename the ROM to .z64 to indicate that it is big-endian. + fs::path filename = FileHelper::get_filename_from_path(_filepath, true); + filename.replace_extension(".z64"); + + fs::path dir = FileHelper::get_directory(_filepath).string(); + fs::path newPath = dir / filename; + FileHelper::rename(_filepath, newPath); + } + + return; +} + +void DkrExtractROM::_calculate_md5_checksum() { + md5::Digest digest = md5::compute(_bytes); + std::stringstream ss; + + // set up stringstream format + ss << std::hex << std::setfill('0'); + + for(uint8_t uc: digest) { + ss << std::setw(2) << (int)uc; + } + + _md5 = ss.str(); +} + +uint32_t DkrExtractROM::get_u32(uint32_t offset) { + DebugHelper::assert((offset + 3) < _romSize, "(DkrExtractROM::get_u32) Data access out of bounds; offset was ", DebugHelper::to_hex(offset), " when ROM size is ", DebugHelper::to_hex(_romSize)); + return (_bytes[offset] << 24) | (_bytes[offset + 1] << 16) | (_bytes[offset + 2] << 8) | _bytes[offset + 3]; +} + +int32_t DkrExtractROM::get_s32(uint32_t offset) { + DebugHelper::assert((offset + 3) < _romSize, "(DkrExtractROM::get_s32) Data access out of bounds; offset was ", DebugHelper::to_hex(offset), " when ROM size is ", DebugHelper::to_hex(_romSize)); + return (_bytes[offset] << 24) | (_bytes[offset + 1] << 16) | (_bytes[offset + 2] << 8) | _bytes[offset + 3]; +} + +uint16_t DkrExtractROM::get_u16(uint32_t offset) { + DebugHelper::assert((offset + 1) < _romSize, "(DkrExtractROM::get_u16) Data access out of bounds; offset was ", DebugHelper::to_hex(offset), " when ROM size is ", DebugHelper::to_hex(_romSize)); + return (_bytes[offset] << 8) | _bytes[offset + 1]; +} + +int16_t DkrExtractROM::get_s16(uint32_t offset) { + DebugHelper::assert((offset + 1) < _romSize, "(DkrExtractROM::get_s16) Data access out of bounds; offset was ", DebugHelper::to_hex(offset), " when ROM size is ", DebugHelper::to_hex(_romSize)); + return (_bytes[offset] << 8) | _bytes[offset + 1]; +} + +uint8_t DkrExtractROM::get_u8(uint32_t offset) { + DebugHelper::assert(offset < _romSize, "(DkrExtractROM::get_u8) Data access out of bounds; offset was ", DebugHelper::to_hex(offset), " when ROM size is ", DebugHelper::to_hex(_romSize)); + return _bytes[offset]; +} + +int8_t DkrExtractROM::get_s8(uint32_t offset) { + DebugHelper::assert(offset < _romSize, "(DkrExtractROM::get_s8) Data access out of bounds; offset was ", DebugHelper::to_hex(offset), " when ROM size is ", DebugHelper::to_hex(_romSize)); + return _bytes[offset]; +} + +union _FloatIntUnion { + uint32_t word; + float wordAsFloat; +}; + +float DkrExtractROM::get_f32(uint32_t offset) { + DebugHelper::assert((offset + 3) < _romSize, "(DkrExtractROM::get_f32) Data access out of bounds; offset was ", DebugHelper::to_hex(offset), " when ROM size is ", DebugHelper::to_hex(_romSize)); + _FloatIntUnion fi; // Doing this to avoid the type-punning warning. + fi.word = (_bytes[offset] << 24) | (_bytes[offset + 1] << 16) | (_bytes[offset + 2] << 8) | _bytes[offset + 3]; + return fi.wordAsFloat; +} + +std::string DkrExtractROM::get_ascii(uint32_t offset, int length) { + bool asciiWithinBounds = (offset < _romSize) || !((length > 0) && ((offset + length) >= _romSize)); + DebugHelper::assert(asciiWithinBounds, "(DkrExtractROM::get_ascii) Data access out of bounds; offset was ", DebugHelper::to_hex(offset), " when ROM size is ", DebugHelper::to_hex(_romSize)); + + char *stringData = reinterpret_cast(_bytes[offset]); + + if(length < 0) { + // string has a null-terminator at the end. + return std::string(stringData); + } + + return std::string(stringData, length); +} + +void DkrExtractROM::get_multiple_ascii(uint32_t offset, std::vector &out, int count) { + // Clear the output vector + out.clear(); + + while(count > 0) { + DebugHelper::assert(offset < _romSize, "(DkrExtractROM::get_multiple_ascii) Data access out of bounds; offset was ", DebugHelper::to_hex(offset), " when ROM size is ", DebugHelper::to_hex(_romSize)); + std::string entry = std::string(reinterpret_cast(_bytes[offset])); + offset += entry.length() + 1; + out.push_back(entry); + count--; + } +} + +void DkrExtractROM::get_data(uint32_t offset, size_t numBytes, std::vector &out) { + // Check if the requested range is within the ROM's size + DebugHelper::assert(offset + numBytes <= _romSize, "(DkrExtractROM::get_data) Requested range is out of bounds. ROM offset = ", DebugHelper::to_hex(offset), ", numBytes = ", DebugHelper::to_hex(numBytes)); + + // Clear the output vector + out.clear(); + + // Get the subsection of the ROM + out.insert(out.end(), _bytes.begin() + offset, _bytes.begin() + offset + numBytes); +} + +void DkrExtractROM::write_rom_section_to_binary_file(fs::path finalFilepath, uint32_t offset, int32_t length) { + DebugHelper::assert(length > 0, "(DkrExtractROM::write_rom_section_to_binary_file) Invalid length of ", length); + FileHelper::write_binary_file((char*)&_bytes[offset], length, finalFilepath, true); +} diff --git a/tools/dkr_assets_tool_src/extract/rom.h b/tools/dkr_assets_tool_src/extract/rom.h new file mode 100644 index 00000000..14ec24b8 --- /dev/null +++ b/tools/dkr_assets_tool_src/extract/rom.h @@ -0,0 +1,42 @@ +#pragma once + +#include + +#include "helpers/fileHelper.h" +#include "helpers/debugHelper.h" +#include "helpers/imageHelper.h" + +class DkrExtractROM { +public: + + DkrExtractROM(fs::path filepath); + ~DkrExtractROM(); + + std::string get_calculated_md5(); + bool is_valid(); + + uint32_t get_u32(uint32_t offset); + int32_t get_s32(uint32_t offset); + uint16_t get_u16(uint32_t offset); + int16_t get_s16(uint32_t offset); + uint8_t get_u8(uint32_t offset); + int8_t get_s8(uint32_t offset); + float get_f32(uint32_t offset); + std::string get_ascii(uint32_t offset, int length=-1); + void get_multiple_ascii(uint32_t offset, std::vector &out, int count); + void get_data(uint32_t offset, size_t numBytes, std::vector &out); + + void write_rom_section_to_binary_file(fs::path finalFilepath, uint32_t offset, int32_t length); + +private: + void _detect_and_fix_rom_endianness(); + void _calculate_md5_checksum(); + + fs::path _filepath; + bool _isValid = false; + std::vector _bytes; + uint32_t _romSize; + std::string _md5; + void _get_fixed_table(uint32_t offset, std::vector &outTable); + void _get_variable_table(uint32_t offset, std::vector &outTable); +}; diff --git a/tools/dkr_assets_tool_src/fileTypes/fonts.hpp b/tools/dkr_assets_tool_src/fileTypes/fonts.hpp new file mode 100644 index 00000000..7d0f48c2 --- /dev/null +++ b/tools/dkr_assets_tool_src/fileTypes/fonts.hpp @@ -0,0 +1,47 @@ +#pragma once + +#include + +#include "types.hpp" + +const int FONTS_NUMBER_OF_TEXTURE_INDICES = 32; + +// Starts at ASCII index 32 and ends at 128. +const char FONTS_START_CHAR = ' '; +const int FONTS_NUMBER_OF_CHARACTERS = 96; + +const fs::path FONTS_SUBDIRECTORY = "game_fonts/"; + +const size_t FONTS_NAME_LENGTH = 32; +const size_t FONTS_JUNKTEXT_LENGTH = 24; + +// 0x8 bytes +struct FontCharacter { +/* 0x0 */ int8_t texIndex; +/* 0x1 */ int8_t charWidth; +/* 0x2 */ int8_t offsetX; +/* 0x3 */ int8_t offsetY; +/* 0x4 */ int8_t texU; +/* 0x5 */ int8_t texV; +/* 0x6 */ int8_t texWidth; +/* 0x7 */ int8_t texHeight; +}; + +// 0x400 bytes +struct FontFile { +/* 0x000 */ char name[FONTS_NAME_LENGTH]; +/* 0x020 */ be_int16_t fixedWidth; +/* 0x022 */ be_int16_t yOffset; +/* 0x024 */ be_int16_t specialCharacterWidth; +/* 0x026 */ be_int16_t tabWidth; +/* 0x028 */ char junkText[FONTS_JUNKTEXT_LENGTH]; +/* 0x040 */ be_int16_t textureIndices[FONTS_NUMBER_OF_TEXTURE_INDICES]; +/* 0x080 */ int32_t reservedForTexturePointers[FONTS_NUMBER_OF_TEXTURE_INDICES]; +/* 0x100 */ FontCharacter characters[FONTS_NUMBER_OF_CHARACTERS]; +}; + +struct FontData { + be_uint32_t numberOfFonts; + FontFile fonts[1]; // Dynamic number of fonts. (Based on numberOfFonts) +}; + \ No newline at end of file diff --git a/tools/dkr_assets_tool_src/fileTypes/gameText.hpp b/tools/dkr_assets_tool_src/fileTypes/gameText.hpp new file mode 100644 index 00000000..a0b65549 --- /dev/null +++ b/tools/dkr_assets_tool_src/fileTypes/gameText.hpp @@ -0,0 +1,62 @@ +#pragma once + +#include "types.hpp" +#include + +const std::vector TEXTBOX_COMMANDS = { + "End", + "NextPage", + "Unused2", + "SetFont", + "SetBorder", + "SetColour", + "SetAlignment", + "Unknown7", + "AddVerticalSpacing", + "SetLineHeight", + "SetTimer", + "AllowUserInput" +}; + +struct SetFontCommand { + uint8_t fontId; +}; + +// 0 = Farthest left/top, 0xFF = Farthest right/bottom +struct SetBorderCommand { + uint8_t left; + uint8_t top; + uint8_t right; + uint8_t bottom; +}; + +struct SetColourCommand { + uint8_t red; + uint8_t green; + uint8_t blue; + uint8_t alpha; +}; + +struct SetAlignmentCommand { + uint8_t value; +}; + +struct Unknown7Command { + uint8_t value; +}; + +struct AddVerticalSpacingCommand { + uint8_t value; +}; + +struct SetLineHeightCommand { + uint8_t value; +}; + +struct SetTimerCommand { + uint8_t value; +}; + +struct AllowUserInputCommand { + uint8_t value; +}; diff --git a/tools/dkr_assets_tool_src/fileTypes/levelHeader.hpp b/tools/dkr_assets_tool_src/fileTypes/levelHeader.hpp new file mode 100644 index 00000000..384dfdf4 --- /dev/null +++ b/tools/dkr_assets_tool_src/fileTypes/levelHeader.hpp @@ -0,0 +1,119 @@ +#pragma once + +#include "types.hpp" + +struct LevelHeader_AiLevels { + int8_t baseAiLevel; + int8_t silverCoinsAiLevel; + int8_t completedAiLevel; + int8_t tracksModeAiLevel; + int8_t trophyRaceAiLevel; +}; + +struct LevelHeader_Weather { + be_int16_t enable; + be_int16_t type; + uint8_t intensity; + uint8_t opacity; + be_int16_t velocity[3]; // X, Y, Z +}; + +struct LevelHeader_Fog { + be_int16_t near; + be_int16_t far; + be_int16_t colour[3]; // R, G, B +}; + +struct LevelHeader { + int8_t world; + uint8_t unk1; + int8_t unk2; + int8_t unk3; + int8_t unk4[4]; + be_float courseHeight; + uint8_t unkC[10]; + uint8_t unk16[10]; + LevelHeader_AiLevels adv1AiLevels; + LevelHeader_AiLevels adv2AiLevels; + uint8_t unk2A; + uint8_t unk2B[9]; + be_int16_t geometry; + be_int16_t collectablesObjMap; + be_int16_t skybox; + + LevelHeader_Fog fog; + + uint8_t unk44[5]; + + // ??? + int8_t specialSky; // For Wizpig 2 + + int8_t velocityCap; + + int8_t laps; + int8_t raceType; + int8_t vehicle; + int8_t avaliableVehicles; + + uint8_t unk4F[3]; + + uint8_t music; + uint8_t unk53; + be_uint16_t instruments; + + uint8_t unk56; + uint8_t unk57; + uint8_t unk58; + uint8_t unk59; + be_int16_t unk5A; + uint8_t unk5C; + uint8_t unk5D; + be_int16_t unk5E; + be_int16_t unk60; + be_int16_t unk62; + be_int16_t unk64; + be_int16_t unk66; + be_int16_t unk68; + uint8_t unk6A; + uint8_t unk6B; + int8_t unk6C; + int8_t unk6D; + be_int16_t unk6E; + uint8_t unk70; + uint8_t unk71; + uint8_t unk72; + uint8_t unk73; + be_int32_t miscAssets[7]; + + // Weather related + LevelHeader_Weather weather; + + int8_t cameraFOV; + uint8_t bgColour[3]; // R, G, B + + be_int16_t unkA0; + int8_t unkA2; + int8_t unkA3; + be_uint32_t specialSkyTexture; // Texture for the animated sky. + be_int16_t unkA8; + be_int16_t unkAA; + be_int32_t pulseLightData; + + be_int16_t unkB0; + uint8_t unkB2; + uint8_t unkB3; + uint8_t unkB4; + uint8_t unkB5; + uint8_t unkB6; + uint8_t unkB7; + int8_t unkB8; + uint8_t unkB9; + be_int16_t objectMap2; + uint8_t unkBC; + int8_t unkBD; + // Multiplayer gradient background + uint8_t bgColourBottom[3]; // R, G, B + uint8_t bgColourTop[3]; // R, G, B + + uint32_t unkC4; +}; \ No newline at end of file diff --git a/tools/dkr_assets_tool_src/fileTypes/levelObjectMap.hpp b/tools/dkr_assets_tool_src/fileTypes/levelObjectMap.hpp new file mode 100644 index 00000000..417d9835 --- /dev/null +++ b/tools/dkr_assets_tool_src/fileTypes/levelObjectMap.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include "types.hpp" + +// 16 bytes +struct LevelObjectMapHeader { + /* 0x00 */ be_uint32_t fileSize; // Total number of bytes of the file. + /* 0x04 */ uint8_t pad4[12]; // Unused in DKR? +}; + +struct LevelObjectMap { + /* 0x00 */ LevelObjectMapHeader header; + /* 0x10 */ uint8_t entriesData[1]; // Bytes of the object entries. (It is dynamic, so can't be any more specific) +}; diff --git a/tools/dkr_assets_tool_src/fileTypes/levelObjectTranslationTable.hpp b/tools/dkr_assets_tool_src/fileTypes/levelObjectTranslationTable.hpp new file mode 100644 index 00000000..421dfa1c --- /dev/null +++ b/tools/dkr_assets_tool_src/fileTypes/levelObjectTranslationTable.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include "types.hpp" + +// In DKR, each entry is a big-endian halfword. +#define LOTT_ENTRY be_int16_t + +const size_t LOTT_SIZE = 512; // In DKR, there are 512 available slots. diff --git a/tools/dkr_assets_tool_src/fileTypes/misc.hpp b/tools/dkr_assets_tool_src/fileTypes/misc.hpp new file mode 100644 index 00000000..056d9a6d --- /dev/null +++ b/tools/dkr_assets_tool_src/fileTypes/misc.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include "types.hpp" + +struct TitleScreenDemos { + int8_t levelId; + int8_t numberOfPlayers; + int8_t cutsceneId; +}; + +struct CheatsTableEntry { + be_int16_t codeOffset; + be_int16_t descOffset; +}; diff --git a/tools/dkr_assets_tool_src/fileTypes/objectHeader.hpp b/tools/dkr_assets_tool_src/fileTypes/objectHeader.hpp new file mode 100644 index 00000000..5872046e --- /dev/null +++ b/tools/dkr_assets_tool_src/fileTypes/objectHeader.hpp @@ -0,0 +1,106 @@ +#pragma once + +#include +#include + +#include "libs/bimap.hpp" + +#include "types.hpp" + +enum ObjectModelType { + OBJECT_MODEL_TYPE_3D_MODEL, + OBJECT_MODEL_TYPE_SPRITE_BILLBOARD, + OBJECT_MODEL_TYPE_VEHICLE_PART, + OBJECT_MODEL_TYPE_UNKNOWN3, + OBJECT_MODEL_TYPE_MISC +}; + +// TODO: Figure out object header flags. +// bimap is useful here since the keys and values are 1 to 1. +const stde::bimap OBJECT_HEADER_FLAGS = { +}; + +struct ObjectHeaderParticleData { + struct bytes { + uint8_t b0; + uint8_t b1; + }; + + struct shorts { + union { + be_int16_t s0_s; + bytes s0_b; + }; + union { + be_int16_t s1_s; + bytes s1_b; + }; + }; + + union { + be_int32_t upper; + shorts upper_w; + }; + + union { + be_int32_t lower; + shorts lower_w; + }; +}; + +typedef struct ObjectHeader { + /* 0x00 */ be_int32_t unk0; // The one use I've seen for this so far is water effect animation speed. + /* 0x04 */ be_float shadowScale; + /* 0x08 */ be_float unk8; + /* 0x0C */ be_float scale; + /* 0x10 */ be_int32_t modelIds; + /* 0x14 */ be_int32_t vehiclePartIds; + /* 0x18 */ be_int32_t vehiclePartIndices; + /* 0x1C */ be_int32_t objectParticles; + be_int32_t unk20; + /* 0x24 */ be_int32_t unk24; // Lights + /* 0x28 */ be_float shadeBrightness; + /* 0x2C */ be_float shadeAmbient; + /* 0x30 */ be_uint16_t flags; + /* 0x32 */ be_int16_t shadowGroup; + /* 0x34 */ be_int16_t unk34; + /* 0x36 */ be_int16_t waterEffectGroup; + /* 0x38 */ be_int16_t unk38; + /* 0x3A */ uint8_t unk3A; + /* 0x3B */ uint8_t unk3B; + /* 0x3C */ uint8_t unk3C; + /* 0x3D */ uint8_t unk3D; + /* 0x3E */ be_int16_t shadeAngleY; + /* 0x40 */ be_int16_t shadeAngleZ; + /* 0x42 */ be_int16_t unk42; + /* 0x44 */ be_int16_t unk44; + /* 0x48 */ be_int16_t unk46; + /* 0x48 */ be_int16_t unk48; + /* 0x4A */ be_int16_t unk4A; + /* 0x4C */ be_int16_t unk4C; + /* 0x4E */ be_int16_t drawDistance; + /* 0x50 */ be_int16_t unk50; + /* 0x52 */ int8_t unk52; // Number of instances? + /* 0x53 */ int8_t modelType; + /* 0x54 */ int8_t behaviorId; + /* 0x55 */ int8_t numberOfModelIds; // size of array pointed by Object->unk68 + /* 0x56 */ int8_t numberOfVehicleParts; // vehiclePartIds count + /* 0x57 */ int8_t numberOfParticles; // Particle count? + /* 0x58 */ int8_t unk58; // Index of some kind? + /* 0x59 */ uint8_t unk59; + /* 0x5A */ int8_t numLightSources; + /* 0x5B */ uint8_t unk5B; // Sound related? + /* 0x5C */ uint8_t unk5C; + /* 0x5D */ uint8_t unk5D; //Misc Asset index? + /* 0x5E */ uint8_t unk5E; + /* 0x5F */ uint8_t unk5F; + /* 0x60 */ char internalName[16]; + /* 0x70 */ uint8_t unk70; + /* 0x71 */ uint8_t unk71; + /* 0x72 */ uint8_t unk72; + /* 0x73 */ uint8_t unk73; + /* 0x74 */ uint8_t unk74; + /* 0x75 */ uint8_t unk75; + /* 0x76 */ uint8_t unk76; + /* 0x77 */ uint8_t unk77; +} ObjectHeader; \ No newline at end of file diff --git a/tools/dkr_assets_tool_src/fileTypes/sprite.hpp b/tools/dkr_assets_tool_src/fileTypes/sprite.hpp new file mode 100644 index 00000000..f437aecb --- /dev/null +++ b/tools/dkr_assets_tool_src/fileTypes/sprite.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include "types.hpp" + +// Size: 12 bytes. +struct SpriteHeader { + be_int16_t startTextureIndex; + be_int16_t numberOfFrames; + be_int16_t unk4; + be_int16_t unk6; + be_int32_t unk8; // Set in-game, always zero in ROM. + //uint8_t data[1]; // Dynamic size, based on numberOfFrames. +}; diff --git a/tools/dkr_assets_tool_src/fileTypes/texCoords.hpp b/tools/dkr_assets_tool_src/fileTypes/texCoords.hpp new file mode 100644 index 00000000..d9dc1da6 --- /dev/null +++ b/tools/dkr_assets_tool_src/fileTypes/texCoords.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include "types.hpp" + +/* Size: 4 bytes */ +typedef struct DkrTexCoords { + be_int16_t u; + be_int16_t v; +} DkrTexCoords; diff --git a/tools/dkr_assets_tool_src/fileTypes/texture.hpp b/tools/dkr_assets_tool_src/fileTypes/texture.hpp new file mode 100644 index 00000000..b98dcbde --- /dev/null +++ b/tools/dkr_assets_tool_src/fileTypes/texture.hpp @@ -0,0 +1,53 @@ +#pragma once + +#include +#include "types.hpp" + +const std::string DEFAULT_TEXTURE_FORMAT = "RGBA16"; + +const double TEXTURE_FPS = 60.0; +const int TEXTURE_TIME_ROUND_PLACES = 3; // Round time floats to 3 decimal places. + +const std::vector TEXTURE_FORMAT_INT_TO_STRING = { + "RGBA32", "RGBA16", "I8", "I4", "IA16", "IA8", "IA4", "CI4", "CI8" +}; + +const std::vector TEXTURE_RENDER_MODES = { + "TRANSPARENT", "OPAQUE", "TRANSPARENT_2", "OPAQUE_2" +}; + +struct TextureHeader { + /* 0x00 */ uint8_t width; + /* 0x01 */ uint8_t height; + /* 0x02 */ uint8_t format; // Lower 4 bits determines image format. + // 0 = RGBA32 + // 1 = RGBA16 + // 2 = I8 + // 3 = I4 + // 4 = IA16 + // 5 = IA8 + // 6 = IA4 + // 7 = CI4 (16 colors) + // 8 = CI8 (64 colors) + /* 0x03 */ int8_t spriteX; + /* 0x04 */ int8_t spriteY; + /* 0x05 */ uint8_t numberOfInstances; // Always 1 in the ROM. + /* 0x06 */ be_int16_t flags; + /* 0x08 */ be_int16_t ciPaletteOffset; + /* 0x0A */ be_int16_t numberOfCommands; // initialized in RAM; Number of commands in the texture display list. (Usually 0x07) + /* 0x0C */ be_int32_t cmd; // initialized in RAM; Pointer to texture display list. + /* 0x10 */ uint8_t unk10; + /* 0x11 */ uint8_t unk11; + /* 0x12 */ uint8_t numOfTextures; // For animated textures, static textures are just 0x01. Each texture has it's own header. + /* 0x13 */ uint8_t unk13; + /* 0x14 */ be_uint16_t frameAdvanceDelay; // How many frames to delay before moving to the next texture. + /* 0x16 */ be_int16_t textureSize; // Size in number of bytes, including the header + /* 0x18 */ uint8_t unk18; + /* 0x19 */ uint8_t unk19; + /* 0x1A */ uint8_t unk1A; + /* 0x1B */ uint8_t unk1B; + /* 0x1C */ uint8_t unk1C; + /* 0x1D */ uint8_t isCompressed; + /* 0x1E */ uint8_t unk1E; + /* 0x1F */ uint8_t unk1F; +}; diff --git a/tools/dkr_assets_tool_src/fileTypes/triangle.hpp b/tools/dkr_assets_tool_src/fileTypes/triangle.hpp new file mode 100644 index 00000000..551e8a6a --- /dev/null +++ b/tools/dkr_assets_tool_src/fileTypes/triangle.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include "types.hpp" +#include "texCoords.hpp" + +/* Size: 0x10 bytes */ +typedef struct DkrTriangle { +/* 0x00 */ uint8_t flags; // 0x40 = Draw backface, 0x00 = Cull backface +/* 0x01 */ uint8_t vi0; // First vertex index +/* 0x02 */ uint8_t vi1; // Second vertex index +/* 0x03 */ uint8_t vi2; // Third vertex index +/* 0x04 */ DkrTexCoords uv0; // Texture coordinates for the first vertex +/* 0x08 */ DkrTexCoords uv1; // Texture coordinates for the second vertex +/* 0x0C */ DkrTexCoords uv2; // Texture coordinates for the third vertex +} DkrTriangle; diff --git a/tools/dkr_assets_tool_src/fileTypes/ttGhost.hpp b/tools/dkr_assets_tool_src/fileTypes/ttGhost.hpp new file mode 100644 index 00000000..0f2cba9d --- /dev/null +++ b/tools/dkr_assets_tool_src/fileTypes/ttGhost.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include "types.hpp" + +#define GHOST_TIME_FPS 60.0 + +/* Size: 8 bytes */ +typedef struct GhostHeader { + /* 0x00 */ uint8_t levelId; + /* 0x01 */ uint8_t vehicleId; // 0 = Car, 1 = Hovercraft, 2 = Plane + /* 0x02 */ uint8_t characterId; // 9 = T.T. + /* 0x03 */ uint8_t unk3; // Might just be padding? + /* 0x04 */ be_int16_t time; // In frames, where 60 frames = 1 second. + /* 0x06 */ be_int16_t nodeCount; // Maximum of 1080 nodes. +} GhostHeader; + +/* Size: 12 bytes */ +typedef struct GhostNode { + /* 0x00 */ be_int16_t x; + /* 0x02 */ be_int16_t y; + /* 0x04 */ be_int16_t z; + /* 0x06 */ be_int16_t zRotation; // This order is correct. + /* 0x08 */ be_int16_t xRotation; + /* 0x0A */ be_int16_t yRotation; +} GhostNode; diff --git a/tools/dkr_assets_tool_src/fileTypes/types.hpp b/tools/dkr_assets_tool_src/fileTypes/types.hpp new file mode 100644 index 00000000..e1414760 --- /dev/null +++ b/tools/dkr_assets_tool_src/fileTypes/types.hpp @@ -0,0 +1,90 @@ +#pragma once + +#include +#include // for ntohs() etc. +#include + +class be_uint16_t { +public: + be_uint16_t() : be_val_(0) { + } + // Transparently cast from uint16_t + be_uint16_t(const uint16_t &val) : be_val_(htons(val)) { + } + // Transparently cast to uint16_t + operator uint16_t() const { + return ntohs(be_val_); + } +private: + uint16_t be_val_; +} __attribute__((packed)); + +class be_uint32_t { +public: + be_uint32_t() : be_val_(0) { + } + // Transparently cast from uint16_t + be_uint32_t(const uint32_t &val) : be_val_(htonl(val)) { + } + // Transparently cast to uint16_t + operator uint32_t() const { + return ntohl(be_val_); + } +private: + uint32_t be_val_; +} __attribute__((packed)); + +class be_int16_t { +public: + be_int16_t() : be_val_(0) { + } + // Transparently cast from int16_t + be_int16_t(const int16_t &val) : be_val_(htons(val)) { + } + // Transparently cast to int16_t + operator int16_t() const { + return ntohs(be_val_); + } +private: + int16_t be_val_; +} __attribute__((packed)); + +class be_int32_t { +public: + be_int32_t() : be_val_(0) {} + // Transparently cast from int32_t + be_int32_t(const int32_t &val) : be_val_(htonl(val)) { + } + // Transparently cast to int32_t + operator int32_t() const { + return ntohl(be_val_); + } +private: + int32_t be_val_; +} __attribute__((packed)); + +// Removes type-punning warning. +union floatInt { + uint32_t i; + float f; +}; + +class be_float { +public: + be_float() : be_val_(0.0f) {} + be_float(float val) { + floatInt floatAsInt; + floatAsInt.f = val; + floatAsInt.i = htonl(floatAsInt.i); + be_val_ = floatAsInt.f; + } + operator float() const { + floatInt floatAsInt; + floatAsInt.f = be_val_; + floatAsInt.i = ntohl(floatAsInt.i); + return floatAsInt.f; + } +private: + float be_val_; +} __attribute__((packed)); + diff --git a/tools/dkr_assets_tool_src/fileTypes/vertex.hpp b/tools/dkr_assets_tool_src/fileTypes/vertex.hpp new file mode 100644 index 00000000..f59a07e8 --- /dev/null +++ b/tools/dkr_assets_tool_src/fileTypes/vertex.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include "types.hpp" + +/* Size: 10 bytes */ +struct DkrVertex { +/* 0x00 */ be_int16_t x; +/* 0x02 */ be_int16_t y; +/* 0x04 */ be_int16_t z; +/* 0x06 */ uint8_t r; +/* 0x07 */ uint8_t g; +/* 0x08 */ uint8_t b; +/* 0x09 */ uint8_t a; +}; \ No newline at end of file diff --git a/tools/dkr_assets_tool_src/helpers/asmHeader.cpp b/tools/dkr_assets_tool_src/helpers/asmHeader.cpp new file mode 100644 index 00000000..17f76b0b --- /dev/null +++ b/tools/dkr_assets_tool_src/helpers/asmHeader.cpp @@ -0,0 +1,54 @@ +#include "asmHeader.h" + +#include "helpers/fileHelper.h" + +WritableAsmInclude::WritableAsmInclude() { +} + +WritableAsmInclude::~WritableAsmInclude() { + +} + +void WritableAsmInclude::write_comment(const char *text) { + _out << "# " << text << std::endl; +} + +void WritableAsmInclude::write_header_comment(const char *text) { + _out << "/********** " << text << " **********/" << std::endl << std::endl; +} + +void WritableAsmInclude::write_newline() { + _out << std::endl; +} + +void WritableAsmInclude::write_word(const std::string &value) { + _out << ".word " << value << std::endl; +} + +void WritableAsmInclude::write_two_words(const std::string &value, const std::string &value2) { + _out << ".word " << value << ", " << value2 << std::endl; +} + +void WritableAsmInclude::write_word_with_comment(const std::string &value, const char *comment) { + _out << ".word " << value << " # " << comment << std::endl; +} + +void WritableAsmInclude::write_include(std::string filepath) { + _out << ".include \"" << filepath << "\"" << std::endl; +} + +void WritableAsmInclude::write_binary_include(std::string filepath) { + _out << ".incbin \"" << filepath << "\"" << std::endl; +} + +void WritableAsmInclude::write_global_label(const std::string &label, bool align16) { + if(align16) { + _out << ".balign 16" << std::endl; + } + _out << "glabel " << label << std::endl; +} + +void WritableAsmInclude::save(fs::path filepath) { + std::string headerText = _out.str(); + FileHelper::write_text_file(headerText, filepath, true); +} diff --git a/tools/dkr_assets_tool_src/helpers/asmHeader.h b/tools/dkr_assets_tool_src/helpers/asmHeader.h new file mode 100644 index 00000000..ff3e90bc --- /dev/null +++ b/tools/dkr_assets_tool_src/helpers/asmHeader.h @@ -0,0 +1,31 @@ +#pragma once + +#include + +#include "helpers/fileHelper.h" + +// Write-Only C Header generator class +class WritableAsmInclude { +public: + WritableAsmInclude(); + ~WritableAsmInclude(); + + void write_comment(const char *comment); + void write_header_comment(const char *comment); + + void write_newline(); + + void write_word(const std::string &value); + void write_two_words(const std::string &value, const std::string &value2); + void write_word_with_comment(const std::string &value, const char *comment); + + void write_include(std::string filepath); + void write_binary_include(std::string filepath); + + void write_global_label(const std::string &label, bool align=false); + + void save(fs::path filepath); + +private: + std::stringstream _out; +}; diff --git a/tools/dkr_assets_tool_src/helpers/assetsHelper.cpp b/tools/dkr_assets_tool_src/helpers/assetsHelper.cpp new file mode 100644 index 00000000..3378497f --- /dev/null +++ b/tools/dkr_assets_tool_src/helpers/assetsHelper.cpp @@ -0,0 +1,157 @@ +#include "assetsHelper.h" + +#include "helpers/fileHelper.h" +#include "helpers/debugHelper.h" + +DeferredAssetInfo::DeferredAssetInfo(std::string type, std::string fromSection, std::string idPostfix, std::string outputPath) : + type(type), fromSection(fromSection), idPostfix(idPostfix), outputPath(outputPath) { + DebugHelper::assert(!type.empty(), "(DeferredAssetInfo::DeferredAssetInfo) Type not specified!"); +} + +// Note: filepath is local to assets. +JsonFile *AssetsHelper::get_meta_file(DkrAssetsSettings &settings, fs::path filepath) { + JsonFile *out; + + DebugHelper::assert(JsonHelper::get().get_file(settings.pathToAssets / filepath, &out), + "(AssetsHelper::get_meta_file) Could not find json file in assets folder: ", filepath); + + return out; +} + +JsonFile *AssetsHelper::get_main_json(DkrAssetsSettings &settings) { + return get_main_json(settings.pathToAssets); +} + +JsonFile *AssetsHelper::get_main_json(fs::path pathToAssets) { + fs::path mainAssetsFilepath = pathToAssets / "assets.meta.json"; + + JsonFile *mainJson; + // Load assets.meta.json, and throw error if it couldn't be found. + DebugHelper::assert(JsonHelper::get().get_file(mainAssetsFilepath, &mainJson), + "(AssetsHelper::_get_section_json) Could not find assets.meta.json. Path was ", mainAssetsFilepath); + + return mainJson; +} + +JsonFile *AssetsHelper::get_asset_section_json(DkrAssetsSettings &settings, const std::string assetSectionId) { + return _get_section_json(settings.pathToAssets, assetSectionId); +} + +// Returns the asset JSON file from a section ID & build ID. +JsonFile *AssetsHelper::get_asset_json(DkrAssetsSettings &settings, const std::string assetSectionId, std::string buildId) { + JsonFile *out = nullptr; + + JsonFile *sectionJson = _get_section_json(settings.pathToAssets, assetSectionId); + + DebugHelper::assert(sectionJson != nullptr, + "(AssetsHelper::get_build_id_of_index) _get_section_json returned null for ", assetSectionId); + + fs::path filename; + + if(buildId.empty()) { + DebugHelper::assert(sectionJson->has("/filename"), + "(AssetsHelper::get_asset_json) [/filename] was not found in the section \"", assetSectionId, "\""); + filename = sectionJson->get_string("/filename"); + } else { + std::string fileSectionPtr = "/files/sections/" + buildId; + + // Make sure the section build id exists in the section json file. + DebugHelper::assert(sectionJson->has(fileSectionPtr), + "(AssetsHelper::get_asset_json) Section \"", buildId, "\" was not found in the section \"", assetSectionId, "\""); + + filename = sectionJson->get_string(fileSectionPtr + "/filename"); + } + + + fs::path localFolder = sectionJson->get_path("/folder"); + FileHelper::format_folder_string(localFolder); // Make sure localFolder string is valid. + fs::path filepath = settings.pathToAssets / localFolder / filename; + + // Load the file JSON, and throw error if it couldn't be found. + DebugHelper::assert(JsonHelper::get().get_file(filepath, &out), + "(AssetsHelper::get_asset_json) Could not find file json. Path was ", filepath); + + return out; +} + +// Returns the index to an asset from a section. +int AssetsHelper::get_asset_index(DkrAssetsSettings &settings, const std::string assetSectionId, std::string &buildId) { + JsonFile *sectionJson = _get_section_json(settings.pathToAssets, assetSectionId); + int index = sectionJson->get_index_of_elem_in_array("/files/order", buildId); + + // Throws an error if the element was not found. + DebugHelper::assert(index >= 0, + "(AssetsHelper::get_asset_index) Could not find \"", buildId, "\" in the order defined in the section \"", assetSectionId, "\""); + + return index; +} + +std::string AssetsHelper::get_section_path(DkrAssetsSettings &settings, const std::string &assetSectionId) { + JsonFile *sectionJson = _get_section_json(settings.pathToAssets, assetSectionId); + + DebugHelper::assert(sectionJson != nullptr, + "(AssetsHelper::get_section_path) _get_section_json returned null for ", assetSectionId); + + return sectionJson->get_path("/folder"); +} + +std::string AssetsHelper::get_build_id_of_index(DkrAssetsSettings &settings, const std::string &assetSectionId, int index) { + JsonFile *sectionJson = _get_section_json(settings.pathToAssets, assetSectionId); + + DebugHelper::assert(sectionJson != nullptr, + "(AssetsHelper::get_build_id_of_index) _get_section_json returned null for ", assetSectionId); + + return sectionJson->get_elem_from_array("/files/order", index); +} + +DeferredAssetInfo AssetsHelper::get_deferred_asset_info(DkrAssetsSettings &settings, const std::string assetSectionId) { + JsonFile *mainJson = get_main_json(settings); + + std::string sectionJsonPtr = "/assets/sections/" + assetSectionId; + + DebugHelper::assert(mainJson->get_bool(sectionJsonPtr + "/deferred"), + "(AssetsHelper::get_deferred_asset_info) ", assetSectionId, " is not deferred!"); + + std::string deferInfoPtr = sectionJsonPtr + "/defer-info"; + + return DeferredAssetInfo( + mainJson->get_string(sectionJsonPtr + "/type"), + mainJson->get_string(deferInfoPtr + "/from-section"), + mainJson->get_string(deferInfoPtr + "/id-postfix"), + mainJson->get_string(deferInfoPtr + "/output-path") + ); +} + +JsonFile *AssetsHelper::_get_section_json(fs::path pathToAssets, const std::string &assetSectionId) { + JsonFile *out = nullptr; + + JsonFile *mainJson = get_main_json(pathToAssets); + + std::string sectionJsonPtr = "/assets/sections/" + assetSectionId; + + // Make sure the section build id exists in assets.meta.json + DebugHelper::assert(mainJson->has(sectionJsonPtr), + "(AssetsHelper::_get_section_json) Section \"", assetSectionId, "\" was not found in assets.meta.json"); + + bool isDeferred = mainJson->get_bool(sectionJsonPtr + "/deferred", false); + + if(isDeferred) { + //DebugHelper::warn("Section \"", assetSectionId, "\" is deferred. Returning null pointer!"); + return nullptr; + } + + fs::path filename = mainJson->get_string(sectionJsonPtr + "/filename"); + + if(filename.empty()) { + //DebugHelper::warn("Section \"", assetSectionId, "\" has no filename. Returning null pointer!"); + return nullptr; + } + + fs::path sectionFilepath = pathToAssets / filename; + + // Load the section JSON, and throw error if it couldn't be found. + DebugHelper::assert(JsonHelper::get().get_file(sectionFilepath, &out), + "(AssetsHelper::_get_section_json) Could not find section json. Path was ", sectionFilepath); + + return out; +} diff --git a/tools/dkr_assets_tool_src/helpers/assetsHelper.h b/tools/dkr_assets_tool_src/helpers/assetsHelper.h new file mode 100644 index 00000000..86cba559 --- /dev/null +++ b/tools/dkr_assets_tool_src/helpers/assetsHelper.h @@ -0,0 +1,40 @@ +#pragma once + +#include + +#include "helpers/jsonHelper.h" +#include "misc/settings.hpp" + +struct DeferredAssetInfo { + std::string type; + std::string fromSection; + std::string idPostfix; + std::string outputPath; + + DeferredAssetInfo(std::string type, std::string fromSection, + std::string idPostfix, std::string outputPath); +}; + +/** + * Singleton class that deals with getting asset JSON files for building. + */ +class AssetsHelper { +public: + static AssetsHelper& get() { + static AssetsHelper instance; + return instance; + } + + static JsonFile *get_meta_file(DkrAssetsSettings &settings, fs::path filepath); + static JsonFile *get_main_json(DkrAssetsSettings &settings); + static JsonFile *get_main_json(fs::path pathToAssets); + static JsonFile *get_asset_section_json(DkrAssetsSettings &settings, const std::string assetSectionId); + static JsonFile *get_asset_json(DkrAssetsSettings &settings, const std::string assetSectionId, std::string buildId=""); + static int get_asset_index(DkrAssetsSettings &settings, const std::string assetSectionId, std::string &buildId); + static std::string get_section_path(DkrAssetsSettings &settings, const std::string &assetSectionId); + static std::string get_build_id_of_index(DkrAssetsSettings &settings, const std::string &assetSectionId, int index); + + static DeferredAssetInfo get_deferred_asset_info(DkrAssetsSettings &settings, const std::string assetSectionId); +private: + static JsonFile *_get_section_json(fs::path pathToAssets, const std::string &assetSectionId); +}; diff --git a/tools/dkr_assets_tool_src/helpers/c/cContext.cpp b/tools/dkr_assets_tool_src/helpers/c/cContext.cpp new file mode 100644 index 00000000..e61f2607 --- /dev/null +++ b/tools/dkr_assets_tool_src/helpers/c/cContext.cpp @@ -0,0 +1,123 @@ +#include "cContext.h" + +#include "helpers/debugHelper.h" +#include "helpers/c/cStructHelper.h" + +#include "cTypes.h" + +CContext::CContext() { +} + +CContext::~CContext() { +} + +void CContext::register_struct(CStruct *structRef) { + DebugHelper::assert(structRef != nullptr, "(CContext::register_struct) Trying to register a null pointer!"); + std::string structName = structRef->get_name(); + if(structName.empty()) { + return; + } + //DebugHelper::info("Registering struct \"", structName, "\""); + DebugHelper::assert(_structsByName.find(structName) == _structsByName.end(), + "(CContext::register_struct) struct \"", structName, "\" has already been defined!"); + _structsByName[structName] = structRef; +} + +void CContext::deregister_struct(std::string &structName) { + if(structName.empty()) { + return; + } + // Make sure the key actually exists in the map. + if(_structsByName.find(structName) == _structsByName.end()) { + return; + } + _structsByName.erase(structName); +} + +CStruct *CContext::get_struct(const std::string &structName) { + DebugHelper::assert(_structsByName.find(structName) != _structsByName.end(), + "(CContext::get_struct) struct \"", structName, "\" is not defined!"); + return _structsByName[structName]; +} + +// Returns 0 if element was not found. +size_t CContext::get_size_of_element(const std::string &elementName) { + // First search to see if the element is a struct + if(_structsByName.find(elementName) != _structsByName.end()) { + CStruct *structElem = get_struct(elementName); + return structElem->get_byte_size(); + } + // Then search to see if the element is an enum. + if(_enumsByName.find(elementName) != _enumsByName.end()) { + return 4; // Enums should be integers, which are 4 bytes. + } + // Lastly, check to see if the element is just a basic type. + if(CTypes::is_standard_type(elementName)) { + return CTypes::get_size_of_type(elementName); + } + return 0; // Could not find element. +} + +void CContext::clear_structs() { + _structsByName.clear(); +} + +void CContext::register_enum(CEnum *enumRef) { + DebugHelper::assert(enumRef != nullptr, "(CContext::register_enum) Trying to register a null pointer!"); + std::string enumName = enumRef->get_name(); + if(enumName.empty()) { + return; + } + //DebugHelper::info("Registering enum \"", enumName, "\""); + DebugHelper::assert(_enumsByName.find(enumName) == _enumsByName.end(), + "(CContext::register_enum) struct \"", enumName, "\" has already been defined!"); + _enumsByName[enumName] = enumRef; + _add_enum_values(enumRef); +} + +void CContext::deregister_enum(std::string &enumName) { + if(enumName.empty()) { + return; + } + // Make sure the key actually exists in the map. + if(_enumsByName.find(enumName) == _enumsByName.end()) { + return; + } + _enumsByName.erase(enumName); +} + +CEnum *CContext::get_enum(const std::string &enumName) { + DebugHelper::assert(_enumsByName.find(enumName) != _enumsByName.end(), + "(CContext::get_enum) enum \"", enumName, "\" is not defined!"); + return _enumsByName[enumName]; +} + +void CContext::clear_enums() { + _enumsByName.clear(); + _enumValues.clear(); +} + +// Currently just gets loaded enum values. +int CContext::get_int_value_of_symbol(const std::string &symbolName) { + if(_enumValues.find(symbolName) != _enumValues.end()) { + return _enumValues[symbolName]; + } + DebugHelper::error("(CContext::get_int_value_of_symbol) Could not evaluate the symbol \"", symbolName, "\""); + return 0; +} + + +std::string CContext::get_symbol_of_enum_int(std::string enumName, int index) { + CEnum *e = get_enum(enumName); + DebugHelper::assert(e != nullptr, "(CContext::get_symbol_of_enum_int) Enum \"", enumName, "\" does not exist!"); + std::string out; + DebugHelper::assert( + e->get_symbol_of_value(index, out), + "(CContext::get_symbol_of_enum_int) Enum \"", enumName, "\" does not have the index value of ", index + ); + return out; +} + +void CContext::_add_enum_values(CEnum *enumRef) { + enumRef->copy_members_to_map(_enumValues); +} diff --git a/tools/dkr_assets_tool_src/helpers/c/cContext.h b/tools/dkr_assets_tool_src/helpers/c/cContext.h new file mode 100644 index 00000000..a768f1d8 --- /dev/null +++ b/tools/dkr_assets_tool_src/helpers/c/cContext.h @@ -0,0 +1,40 @@ +#pragma once + +#include +#include + +#include + +#include "helpers/c/cStructHelper.h" +#include "helpers/c/cEnumsHelper.h" + +class CContext { +public: + CContext(); + ~CContext(); + + // Structures / Unions + void register_struct(CStruct *structRef); + void deregister_struct(std::string &structName); + CStruct *get_struct(const std::string &structName); + size_t get_size_of_element(const std::string &elementName); + void clear_structs(); + + // Enums + void register_enum(CEnum *enumRef); + void deregister_enum(std::string &enumName); + CEnum *get_enum(const std::string &enumName); + void clear_enums(); + + // General + int get_int_value_of_symbol(const std::string &symbolName); + + std::string get_symbol_of_enum_int(std::string enumName, int index); + +private: + std::unordered_map _structsByName; + std::unordered_map _enumsByName; + std::unordered_map _enumValues; + + void _add_enum_values(CEnum *enumRef); +}; \ No newline at end of file diff --git a/tools/dkr_assets_tool_src/helpers/c/cEnumsHelper.cpp b/tools/dkr_assets_tool_src/helpers/c/cEnumsHelper.cpp new file mode 100644 index 00000000..336e470f --- /dev/null +++ b/tools/dkr_assets_tool_src/helpers/c/cEnumsHelper.cpp @@ -0,0 +1,214 @@ +#include "cEnumsHelper.h" + +#include +#include + +#include "helpers/fileHelper.h" +#include "helpers/regexHelper.h" +#include "helpers/debugHelper.h" +#include "helpers/stringHelper.h" + +#include "libs/calculator.hpp" + +#include "cContext.h" + +const std::string C_ENUM_DEFINITION = R"((typedef)?\s*(enum)\s*([A-Za-z_][A-Za-z_0-9]*)?\s*\{([^}]*)\}\s*([A-Za-z_][A-Za-z_0-9]*)?\s*;)"; +const std::string C_ENUM_MEMBER = R"(\s*([A-Za-z_][A-Za-z0-9_]*)\s*((?:(?:=)\s*([^,]*))|(?:\,)|(?:$)))"; +const std::string C_ENUM_SYMBOL = R"(\b([A-Za-z_][A-Za-z0-9_]*)\b)"; + +// Modifies `enumValue` so that all symbols get converted to integers. For example: "VEHICLE_PLANE" should get replaced with "2". +void CEnum::_evaluate_enum_symbols(std::string &enumValue) { + while(true) { + RegexMatch *match = RegexHelper::get_first_match(enumValue, C_ENUM_SYMBOL); + if(match == nullptr) { + return; // Done! + } + std::string symbol = match->get_group(1).get_text(); + int offset = match->get_group(1).get_offset(); + int value; + if(!get_value_of_member(symbol, value)) { + // If the value is not a part of this enum, then go check to see if the context has it. + value = _context->get_int_value_of_symbol(symbol); + } + std::string valueAsString = std::to_string(value); + enumValue = enumValue.replace(offset, symbol.length(), valueAsString); + delete match; // Done with the match. + } +} + +int CEnum::_evaluate_enum(std::string enumValue) { + StringHelper::trim(enumValue); + _evaluate_enum_symbols(enumValue); + try { + return calculator::eval(enumValue); + } catch (calculator::error& e) { + std::cerr << e.what() << std::endl; + throw 1; + } +} + +int CEnum::_parse_enum_value(std::string &enumValue) { + try { + // Should work for most basic cases. + return std::stoi(enumValue, 0, 0); + } catch (const std::invalid_argument& ia) { + // Not a simple conversion, continue. + } + return _evaluate_enum(enumValue); +} + +CEnum::CEnum(CContext *context) : _context(context) { +} + +CEnum::CEnum(CContext *context, const std::string &rawCode) : _context(context) { + RegexMatch *enumDefMatch = RegexHelper::get_first_match(rawCode, C_ENUM_DEFINITION); + DebugHelper::assert(enumDefMatch != nullptr, "rawCode \"", rawCode, "\" is not valid."); + + _name = enumDefMatch->get_group(3).get_text(); + + std::string typedefGroup = enumDefMatch->get_group(1).get_text(); + if(typedefGroup == "typedef") { + _typedefName = enumDefMatch->get_group(5).get_text(); + } + + const std::string enumCode = enumDefMatch->get_group(4).get_text(); + + std::vector enumMemberMatches; + + RegexHelper::get_matches(enumCode, C_ENUM_MEMBER, enumMemberMatches); + + int nextValue = 0; + for(RegexMatch &match : enumMemberMatches) { + std::string enumLabel = match.get_group(1).get_text(); + std::string rest = match.get_group(2).get_text(); + + if(StringHelper::starts_with(rest, "=")) { + std::string enumValue = match.get_group(3).get_text(); + int parsedEnumValue = _parse_enum_value(enumValue); + _members[enumLabel] = parsedEnumValue; + nextValue = parsedEnumValue + 1; + continue; + } + _members[enumLabel] = nextValue; + nextValue++; + } + + _context->register_enum(this); +} + +CEnum::~CEnum() { + _context->deregister_enum(_name); +} + +std::string CEnum::get_name() { + return _name; +} + +void CEnum::copy_members_to_map(std::unordered_map &inputMap) { + for (const auto & [ key, value ] : _members) { + inputMap[key] = value; + } +} + + +bool CEnum::get_value_of_member(const std::string &memberKey, int &out) { + if(_members.find(memberKey) == _members.end()) { + return false; + } + out = _members[memberKey]; + return true; +} + +bool CEnum::get_symbol_of_value(int value, std::string &outSymbol) { + for (auto& it : _members) { + if (it.second == value) { + outSymbol = it.first; // Return the first symbol that matches the value. + return true; + } + } + // value was not found in the map. + return false; +} + +size_t CEnum::get_member_count() { + return _members.size(); +} + +std::unordered_map::iterator CEnum::get_start_iterator() { + return _members.begin(); +} + +std::unordered_map::iterator CEnum::get_end_iterator() { + return _members.end(); +} + +/*******************************************************************************************/ + +WriteableCEnum::WriteableCEnum(std::string name) : _name(name), _currentValue(0) { +} + +WriteableCEnum::~WriteableCEnum() { +} + +void WriteableCEnum::add_symbol(std::string symbol) { + _members[_currentValue] = symbol; + _currentValue++; +} + +void WriteableCEnum::add_symbol(std::string symbol, int newValue) { + _currentValue = newValue; + add_symbol(symbol); +} + +std::string WriteableCEnum::to_string() { + std::stringstream ss; + + const char *indent = " "; + + int checkVal = 0; + + ss << "typedef enum " << _name << " { " << std::endl; + + // Iterate over the map + for (const auto& member : _members) { + ss << indent << member.second; + if(member.first != checkVal) { + checkVal = member.first; + ss << " = " << checkVal; + } + if (member != *std::prev(_members.end())) { + ss << ","; + } + ss << std::endl; + checkVal++; + } + + ss << "} " << _name << ";" << std::endl; + + return ss.str(); +} + +/*******************************************************************************************/ + +const std::string LOOKFOR_C_ENUM_REGEX = R"(\s*(typedef)?\s*(enum)\s*([A-Za-z_][A-Za-z0-9_]*)\s*\{[^}]*\}\s*([A-Za-z_][A-Za-z0-9_]*)?\s*;)"; + +// TODO: Implement these! +void CEnumsHelper::get_enums_from_code(CContext *context, const std::string &code, std::vector &out) { + std::vector matches; + RegexHelper::get_matches(code, LOOKFOR_C_ENUM_REGEX, matches); + + for(RegexMatch &match : matches) { + // Get the C code for this enum. + std::string enumCode = match.get_group(0).get_text(); + // Output new CEnum + out.push_back(new CEnum(context, enumCode)); + } +} + +void CEnumsHelper::load_enums_from_file(CContext *context, fs::path filepath) { + std::vector dummy; // Not actually used. + std::string cFileCode = FileHelper::read_text_file(filepath); + get_enums_from_code(context, cFileCode, dummy); +} + + \ No newline at end of file diff --git a/tools/dkr_assets_tool_src/helpers/c/cEnumsHelper.h b/tools/dkr_assets_tool_src/helpers/c/cEnumsHelper.h new file mode 100644 index 00000000..2206d9ab --- /dev/null +++ b/tools/dkr_assets_tool_src/helpers/c/cEnumsHelper.h @@ -0,0 +1,70 @@ +#pragma once + +#include "helpers/fileHelper.h" + +#include +#include +#include +#include + +class CContext; + +class CEnum { +public: + CEnum(CContext *context); // Empty enum + CEnum(CContext *context, const std::string &rawCode); // Parse from a enum string. + ~CEnum(); + + std::string get_name(); + + // Used in CContext. + void copy_members_to_map(std::unordered_map &inputMap); + + // Returns true if key was found in the _members map. + bool get_value_of_member(const std::string &memberKey, int &out); + + bool get_symbol_of_value(int value, std::string &outSymbol); + + size_t get_member_count(); + + std::unordered_map::iterator get_start_iterator(); + std::unordered_map::iterator get_end_iterator(); + +private: + CContext *_context; + std::unordered_map _members; + + std::string _name; + std::string _typedefName; + + // Modifies `enumValue` so that all symbols get converted to integers. For example: "VEHICLE_PLANE" should get replaced with "2". + void _evaluate_enum_symbols(std::string &enumValue); + int _evaluate_enum(std::string enumValue); + int _parse_enum_value(std::string &enumValue); +}; + +// Write-Only Enum class. Used in cHeader.h to create enums with. +class WriteableCEnum { +public: + WriteableCEnum(std::string name); + ~WriteableCEnum(); + + void add_symbol(std::string symbol); + void add_symbol(std::string symbol, int newValue); + + std::string to_string(); +private: + std::string _name; + int _currentValue; + std::map _members; // Note: Inverted from CEnum version. +}; + +/** + * Class that deals with reading / creating C enums. + */ +class CEnumsHelper { +public: + static void get_enums_from_code(CContext *context, const std::string &code, std::vector &out); + static void load_enums_from_file(CContext *context, fs::path filepath); +private: +}; diff --git a/tools/dkr_assets_tool_src/helpers/c/cHeader.cpp b/tools/dkr_assets_tool_src/helpers/c/cHeader.cpp new file mode 100644 index 00000000..a3f98ef5 --- /dev/null +++ b/tools/dkr_assets_tool_src/helpers/c/cHeader.cpp @@ -0,0 +1,34 @@ +#include "cHeader.h" + +#include "helpers/fileHelper.h" + +WritableCHeader::WritableCHeader() { +} + +WritableCHeader::~WritableCHeader() { +} + +void WritableCHeader::write_comment(const char *text) { + _out << "// " << text << std::endl; +} + +void WritableCHeader::write_header_comment(const char *text) { + _out << "/********** " << text << " **********/" << std::endl << std::endl; +} + +void WritableCHeader::write_newline() { + _out << std::endl; +} + +void WritableCHeader::write_raw_text(std::string text) { + _out << text; +} + +void WritableCHeader::write_raw_text_line(std::string text) { + _out << text << std::endl; +} + +void WritableCHeader::save(fs::path filepath) { + std::string headerText = _out.str(); + FileHelper::write_text_file(headerText, filepath, true); +} diff --git a/tools/dkr_assets_tool_src/helpers/c/cHeader.h b/tools/dkr_assets_tool_src/helpers/c/cHeader.h new file mode 100644 index 00000000..14a5744f --- /dev/null +++ b/tools/dkr_assets_tool_src/helpers/c/cHeader.h @@ -0,0 +1,27 @@ +#pragma once + +#include + +#include "helpers/fileHelper.h" +#include "helpers/c/cEnumsHelper.h" + +// Write-Only C Header generator class +class WritableCHeader { +public: + WritableCHeader(); + ~WritableCHeader(); + + void write_comment(const char *comment); + void write_header_comment(const char *comment); + void write_newline(); + + void write_raw_text(std::string text); + void write_raw_text_line(std::string text); + + void write_enum(CEnum *enumValue); + + void save(fs::path filepath); + +private: + std::stringstream _out; +}; diff --git a/tools/dkr_assets_tool_src/helpers/c/cStructGltfHelper.cpp b/tools/dkr_assets_tool_src/helpers/c/cStructGltfHelper.cpp new file mode 100644 index 00000000..52e92f79 --- /dev/null +++ b/tools/dkr_assets_tool_src/helpers/c/cStructGltfHelper.cpp @@ -0,0 +1,67 @@ +#include "cStructGltfHelper.h" + +void CStructGltfHelper::put_struct_entry_into_gltf_node_extra(CStructEntry *structMember, WriteableGltfFile &gltfFile, int gltfNode, uint8_t *bytes) { + CStructEntry::InternalType internalType = structMember->get_internal_type(); + + switch(internalType) { + case CStructEntry::InternalType::INTEGER: + { + int value = structMember->get_integer_from_data(bytes); + gltfFile.set_node_extra(gltfNode, structMember->name, value); + } + break; + case CStructEntry::InternalType::ARRAY_INTEGER: + { + std::vector values; + structMember->get_values_from_data_array(values, bytes); + tinygltf::Value::Array arrayOfValues; + for(int64_t val : values) { + arrayOfValues.push_back(tinygltf::Value((int)val)); + } + gltfFile.set_node_extra(gltfNode, structMember->name, arrayOfValues); + } + break; + case CStructEntry::InternalType::UNKNOWN: + break; // Do nothing (for now) + default: + DebugHelper::error("(CStructGltfHelper::put_struct_entry_into_gltf_node_extra) Type not implemented: ", internalType); + break; + } +} + +void CStructGltfHelper::put_gltf_node_extra_into_struct_entry(CStructEntry *structMember, GltfFile &gltfFile, int gltfNode, uint8_t *bytes) { + CStructEntry::InternalType internalType = structMember->get_internal_type(); + + switch(internalType) { + case CStructEntry::InternalType::INTEGER: + { + int value = gltfFile.get_node_extra(gltfNode, structMember->name, 0); + structMember->set_integer_to_data(bytes, value); + } + break; + case CStructEntry::InternalType::ARRAY_INTEGER: + { + tinygltf::Value::Array arrayOfValues = gltfFile.get_node_extra(gltfNode, structMember->name, {}); + std::vector values; + for(tinygltf::Value &val : arrayOfValues) { + values.push_back(val.GetNumberAsInt()); + } + structMember->set_values_to_data_array(values, bytes); + /* + std::vector values; + structMember->get_values_from_data_array(values, bytes); + tinygltf::Value::Array arrayOfValues; + for(int64_t val : values) { + arrayOfValues.push_back(tinygltf::Value((int)val)); + } + gltfFile.set_node_extra(gltfNode, structMember->name, arrayOfValues); + */ + } + break; + case CStructEntry::InternalType::UNKNOWN: + break; // Do nothing (for now) + default: + DebugHelper::error("(CStructGltfHelper::put_struct_entry_into_gltf_node_extra) Type not implemented: ", internalType); + break; + } +} \ No newline at end of file diff --git a/tools/dkr_assets_tool_src/helpers/c/cStructGltfHelper.h b/tools/dkr_assets_tool_src/helpers/c/cStructGltfHelper.h new file mode 100644 index 00000000..393b6cf8 --- /dev/null +++ b/tools/dkr_assets_tool_src/helpers/c/cStructGltfHelper.h @@ -0,0 +1,15 @@ +#include "helpers/c/cStructHelper.h" +#include "helpers/gltf/gltfHelper.h" + +// Class that helps with interacting with both cStructs and Gltf files + +class CStructGltfHelper { +public: + // struct entry -> gltf node extra + static void put_struct_entry_into_gltf_node_extra(CStructEntry *structMember, WriteableGltfFile &gltfFile, + int gltfNode, uint8_t *bytes); + + // gltf node extra -> struct entry + static void put_gltf_node_extra_into_struct_entry(CStructEntry *structMember, GltfFile &gltfFile, + int gltfNode, uint8_t *bytes); +}; diff --git a/tools/dkr_assets_tool_src/helpers/c/cStructHelper.cpp b/tools/dkr_assets_tool_src/helpers/c/cStructHelper.cpp new file mode 100644 index 00000000..9cd9dc6e --- /dev/null +++ b/tools/dkr_assets_tool_src/helpers/c/cStructHelper.cpp @@ -0,0 +1,577 @@ +#include "cStructHelper.h" + +#include +#include + +#include "helpers/debugHelper.h" +#include "helpers/regexHelper.h" +#include "helpers/stringHelper.h" +#include "helpers/fileHelper.h" + +#include "cContext.h" +#include "cTypes.h" + +CStructEntry::CStructEntry(CContext *context, CStruct *parent, std::string &type, std::string &pointer, std::string &name, + std::string &arrayBrackets) : type(type), pointer(pointer), name(name), arrayBrackets(arrayBrackets), + _context(context), _parent(parent) { + // Make sure the strings have no whitespace. Makes processing easier. + StringHelper::remove_all_whitespace(this->type); + StringHelper::remove_all_whitespace(this->pointer); + StringHelper::remove_all_whitespace(this->name); + StringHelper::remove_all_whitespace(this->arrayBrackets); + _calc_array_multiplier(); +} + +bool CStructEntry::is_pointer_to_type() { + return !pointer.empty(); +} + +bool CStructEntry::is_array() { + return !arrayBrackets.empty(); +} + +std::string CStructEntry::to_string() { + std::stringstream ss; + ss << type << " " << pointer << name << arrayBrackets << ";"; + return ss.str(); +} + +bool CStructEntry::is_type_trivial() { + if(is_pointer_to_type()) { + return true; // Pointers have fixed sizes, so yes. + } + if(innerStruct != nullptr) { + return innerStruct->is_trivial(); + } + return CTypes::is_standard_type(type); +} + +CStructEntry::InternalType CStructEntry::get_internal_type() { + if(_internalType == InternalType::NOT_SET) { + update_internal_type(); + } + return _internalType; +} + +void CStructEntry::update_internal_type() { + if(is_pointer_to_type()) { + _internalType = InternalType::POINTER; + } else if(innerStruct != nullptr) { + _internalType = InternalType::STRUCT_UNION; + } else if(CTypes::is_integer_type(type)) { + _internalType = InternalType::INTEGER; + } else if(CTypes::is_float_type(type)) { + _internalType = InternalType::FLOAT; + } else { + _internalType = InternalType::UNKNOWN; + return; + } + + if(is_array()) { + _internalType = (InternalType)((int)_internalType + (int)NUMBER_OF_VALUE_TYPES); + } +} + +bool CStructEntry::is_internal_type(const InternalType internalType) { + if(_internalType == InternalType::NOT_SET) { + update_internal_type(); + } + return _internalType == internalType; +} + +bool CStructEntry::is_integer_type() { + return is_internal_type(InternalType::INTEGER); +} + +bool CStructEntry::is_float_type() { + return is_internal_type(InternalType::FLOAT); +} + +bool CStructEntry::is_pointer_type() { + return is_internal_type(InternalType::POINTER); +} + +bool CStructEntry::is_array_of_integers() { + return is_internal_type(InternalType::ARRAY_INTEGER); +} + +bool CStructEntry::is_array_of_floats() { + return is_internal_type(InternalType::ARRAY_FLOAT); +} + +bool CStructEntry::is_array_of_pointers() { + return is_internal_type(InternalType::ARRAY_POINTER); +} + +bool CStructEntry::is_array_of_structs_or_unions() { + return is_internal_type(InternalType::ARRAY_STRUCT_UNION); +} + +size_t CStructEntry::get_array_multiplier() { + return _arrayMultiplier; +} + +size_t CStructEntry::get_byte_size() { + size_t outSize; + + if(is_pointer_to_type()) { + outSize = CTypes::size_of_pointer(); + } else if(innerStruct != nullptr) { + outSize = innerStruct->get_byte_size(); + } else { + outSize = CTypes::get_size_of_type(type); + if(outSize == 0) { + // Not a trivial type, try to get it from global context. + outSize = _context->get_size_of_element(type); + } + } + + DebugHelper::assert(outSize > 0, + "(CStructEntry::get_byte_size) Failed to calculate size for \"", name, "\" (type is \"", type, "\"). Is that type defined?"); + + return outSize * _arrayMultiplier; +} + +std::string CStructEntry::get_display_name() { + if(name.empty() && innerStruct != nullptr) { + std::stringstream ss; + ss << "(Anonymous " << (innerStruct->is_a_union() ? "Union" : "Struct") << ")"; + return ss.str(); + } + return name; +} + +int64_t CStructEntry::get_integer_from_data(uint8_t *data, bool isBigEndian) { + size_t numBytes = get_byte_size(); + + int64_t value = 0; + + for(size_t i = 0; i < numBytes; i++) { + size_t index = get_offset() + ((isBigEndian) ? numBytes - i - 1 : i); + value |= ((int64_t)data[index]) << (int64_t)(i * 8); + } + + return value; +} + +void CStructEntry::set_integer_to_data(uint8_t *data, int64_t value, bool isBigEndian) { + size_t numBytes = get_byte_size(); + + for(size_t i = 0; i < numBytes; i++) { + size_t index = get_offset() + ((isBigEndian) ? numBytes - i - 1 : i); + data[index] = value >> (int64_t)(i * 8); + } +} + +template +void CStructEntry::get_values_from_data_array(std::vector &out, uint8_t *data, bool isBigEndian) { + DebugHelper::assert(is_array(), "(CStructEntry::get_values_from_data_array) Entry ", name, " is not an array!"); + DebugHelper::assert(is_type_trivial(), "(CStructEntry::get_values_from_data_array) Entry ", name, " is not trivial, cannot get data!"); + + size_t totalSize = get_byte_size(); + size_t numEntries = _arrayMultiplier; + size_t numBytesPerEntry = totalSize / numEntries; + + out.resize(numEntries); + + for(size_t arrayEntry = 0; arrayEntry < numEntries; arrayEntry++) { + int64_t valueAsInteger = 0; + + // Get each byte of the value from the data array. + // Note: This must be done byte-by-byte, since N64 data is *usually* big endian. + for(size_t byteIndex = 0; byteIndex < numBytesPerEntry; byteIndex++) { + size_t index = get_offset() + (arrayEntry * numBytesPerEntry) + ((isBigEndian) ? numBytesPerEntry - byteIndex - 1 : byteIndex); + valueAsInteger |= ((int64_t)data[index]) << (int64_t)(byteIndex * 8); + } + + out[arrayEntry] = *(reinterpret_cast(&valueAsInteger)); // Convert value to proper type. + } +} + +template void CStructEntry::get_values_from_data_array(std::vector &out, uint8_t *data, bool isBigEndian); + +template +void CStructEntry::set_values_to_data_array(std::vector &in, uint8_t *data, bool isBigEndian) { + DebugHelper::assert(is_array(), "(CStructEntry::set_values_to_data_array) Entry ", name, " is not an array!"); + DebugHelper::assert(is_type_trivial(), "(CStructEntry::set_values_to_data_array) Entry ", name, " is not trivial, cannot get data!"); + + size_t totalSize = get_byte_size(); + size_t numEntries = _arrayMultiplier; + size_t numBytesPerEntry = totalSize / numEntries; + + for(size_t arrayEntry = 0; arrayEntry < numEntries; arrayEntry++) { + // Convert entry to int64_t + int64_t valueAsInteger = *(reinterpret_cast(&in[arrayEntry])); + + // Note: This must be done byte-by-byte, since N64 data is *usually* big endian. + for(size_t byteIndex = 0; byteIndex < numBytesPerEntry; byteIndex++) { + size_t index = get_offset() + (arrayEntry * numBytesPerEntry) + ((isBigEndian) ? numBytesPerEntry - byteIndex - 1 : byteIndex); + data[index] = valueAsInteger >> (int64_t)(byteIndex * 8); + } + } +} + +template void CStructEntry::set_values_to_data_array(std::vector &in, uint8_t *data, bool isBigEndian); + +int CStructEntry::get_offset() { + if(_offset == -1) { + _parent->calculate_offsets(); + } + DebugHelper::assert(_offset >= 0, "(CStructEntry::get_offset) Could not calculate offset for ", name); + return _offset; +} + +void CStructEntry::set_offset(int newOffset) { + _offset = newOffset; +} + +const std::string C_STRUCT_ENTRY_REGEX_ARRAY_BRACKET_NUMBERS = R"(\[\s*([^\]\s]+)\s*\])"; + +void CStructEntry::_calc_array_multiplier() { + _arrayMultiplier = 1; + if(!is_array()) { + return; + } + std::vector matches; + RegexHelper::get_matches(arrayBrackets, C_STRUCT_ENTRY_REGEX_ARRAY_BRACKET_NUMBERS, matches); + + DebugHelper::assert(matches.size() > 0, "(CStructEntry::_calc_array_multiplier) Brackets are invalid: \"", arrayBrackets, "\""); + + for(RegexMatch &match : matches) { + std::string numberStr = match.get_group(1).get_text(); + + int numberValue = std::stoi(numberStr, nullptr, 0); + + DebugHelper::assert(numberValue > 0, "(CStructEntry::_calc_array_multiplier) Value cannot be less than 1. \"", numberStr, "\""); + + _arrayMultiplier *= numberValue; + } +} + +CStruct::CStruct(CContext *context) : _context(context) { +} + +CStruct::~CStruct() { + // Should be fine to call even if the struct is already not registered. + _context->deregister_struct(_name); + + for(CStructEntry *entry : _entries) { + delete entry; + } +} + +//std::string C_STRUCT_NAME_REGEX = R"(struct\s+([A-Za-z_][A-Za-z0-9_]*)\s+\{)"; + +const std::string C_STRUCT_MEMBERS_REGEX = R"(([A-Za-z_][A-Za-z0-9_]*)[ \t]+([0-9A-Za-z_*\[\], \t]+);)"; +const std::string C_STRUCT_MEMBERS_ENTRY_REGEX = R"(^([*][* ]*)?([a-zA-Z_][a-zA-Z_0-9]*)?(?:\s*(\[.*\]))?)"; +const std::string C_STRUCT_DEFINITION = R"((typedef)?\s*(struct|union)\s*([A-Za-z_][A-Za-z0-9_]*)?\s*\{((?:.|\n)*)}\s*([A-Za-z_][A-Za-z0-9_]*)?\s*;?)"; +const std::string C_STRUCT_RANGE_CHECK = R"(((?:.|\n)*?)(((struct|union)\s*([A-Za-z_][A-Za-z0-9_]*)?\s*))?(;|\{))"; + +struct CStructMemberParse { + int start; // Offset to the start of the text. + int end; // Offset to the end of the text. + bool isStruct; // type is a struct/union + int structStart; + int structEnd; + + void reset() { + start = -1; + end = -1; + isStruct = false; + structStart = -1; + structEnd = -1; + } + + std::string to_string() { + std::stringstream ss; + + ss << "[CStructMemberParse] " + << start << "," << end; + + if(isStruct) { + ss << "(" << structStart << "," << structEnd << ")"; + } + + return ss.str(); + } + + std::string get_substring(const std::string &structCode) { + size_t length = end - start; + return structCode.substr(start, length); + } + + std::string get_struct_substring(const std::string &structCode) { + size_t length = structEnd - structStart; + return structCode.substr(structStart, length); + } +}; + +const std::string C_STRUCT_END_CHAR = R"(^((?:.|\n)*?([;{])))"; + +int get_next_member(const std::string &structCode, int offsetInCode, CStructMemberParse &out) { + + // Make sure previous information doesn't get reused. + out.reset(); + + // We need to first check if we are dealing with a struct/union or not. + // To do that, I look to see if a ';' or a '{' appears first. + int endCharOffset; + char endChar; + RegexMatch *match = RegexHelper::get_first_match(structCode, C_STRUCT_END_CHAR, offsetInCode); + + if(match == nullptr) { + //DebugHelper::info("(get_next_member) match was null!"); + return -1; + } + + endCharOffset = match->get_group(2).get_offset(); + + if(endCharOffset == -1) { + //DebugHelper::info("(get_next_member) endChar was not found!"); + delete match; + return -1; + } + + endCharOffset += offsetInCode; + + endChar = match->get_group(2).get_text()[0]; + + if(endChar == ';') { + // Not a struct type, so just return the start/end points. + out.start = offsetInCode; + out.end = endCharOffset + 1; + delete match; + return out.end; + } + + DebugHelper::assert(endChar == '{', "(get_next_member) endChar not a opening brace!"); + + // endChar is a '{' + out.isStruct = true; + out.structStart = offsetInCode; + + int closeBraceOffset = StringHelper::find_closing_brace(structCode, endCharOffset); + + DebugHelper::assert(structCode[closeBraceOffset] == '}', "(get_next_member) Invalid closing brace!"); + + out.structEnd = closeBraceOffset + 1; + + offsetInCode = out.structEnd; + + // Now that the struct was found, get the rest of the member. + //bool success = get_next_member_end_character(structCode, offsetInCode, endCharOffset, endChar, false); + //DebugHelper::assert(success, "(get_next_member) Couldn't find an ending colon for the struct! At pos ", offsetInCode); + + delete match; + + endCharOffset = structCode.find_first_of(';', offsetInCode); + + out.start = offsetInCode; + out.end = endCharOffset + 1; + + return out.end; +} + +CStruct::CStruct(CContext *context, const std::string &rawCode) : _context(context) { + RegexMatch *structDefMatch = RegexHelper::get_first_match(rawCode, C_STRUCT_DEFINITION); + DebugHelper::assert(structDefMatch != nullptr, "rawCode \"", rawCode, "\" is not valid."); + + std::string structOrUnion = structDefMatch->get_group(2).get_text(); + _isUnion = (structOrUnion == "union"); + _name = structDefMatch->get_group(3).get_text(); + + std::string typedefGroup = structDefMatch->get_group(1).get_text(); + if(typedefGroup == "typedef") { + _typedefName = structDefMatch->get_group(5).get_text(); + } + + const std::string structCode = structDefMatch->get_group(4).get_text(); + + int textOffset = 0; + int structCodeEnd = (int)structCode.length(); + + CStructMemberParse parseInfo; + while (textOffset < structCodeEnd) { + int newOffset = get_next_member(structCode, textOffset, parseInfo); + //DebugHelper::info("newOffset = ", newOffset, ", parsed = ", parseInfo.to_string()); + + if(newOffset <= textOffset) { + break; + } + + CStruct *innerStruct = nullptr; + + std::string memberCode = parseInfo.get_substring(structCode); + //DebugHelper::info("memberCode = ", memberCode); + + std::string type; + std::string rest; + + if(parseInfo.isStruct) { + std::string innerStructCode = parseInfo.get_struct_substring(structCode); + innerStruct = new CStruct(_context, innerStructCode); + + type = innerStruct->is_a_union() ? "union" : "struct"; + rest = memberCode; + } else { + // Regular non-struct member. + RegexMatch *match = RegexHelper::get_first_match(memberCode, C_STRUCT_MEMBERS_REGEX); + + DebugHelper::assert(match != nullptr, "memberCode \"", memberCode, "\" is not valid."); + + type = match->get_group(1).get_text(); + rest = match->get_group(2).get_text(); + + delete match; // done with match. + } + + std::vector entries; + StringHelper::split_and_trim(rest, ',', entries); + + for(std::string &entry : entries) { + + std::string pointers; + std::string name; + std::string arrayBrackets; + + if(entry != ";") { + RegexMatch *match = RegexHelper::get_first_match(entry, C_STRUCT_MEMBERS_ENTRY_REGEX); + DebugHelper::assert(match != nullptr, "entry \"", entry, "\" is not valid."); + pointers = match->get_group(1).get_text(); // The asterisks + name = match->get_group(2).get_text(); // Name of the variable. + arrayBrackets = match->get_group(3).get_text(); // If this entry is an array, then get the brackets. + delete match; // done with match. + } + + _entries.push_back(new CStructEntry(_context, this, type, pointers, name, arrayBrackets)); + + if(parseInfo.isStruct) { + _entries.back()->innerStruct = innerStruct; + } + + } + + textOffset = newOffset; + } + + _calc_trivialness(); + _context->register_struct(this); +} + +std::string CStruct::get_name() { + return _name; +} + +bool CStruct::is_a_union() { + return _isUnion; +} + +bool CStruct::is_anonymous() { + return _typedefName.empty(); +} + +std::string CStruct::to_string() { + std::stringstream ss; + if(_name.empty()) { + ss << "struct {\n"; + } else { + ss << "typedef struct " << _name << " {\n"; + } + for(CStructEntry *entry : _entries) { + ss << " " << entry->to_string() << "\n"; + } + if(_name.empty()) { + ss << "}" << ";"; + } else { + ss << "} " << _name << ";"; + } + return ss.str(); +} + +CStructEntry *CStruct::get_entry(size_t entryIndex) { + DebugHelper::assert(entryIndex < _entries.size(), "(CStruct::get_entry) Out of bounds index ", entryIndex, ". Struct only has ", _entries.size(), " entries."); + return _entries[entryIndex]; +} + +size_t CStruct::entry_count() { + return _entries.size(); +} + +size_t CStruct::get_byte_size() { + size_t outSize = 0; + + if(_isUnion) { + for(CStructEntry *entry : _entries) { + size_t memberSize = entry->get_byte_size(); + // Get the maximum size. + outSize = (memberSize > outSize) ? memberSize : outSize; + } + } else { + for(CStructEntry *entry : _entries) { + outSize += entry->get_byte_size(); + } + } + + return outSize; +} + +bool CStruct::is_trivial() { + return _isTrivial; +} + +// This is only run if needed. +void CStruct::calculate_offsets(int currentOffset) { + for(CStructEntry *entry : _entries) { + entry->set_offset(currentOffset); + if(entry->innerStruct != nullptr) { + entry->innerStruct->calculate_offsets(currentOffset); + } + currentOffset += entry->get_byte_size(); + } +} + +void CStruct::_calc_trivialness() { + _isTrivial = true; + for(CStructEntry *entry : _entries) { + if(!entry->is_type_trivial()) { + _isTrivial = false; + return; + } + } +} + +const std::string LOOKFOR_C_STRUCT_REGEX = R"(\s*(typedef)?\s*(struct|union)\s*([A-Za-z_][A-Za-z0-9_]*)\s*\{)"; + +void CStructHelper::get_structs_from_code(CContext *context, const std::string &code, std::vector &out) { + size_t codeLength = code.length(); + size_t curPos = 0; + RegexMatch *currentMatch = RegexHelper::get_first_match(code, LOOKFOR_C_STRUCT_REGEX, curPos); + + while((currentMatch != nullptr) && (curPos < codeLength)) { + // Get start & end points of the struct. + size_t structStart = curPos + currentMatch->get_group(0).get_offset(); + size_t structEnd = StringHelper::find_closing_brace(code, structStart) + 1; + + // Extract the struct from the code file. + std::string structCode = code.substr(structStart, structEnd - structStart); + + // Create struct & add it to the vector. + out.push_back(new CStruct(context, structCode)); + + // Find next struct + curPos = structEnd; + delete currentMatch; + currentMatch = RegexHelper::get_first_match(code, LOOKFOR_C_STRUCT_REGEX, curPos); + } + + if(currentMatch != nullptr) { + delete currentMatch; + } + +} + +void CStructHelper::load_structs_from_file(CContext *context, fs::path filepath) { + std::vector dummy; // Not actually used. + std::string cFileCode = FileHelper::read_text_file(filepath); + get_structs_from_code(context, cFileCode, dummy); +} diff --git a/tools/dkr_assets_tool_src/helpers/c/cStructHelper.h b/tools/dkr_assets_tool_src/helpers/c/cStructHelper.h new file mode 100644 index 00000000..76b1fe25 --- /dev/null +++ b/tools/dkr_assets_tool_src/helpers/c/cStructHelper.h @@ -0,0 +1,132 @@ +#pragma once + +#include "helpers/fileHelper.h" + +#include +#include +#include + +class CContext; +class CStruct; + +// Represents an entry of a C structure. +struct CStructEntry { + + enum InternalType { + // default value + NOT_SET, + // Single value types + INTEGER, + POINTER, + FLOAT, + STRUCT_UNION, + // Array types + ARRAY_INTEGER, + ARRAY_POINTER, + ARRAY_FLOAT, + ARRAY_STRUCT_UNION, + // Not any recognized value. + UNKNOWN, + NUMBER_OF_VALUE_TYPES = 4 + }; + + std::string type; + std::string pointer; + std::string name; + std::string arrayBrackets; + + CStruct *innerStruct = nullptr; // Only used in struct/union type. + + CStructEntry(CContext *context, CStruct *parent, std::string &type, std::string &pointer, std::string &name, + std::string &arrayBrackets); + bool is_pointer_to_type(); + bool is_array(); + + std::string to_string(); + + bool is_type_trivial(); + + InternalType get_internal_type(); + void update_internal_type(); + bool is_internal_type(const InternalType internalType); + bool is_integer_type(); + bool is_float_type(); + bool is_pointer_type(); // Checks `_internalType` instead of `pointer` + bool is_array_of_integers(); + bool is_array_of_floats(); + bool is_array_of_pointers(); + bool is_array_of_structs_or_unions(); + + size_t get_array_multiplier(); + size_t get_byte_size(); + + std::string get_display_name(); + + int64_t get_integer_from_data(uint8_t *data, bool isBigEndian=true); + void set_integer_to_data(uint8_t *data, int64_t value, bool isBigEndian=true); + + template + void get_values_from_data_array(std::vector &out, uint8_t *data, bool isBigEndian=true); + + template + void set_values_to_data_array(std::vector &in, uint8_t *data, bool isBigEndian=true); + + int get_offset(); + void set_offset(int newOffset); // Note: Should only be called by the parent cstruct. + +private: + CContext *_context; + CStruct *_parent; + InternalType _internalType = InternalType::NOT_SET; + int _offset = -1; // Is only calculated if get_offset is called. + + size_t _arrayMultiplier; + + void _calc_array_multiplier(); + +}; + +// Class that represents a structure in a C file. +class CStruct { +public: + CStruct(CContext *context); // Empty struct + CStruct(CContext *context, const std::string &rawCode); // Parse from a struct string. + ~CStruct(); + + std::string get_name(); + bool is_a_union(); + bool is_anonymous(); + + std::string to_string(); + + CStructEntry *get_entry(size_t entryIndex); + size_t entry_count(); + + size_t get_byte_size(); + bool is_trivial(); + + void calculate_offsets(int currentOffset = 0); + +private: + CContext *_context; + + std::vector _entries; + std::string _name = ""; + std::string _typedefName = ""; + bool _isUnion = false; + + // "Trivial" meaning that the byte size of the struct can be easily calculated. + bool _isTrivial = false; + + void _calc_trivialness(); +}; + +/** + * Class that deals with reading / creating C structs. + */ +class CStructHelper { +public: + //static void get_struct_from_c_file(const std::string &filepath, const std::string &structName, CStruct &out); + static void get_structs_from_code(CContext *context, const std::string &code, std::vector &out); + static void load_structs_from_file(CContext *context, fs::path filepath); +}; diff --git a/tools/dkr_assets_tool_src/helpers/c/cTypes.cpp b/tools/dkr_assets_tool_src/helpers/c/cTypes.cpp new file mode 100644 index 00000000..849db30b --- /dev/null +++ b/tools/dkr_assets_tool_src/helpers/c/cTypes.cpp @@ -0,0 +1,90 @@ +#include "cTypes.h" + +#include +#include "helpers/debugHelper.h" + +enum CTypeCategory { + CTYPE_INTEGER, + CTYPE_FLOAT +}; + +struct CTypeInfo { + size_t size; + CTypeCategory category; +}; + +// TODO: Is there a better way to do this? +// Note: sizes according to N64 hardware. +std::unordered_map typeInfos = { + // 1 byte types + { "char", {1, CTYPE_INTEGER}}, + { "signed char", {1, CTYPE_INTEGER}}, + { "unsigned char", {1, CTYPE_INTEGER}}, + { "s8", {1, CTYPE_INTEGER}}, + { "u8", {1, CTYPE_INTEGER}}, + // 2 byte types + { "short", {2, CTYPE_INTEGER}}, + { "signed short", {2, CTYPE_INTEGER}}, + { "unsigned short", {2, CTYPE_INTEGER}}, + { "short int", {2, CTYPE_INTEGER}}, + { "signed short int", {2, CTYPE_INTEGER}}, + { "unsigned short int", {2, CTYPE_INTEGER}}, + { "s16", {2, CTYPE_INTEGER}}, + { "u16", {2, CTYPE_INTEGER}}, + // 4 byte types + { "int", {4, CTYPE_INTEGER}}, + { "signed int", {4, CTYPE_INTEGER}}, + { "unsigned int", {4, CTYPE_INTEGER}}, + { "long", {4, CTYPE_INTEGER}}, // long is 32-bits on N64 + { "signed long", {4, CTYPE_INTEGER}}, + { "unsigned long", {4, CTYPE_INTEGER}}, + { "s32", {4, CTYPE_INTEGER}}, + { "u32", {4, CTYPE_INTEGER}}, + { "float", {4, CTYPE_FLOAT}}, + { "f32", {4, CTYPE_FLOAT}}, + // 8 byte types + { "long long int", {8, CTYPE_INTEGER}}, + { "signed long long int", {8, CTYPE_INTEGER}}, + { "unsigned long long int", {8, CTYPE_INTEGER}}, + { "s64", {8, CTYPE_INTEGER}}, + { "u64", {8, CTYPE_INTEGER}}, + { "double", {8, CTYPE_FLOAT}}, + { "f64", {8, CTYPE_FLOAT}}, +}; + +bool CTypes::is_standard_type(const std::string &typeName) { + if(typeName.empty()) { + return false; // Empty string is no type at all. + } + auto found = typeInfos.find(typeName); + if(found == typeInfos.end()) { + return false; // Invalid type + } + return true; +} + +size_t CTypes::get_size_of_type(const std::string &typeName) { + if(!CTypes::is_standard_type(typeName)) { + return 0; + } + return typeInfos[typeName].size; +} + +bool CTypes::is_integer_type(const std::string &typeName) { + if(!CTypes::is_standard_type(typeName)) { + return false; + } + return typeInfos[typeName].category == CTypeCategory::CTYPE_INTEGER; +} + +bool CTypes::is_float_type(const std::string &typeName) { + if(!CTypes::is_standard_type(typeName)) { + return false; + } + return typeInfos[typeName].category == CTypeCategory::CTYPE_FLOAT; +} + +size_t CTypes::size_of_pointer() { + return 4; // Note: Assuming N64 platform. +} + diff --git a/tools/dkr_assets_tool_src/helpers/c/cTypes.h b/tools/dkr_assets_tool_src/helpers/c/cTypes.h new file mode 100644 index 00000000..ce7160ad --- /dev/null +++ b/tools/dkr_assets_tool_src/helpers/c/cTypes.h @@ -0,0 +1,19 @@ +#pragma once + +#include +#include + +// Class that represents standard c types. +class CTypes { +public: + static bool is_standard_type(const std::string &typeName); + + static size_t get_size_of_type(const std::string &typeName); + + static bool is_integer_type(const std::string &typeName); + static bool is_float_type(const std::string &typeName); + + static size_t size_of_pointer(); + + static bool does_type_have_an_entry(const std::string &typeName); +}; \ No newline at end of file diff --git a/tools/dkr_assets_tool_src/helpers/dataHelper.cpp b/tools/dkr_assets_tool_src/helpers/dataHelper.cpp new file mode 100644 index 00000000..e3ba7326 --- /dev/null +++ b/tools/dkr_assets_tool_src/helpers/dataHelper.cpp @@ -0,0 +1,25 @@ +#include "dataHelper.h" + +#define ALIGN_N(val, N) ((val + (N - 1)) & (~(N - 1))) + +// ALigns length to 16-bytes. +size_t DataHelper::align16(size_t length) { + return ALIGN_N(length, 16); +} + +// ALigns length to 8-bytes. +size_t DataHelper::align8(size_t length) { + return ALIGN_N(length, 8); +} + +// ALigns length to 4-bytes. +size_t DataHelper::align4(size_t length) { + return ALIGN_N(length, 4); +} + +bool DataHelper::is_power_of_two(uint32_t value) { + if(value == 0) { + return false; + } + return (value & (value - 1)) == 0; +} diff --git a/tools/dkr_assets_tool_src/helpers/dataHelper.h b/tools/dkr_assets_tool_src/helpers/dataHelper.h new file mode 100644 index 00000000..681fb300 --- /dev/null +++ b/tools/dkr_assets_tool_src/helpers/dataHelper.h @@ -0,0 +1,57 @@ +#pragma once + +#include +#include +#include +#include + +/** + * Singleton class that has useful functions for helping with data. + */ +class DataHelper { +public: + // Probably not needed? + static DataHelper& get() { + static DataHelper instance; + return instance; + } + + // ALigns length to 16-bytes. + static size_t align16(size_t length); + + // ALigns length to 8-bytes. + static size_t align8(size_t length); + + // ALigns length to 4-bytes. + static size_t align4(size_t length); + + static bool is_power_of_two(uint32_t value); + + // Returns -1 if element was not found. + template + static int vector_index_of(const std::vector &vec, T element) { + auto it = std::find(vec.begin(), vec.end(), element); // Iterator for the element. + + if(it == vec.end()) { + // Not found. + return -1; + } + + // Element was found, get index into the array. + return it - vec.begin(); + } + + // Returns -1 if element was not found. + template + static bool vector_has(const std::vector &vec, T element) { + auto it = std::find(vec.begin(), vec.end(), element); // Iterator for the element. + + if(it == vec.end()) { + // Not found. + return false; + } + + // Element was found, get index into the array. + return true; + } +}; diff --git a/tools/dkr_assets_tool_src/helpers/debugHelper.cpp b/tools/dkr_assets_tool_src/helpers/debugHelper.cpp new file mode 100644 index 00000000..3eff8d8b --- /dev/null +++ b/tools/dkr_assets_tool_src/helpers/debugHelper.cpp @@ -0,0 +1,41 @@ +#include "debugHelper.h" + +void DebugHelper::set_verbose(bool isVerbose) { + _verbose = isVerbose; +} + +bool DebugHelper::is_verbose() { + return _verbose; +} + +void DebugHelper::set_asserts(bool useAsserts) { + _assertsEnabled = useAsserts; +} +bool DebugHelper::using_asserts() { + return _assertsEnabled; +} + +DebugHelper::DebugTimer::DebugTimer() : + m_beg(clock_::now()) { +} + +void DebugHelper::DebugTimer::reset() { + m_beg = clock_::now(); +} + +std::string DebugHelper::DebugTimer::elapsed() { + std::chrono::time_point m_end = clock_::now(); + + const char *label = GREEN_TEXT "us" RESET_TEXT; + + double time = std::chrono::duration_cast(m_end - m_beg).count(); + if(time > 1000.0) { + time /= 1000.0; + label = CYAN_TEXT "ms" RESET_TEXT; + if(time > 1000.0) { + time /= 1000.0; + label = MAGENTA_TEXT "seconds" RESET_TEXT; + } + } + return std::to_string(time).substr(0, std::to_string(time).find(".") + 3) + " " + label; +} diff --git a/tools/dkr_assets_tool_src/helpers/debugHelper.h b/tools/dkr_assets_tool_src/helpers/debugHelper.h new file mode 100644 index 00000000..6bee3b0c --- /dev/null +++ b/tools/dkr_assets_tool_src/helpers/debugHelper.h @@ -0,0 +1,152 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +// Terminal colors +#define RED_TEXT "\033[1;31m" +#define GREEN_TEXT "\033[1;32m" +#define YELLOW_TEXT "\033[1;33m" +#define BLUE_TEXT "\033[1;34m" +#define MAGENTA_TEXT "\033[1;35m" +#define CYAN_TEXT "\033[1;36m" + +#define RESET_TEXT "\033[0m" + + + +/** + * Singleton class that deals with info / logging / errors + */ +class DebugHelper { +public: + // From https://gist.github.com/tzutalin/fd0340a93bb8d998abb9 + class DebugTimer { + public: + DebugTimer(); + void reset(); + std::string elapsed(); + private: + typedef std::chrono::high_resolution_clock clock_; + typedef std::chrono::duration> second_; + std::chrono::time_point m_beg; + }; + + static DebugHelper& get() { + static DebugHelper instance; + return instance; + } + + template + static void info(Args... args) { + std::stringstream ss; + ss << CYAN_TEXT << "INFO: " << RESET_TEXT; + (ss << ... << args); + ss << std::endl; + std::cout << ss.str(); + } + + template + static void info_custom(const char *type, const char *color, Args... args) { + std::stringstream ss; + ss << color << type << ": " << RESET_TEXT; + (ss << ... << args); + ss << std::endl; + std::cout << ss.str(); + } + + template + static void info_verbose(Args... args) { + if(!DebugHelper::get().is_verbose()) { + return; + } + info(args...); + } + + template + static void warn(Args... args) { + std::stringstream ss; + ss << YELLOW_TEXT << "WARNING: "; + (ss << ... << args); + ss << RESET_TEXT << std::endl; + std::cout << ss.str(); + } + + template + static void error(Args... args) { + std::stringstream ss; + ss << RED_TEXT << "ERROR: "; + (ss << ... << args); + ss << RESET_TEXT << std::endl; + std::cout << ss.str(); + throw 1; + } + + template + static void error_no_throw(Args... args) { + std::stringstream ss; + ss << RED_TEXT << "ERROR: "; + (ss << ... << args); + ss << RESET_TEXT << std::endl; + std::cout << ss.str(); + } + + template + static void assert(bool condition, Args... args) { + if(!DebugHelper::get().using_asserts()) return; + if(!condition) { + DebugHelper::error(args...); + } + } + + // For use in files that have included. + template + static void assert_(bool condition, Args... args) { + assert(condition, args...); + } + + template + static std::string vector_to_string(std::vector vec, int maxLength=-1) { + std::stringstream ss; + size_t len = (maxLength < 1) ? vec.size() : maxLength; + + ss << "["; + for(size_t i = 0; i < len; i++) { + ss << vec[i]; + if(i < len - 1) { + ss << ", "; + } + } + ss << "]"; + + return ss.str(); + } + + static std::string bytes_to_hex_string(uint8_t *data, uint32_t dataLength) { + std::stringstream ss; + ss << std::hex << std::setfill('0'); + for(uint32_t i = 0; i < dataLength; ++i) + ss << std::setw(2) << static_cast(data[i]) << " "; + return ss.str(); + } + + static std::string to_hex(uint32_t val) { + std::stringstream ss; + ss << "0x" << std::uppercase << std::hex << std::setw(8) << std::setfill('0') << val << std::nouppercase << std::dec; + return ss.str(); + } + + void set_verbose(bool isVerbose = true); + bool is_verbose(); + void set_asserts(bool useAsserts = true); + bool using_asserts(); +private: + bool _verbose = false; + bool _assertsEnabled = false; + int timerChannel = 0; +}; diff --git a/tools/dkr_assets_tool_src/helpers/fileHelper.cpp b/tools/dkr_assets_tool_src/helpers/fileHelper.cpp new file mode 100644 index 00000000..bd2203a1 --- /dev/null +++ b/tools/dkr_assets_tool_src/helpers/fileHelper.cpp @@ -0,0 +1,357 @@ +#include "fileHelper.h" + +#include +#include +#include +#include + +#include "helpers/debugHelper.h" + +std::vector FileHelper::read_binary_file(const fs::path &filename) { + DebugHelper::assert(path_exists(filename), "(FileHelper::read_binary_file) Path ", filename, " does not exist!"); + std::ifstream is; + is.open(filename.c_str(), std::ios::binary); + is.seekg(0, std::ios::end); + size_t filesize = is.tellg(); + is.seekg(0, std::ios::beg); + std::vector bytes(filesize); + is.read((char *)bytes.data(), filesize); + is.close(); + return bytes; +} + +std::string FileHelper::read_text_file(const fs::path &filename, size_t maxSize) { + DebugHelper::assert(path_exists(filename), "(FileHelper::read_text_file) Path ", filename, " does not exist!"); + std::ifstream t(filename); + t.seekg(0, std::ios::end); + size_t size = std::min((size_t)t.tellg(), maxSize); + std::string buffer(size, ' '); + t.seekg(0); + t.read(&buffer[0], size); + return buffer; +} + +void FileHelper::write_text_file(const std::string &text, const fs::path &filepath, bool ensurePathExists) { + if(ensurePathExists) { + write_folder_if_it_does_not_exist(filepath); + } + std::ofstream myfile; + myfile.open(filepath); + myfile << text; + myfile.close(); +} + +void FileHelper::write_folder_if_it_does_not_exist(const fs::path &path) { + fs::path dirPath = path; + if (dirPath.has_filename()) { + dirPath = dirPath.parent_path(); + } + if(dirPath.empty()) { + return; + } + if (!fs::exists(dirPath)) { + fs::create_directories(dirPath); + } +} + +const char *EMPTY_DATA = ""; + +void FileHelper::write_empty_file(const fs::path &filepath, bool ensurePathExists) { + write_binary_file(EMPTY_DATA, 0, filepath, ensurePathExists); +} + +void FileHelper::write_binary_file(std::vector &data, const fs::path &filepath, bool ensurePathExists) { + write_binary_file((const char*)&data[0], data.size(), filepath, ensurePathExists); +} + +void FileHelper::write_binary_file(uint8_t *data, size_t dataSize, const fs::path &filepath, bool ensurePathExists) { + write_binary_file((const char*)data, dataSize, filepath, ensurePathExists); +} + +void FileHelper::write_binary_file(const char *data, size_t dataSize, const fs::path &filepath, bool ensurePathExists) { + if(ensurePathExists) { + write_folder_if_it_does_not_exist(filepath); + } + std::ofstream wf(filepath.c_str(), std::ios::out | std::ios::binary); + wf.write(data, dataSize); + wf.close(); +} + +bool FileHelper::path_exists(const fs::path &path) { + return fs::exists(path); +} + +bool FileHelper::is_zip_file(const fs::path &path) { + if(!FileHelper::path_exists(path) || fs::is_directory(path)) { + return false; + } + + try { + std::ifstream data(path, std::ios::binary); + char buffer[4]; + data.read(buffer, 4); + data.close(); + uint32_t signature = *(reinterpret_cast(buffer)); + return signature == 0x04034B50 || // Little Endian + signature == 0x504B0304; // Big Endian + } catch (...) { + // TODO: Check for the actual error. + } + + return false; +} + +std::vector FileHelper::get_files_from_directory(const fs::path &dirPath, bool recursive) { + std::vector out; + try { + if(recursive) { + for (const auto &file : fs::recursive_directory_iterator(dirPath)) { + if(!file.is_directory()) { + out.push_back(file); + } + } + } else { + for (const auto &file : fs::directory_iterator(dirPath)) { + if(!file.is_directory()) { + out.push_back(file); + } + } + } + } catch(fs::filesystem_error const&) { + DebugHelper::error("Could not find the directory ", dirPath); + } + return out; +} + +std::vector FileHelper::get_files_from_directory_with_extension(const fs::path &dirPath, std::string extension, bool recursive) { + std::vector out; + try { + if(recursive) { + for (const auto &file : fs::recursive_directory_iterator(dirPath)) { + if(StringHelper::ends_with(file.path(), extension)) { + if(!file.is_directory()) { + out.push_back(file); + } + } + } + } else { + for (const auto &file : fs::directory_iterator(dirPath)) { + if(StringHelper::ends_with(file.path(), extension)) { + if(!file.is_directory()) { + out.push_back(file); + } + } + } + } + } catch(fs::filesystem_error const&) { + DebugHelper::error("Could not find the directory ", dirPath); + } + return out; +} + +std::vector FileHelper::get_files_from_directory_excluding_extension(const fs::path &dirPath, std::string extension, bool recursive) { + std::vector out; + try { + if(recursive) { + for (const auto &file : fs::recursive_directory_iterator(dirPath)) { + if(!StringHelper::ends_with(file.path(), extension)) { + if(!file.is_directory()) { + out.push_back(file); + } + } + } + } else { + for (const auto &file : fs::directory_iterator(dirPath)) { + if(!StringHelper::ends_with(file.path(), extension)) { + if(!file.is_directory()) { + out.push_back(file); + } + } + } + } + } catch(fs::filesystem_error const&) { + DebugHelper::error("Could not find the directory ", dirPath); + } + return out; +} + +std::vector FileHelper::get_folders_from_directory(const fs::path &dirPath, bool recursive) { + std::vector out; + try { + if(recursive) { + for (const auto &file : fs::recursive_directory_iterator(dirPath)) { + if(file.is_directory()) { + out.push_back(file); + } + } + } else { + for (const auto &file : fs::directory_iterator(dirPath)) { + if(file.is_directory()) { + out.push_back(file); + } + } + } + } catch(fs::filesystem_error const&) { + DebugHelper::error("Could not find the directory ", dirPath); + } + return out; +} + +void FileHelper::append_files_from_directory(const fs::path &dirPath, std::vector &out, bool recursive) { + try { + if(recursive) { + for (const auto &file : fs::recursive_directory_iterator(dirPath)) { + if(!file.is_directory()) { + out.push_back(file); + } + } + } else { + for (const auto &file : fs::directory_iterator(dirPath)) { + if(!file.is_directory()) { + out.push_back(file); + } + } + } + } catch(fs::filesystem_error const&) { + DebugHelper::error("Could not find the directory ", dirPath); + } +} + +void FileHelper::append_files_from_directory_relative(const fs::path &dirPath, std::vector &out, bool recursive) { + try { + if(recursive) { + for (const auto &file : fs::recursive_directory_iterator(dirPath)) { + if(!file.is_directory()) { + fs::path p = std::filesystem::relative(file, dirPath); + if(!p.empty()) { + out.push_back(p); + } + } + } + } else { + for (const auto &file : fs::directory_iterator(dirPath)) { + if(!file.is_directory()) { + fs::path p = std::filesystem::relative(file, dirPath); + if(!p.empty()) { + out.push_back(p); + } + } + } + } + } catch(fs::filesystem_error const&) { + DebugHelper::error("Could not find the directory ", dirPath); + } +} + +void FileHelper::append_files_from_directory_with_extension(const fs::path &dirPath, std::string extension, std::vector &out, bool recursive) { + try { + if(recursive) { + for (const auto &file : fs::recursive_directory_iterator(dirPath)) { + if(StringHelper::ends_with(file.path(), extension)) { + if(!file.is_directory()) { + out.push_back(file); + } + } + } + } else { + for (const auto &file : fs::directory_iterator(dirPath)) { + if(StringHelper::ends_with(file.path(), extension)) { + if(!file.is_directory()) { + out.push_back(file); + } + } + } + } + } catch(fs::filesystem_error const&) { + DebugHelper::error("Could not find the directory ", dirPath); + } +} + +fs::path FileHelper::get_filename_from_path(const fs::path &path, bool exclude_extension) { + if(exclude_extension) { + return path.stem().string(); + } else { + return path.filename().string(); + } +} + +bool FileHelper::does_filename_equal(const fs::path &path, std::string filename, bool exclude_extension) { + if(exclude_extension) { + return path.stem().string() == filename; + } else { + return path.filename().string() == filename; + } +} + +fs::path FileHelper::get_directory(const fs::path &path) { + return path.parent_path(); +} + +void FileHelper::rename(const fs::path &oldPath, const fs::path &newPath) { + fs::rename(oldPath, newPath); +} + +void FileHelper::copy(const fs::path &oldPath, const fs::path &newPath, bool recursive) { + write_folder_if_it_does_not_exist(newPath); + + fs::copy_options options = (recursive) ? fs::copy_options::recursive : fs::copy_options::none; + options |= fs::copy_options::overwrite_existing; + + fs::copy(oldPath, newPath, options); +} + +void FileHelper::format_folder_string(fs::path &folderPath) { + if((!folderPath.empty()) && !StringHelper::ends_with(folderPath, "/")) { + folderPath += "/"; + } +} + +size_t FileHelper::align16(size_t size) { + return (size + 15) & ~0xF; +} + +void FileHelper::byteswap(std::vector &bytes) { + size_t numBytes = bytes.size(); + for(size_t i = 0; i < numBytes; i += 2) { + uint8_t temp = bytes[i]; + bytes[i] = bytes[i + 1]; + bytes[i + 1] = temp; + } +} + +void FileHelper::endianswap(std::vector &bytes) { + size_t numBytes = bytes.size(); + uint8_t temp[4]; + for(size_t i = 0; i < numBytes; i += 4) { + temp[0] = bytes[i + 0]; + temp[1] = bytes[i + 1]; + temp[2] = bytes[i + 2]; + temp[3] = bytes[i + 3]; + bytes[i + 0] = temp[3]; + bytes[i + 1] = temp[2]; + bytes[i + 2] = temp[1]; + bytes[i + 3] = temp[0]; + } +} + +std::string FileHelper::get_last_modified_timestamp(const fs::path &path) { + fs::file_time_type ftime = fs::last_write_time(path); + + // Unfortunately, this is the only way that works in C++17. + auto sctp = std::chrono::time_point_cast + (ftime - std::filesystem::file_time_type::clock::now() + std::chrono::system_clock::now()); + std::time_t t = std::chrono::system_clock::to_time_t(sctp); + + std::string out(21, '\0'); + strftime(&out[0], out.size(), "%FT%TZ", gmtime(&t)); + out.pop_back(); // Removes the null terminator from the string. + + return out; +} + +void FileHelper::insert_timestamps_from_directory(const fs::path &dirPath, std::unordered_map ×tamps) { + // TODO: Make this multithreaded? + for (const auto &filepath : fs::recursive_directory_iterator(dirPath)) { + timestamps[filepath] = get_last_modified_timestamp(filepath); + } +} diff --git a/tools/dkr_assets_tool_src/helpers/fileHelper.h b/tools/dkr_assets_tool_src/helpers/fileHelper.h new file mode 100644 index 00000000..906851b6 --- /dev/null +++ b/tools/dkr_assets_tool_src/helpers/fileHelper.h @@ -0,0 +1,62 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include "stringHelper.h" +#include "debugHelper.h" + +#include +namespace fs = std::filesystem; + +class FileHelper { +public: + static std::vector read_binary_file(const fs::path &filename); + static std::string read_text_file(const fs::path &filepath, size_t maxSize=SIZE_MAX); + + static void write_text_file(const std::string &text, const fs::path &filepath, bool ensurePathExists=false); + + static void write_folder_if_it_does_not_exist(const fs::path &path); + + static void write_empty_file(const fs::path &filepath, bool ensurePathExists=false); + static void write_binary_file(std::vector &data, const fs::path &filepath, bool ensurePathExists=false); + static void write_binary_file(uint8_t *data, size_t dataSize, const fs::path &filepath, bool ensurePathExists=false); + static void write_binary_file(const char *data, size_t dataSize, const fs::path &filepath, bool ensurePathExists=false); + + static bool path_exists(const fs::path &path); + static bool is_zip_file(const fs::path &path); + + static std::vector get_files_from_directory(const fs::path &dirPath, bool recursive=true); + static std::vector get_files_from_directory_with_extension(const fs::path &dirPath, std::string extension, bool recursive=true); + static std::vector get_files_from_directory_excluding_extension(const fs::path &dirPath, std::string extension, bool recursive=true); + static std::vector get_folders_from_directory(const fs::path &dirPath, bool recursive=true); + + static void append_files_from_directory(const fs::path &dirPath, std::vector &out, bool recursive=true); + static void append_files_from_directory_relative(const fs::path &dirPath, std::vector &out, bool recursive=true); + static void append_files_from_directory_with_extension(const fs::path &dirPath, std::string extension, std::vector &out, bool recursive=true); + + static fs::path get_filename_from_path(const fs::path &path, bool exclude_extension = false); + + static bool does_filename_equal(const fs::path &path, std::string filename, bool exclude_extension = false); + + static fs::path get_directory(const fs::path &path); + + static void rename(const fs::path &oldPath, const fs::path &newPath); + static void copy(const fs::path &oldPath, const fs::path &newPath, bool recursive = false); + + static void format_folder_string(fs::path &folderPath); + + static size_t align16(size_t size); + + static void byteswap(std::vector &bytes); + // Converts between big and little endian + static void endianswap(std::vector &bytes); + + static std::string get_last_modified_timestamp(const fs::path &path); + static void insert_timestamps_from_directory(const fs::path &dirPath, std::unordered_map ×tamps); +private: + +}; diff --git a/tools/dkr_assets_tool_src/helpers/gltf/gltfDkrTriangle.cpp b/tools/dkr_assets_tool_src/helpers/gltf/gltfDkrTriangle.cpp new file mode 100644 index 00000000..919a695f --- /dev/null +++ b/tools/dkr_assets_tool_src/helpers/gltf/gltfDkrTriangle.cpp @@ -0,0 +1,40 @@ +#include "gltfDkrTriangle.h" + +#include + +GltfDkrTriangle::GltfDkrTriangle(DkrTriangle &tri) { + vi0 = tri.vi0; + vi1 = tri.vi1; + vi2 = tri.vi2; +} + +GltfDkrTriangle::GltfDkrTriangle(uint16_t a, uint16_t b, uint16_t c) { + vi0 = a; + vi1 = b; + vi2 = c; +} + +// Determine if another triangle is the backface of this one. +bool GltfDkrTriangle::is_backface(const GltfDkrTriangle &other) { + return this->vi0 == other.vi0 && this->vi1 == other.vi2 && this->vi2 == other.vi1; +} + +// Returns number of bytes written. +int GltfDkrTriangle::write_indices(uint16_t *indices) { + indices[0] = vi0; + indices[1] = vi1; + indices[2] = vi2; + return get_size(); +} + +uint16_t GltfDkrTriangle::get_minimum_index() { + return std::min(vi0, std::min(vi1, vi2)); +} + +uint16_t GltfDkrTriangle::get_maximum_index() { + return std::max(vi0, std::max(vi1, vi2)); +} + +size_t GltfDkrTriangle::get_size() { + return sizeof(uint16_t) * 3; +} \ No newline at end of file diff --git a/tools/dkr_assets_tool_src/helpers/gltf/gltfDkrTriangle.h b/tools/dkr_assets_tool_src/helpers/gltf/gltfDkrTriangle.h new file mode 100644 index 00000000..4b3a5645 --- /dev/null +++ b/tools/dkr_assets_tool_src/helpers/gltf/gltfDkrTriangle.h @@ -0,0 +1,22 @@ +#pragma once + +#include "fileTypes/triangle.hpp" + +class GltfDkrTriangle { +public: + uint16_t vi0, vi1, vi2; + + GltfDkrTriangle(DkrTriangle &tri); + GltfDkrTriangle(uint16_t a, uint16_t b, uint16_t c); + + // Determine if another triangle is the backface of this one. + bool is_backface(const GltfDkrTriangle &other); + + // Returns number of bytes written. + int write_indices(uint16_t *indices); + + uint16_t get_minimum_index(); + uint16_t get_maximum_index(); + + static size_t get_size(); +}; \ No newline at end of file diff --git a/tools/dkr_assets_tool_src/helpers/gltf/gltfDkrVertex.cpp b/tools/dkr_assets_tool_src/helpers/gltf/gltfDkrVertex.cpp new file mode 100644 index 00000000..641fd5bb --- /dev/null +++ b/tools/dkr_assets_tool_src/helpers/gltf/gltfDkrVertex.cpp @@ -0,0 +1,96 @@ +#include "gltfDkrVertex.h" + +GltfDkrVertex::GltfDkrVertex(DkrVertex *vertex, DkrTexCoords *uv, int texWidth, int texHeight){ + x = (float)vertex->x * MODEL_SCALE_GLTF; + y = (float)vertex->y * MODEL_SCALE_GLTF; + z = (float)vertex->z * MODEL_SCALE_GLTF; + r = (float)vertex->r / 255.0f; + g = (float)vertex->g / 255.0f; + b = (float)vertex->b / 255.0f; + a = (float)vertex->a / 255.0f; + if (uv == nullptr || texWidth == 0 || texHeight == 0) { + u = 0; + v = 0; + return; + } + u = ((float)uv->u / 32.0f) / (float)texWidth; + v = ((float)uv->v / 32.0f) / (float)texHeight; +} + +GltfDkrVertex::GltfDkrVertex(int16_t xPos, int16_t yPos, int16_t zPos, + uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha, + int16_t uOffset, int16_t vOffset, int texWidth, int texHeight) { + x = (float)xPos * MODEL_SCALE_GLTF; + y = (float)yPos * MODEL_SCALE_GLTF; + z = (float)zPos * MODEL_SCALE_GLTF; + r = (float)red / 255.0f; + g = (float)green / 255.0f; + b = (float)blue / 255.0f; + a = (float)alpha / 255.0f; + if(texWidth == 0 || texHeight == 0) { + u = 0; + v = 0; + return; + } + u = ((float)uOffset / 32.0f) / (float)texWidth; + v = ((float)vOffset / 32.0f) / (float)texHeight; +} + +GltfDkrVertex::GltfDkrVertex(float xPos, float yPos, float zPos, + float red, float green, float blue, float alpha, float uOffset, float vOffset) { + x = xPos * MODEL_SCALE_GLTF_INVERSE; + y = yPos * MODEL_SCALE_GLTF_INVERSE; + z = zPos * MODEL_SCALE_GLTF_INVERSE; + r = red; + g = green; + b = blue; + a = alpha; + u = uOffset; + v = vOffset; +} + +bool GltfDkrVertex::operator==(const GltfDkrVertex& other){ + return x == other.x && y == other.y && z == other.z && + r == other.r && g == other.g && b == other.b && a == other.a && + u == other.u && v == other.v; +} + +// Returns number of bytes written. +int GltfDkrVertex::write_position(float *positions) { + positions[0] = x; + positions[1] = y; + positions[2] = z; + return get_positions_size(); +} + +// Returns number of bytes written. +int GltfDkrVertex::write_color(float *colors) { + colors[0] = r; + colors[1] = g; + colors[2] = b; + colors[3] = a; + return get_colors_size(); +} + +// Returns number of bytes written. +int GltfDkrVertex::write_uv(float *uvs) { + uvs[0] = u; + uvs[1] = v; + return get_uv_size(); +} + +size_t GltfDkrVertex::get_positions_size() { + return sizeof(float) * 3; +} + +size_t GltfDkrVertex::get_colors_size() { + return sizeof(float) * 4; +} + +size_t GltfDkrVertex::get_uv_size() { + return sizeof(float) * 2; +} + +size_t GltfDkrVertex::get_size() { + return get_positions_size() + get_colors_size() + get_uv_size(); +} diff --git a/tools/dkr_assets_tool_src/helpers/gltf/gltfDkrVertex.h b/tools/dkr_assets_tool_src/helpers/gltf/gltfDkrVertex.h new file mode 100644 index 00000000..6eaba641 --- /dev/null +++ b/tools/dkr_assets_tool_src/helpers/gltf/gltfDkrVertex.h @@ -0,0 +1,39 @@ +#pragma once + +#include "fileTypes/vertex.hpp" +#include "fileTypes/texCoords.hpp" + +// TODO: Move this into a singleton class. +#define MODEL_SCALE_GLTF (1.0f / 1000.0f) +#define MODEL_SCALE_GLTF_INVERSE (1.0f / MODEL_SCALE_GLTF) + +// Class used for converting DKR's vertex information to the glTF format. +class GltfDkrVertex { +public: + float x, y, z; + float r, g, b, a; + float u, v; + + GltfDkrVertex(DkrVertex *vertex, DkrTexCoords *uv=nullptr, int texWidth=0, int texHeight=0); + GltfDkrVertex(int16_t xPos, int16_t yPos, int16_t zPos, + uint8_t red = 255, uint8_t green = 255, uint8_t blue = 255, uint8_t alpha = 255, + int16_t uOffset = 0, int16_t vOffset = 0, int texWidth = 0, int texHeight = 0); + GltfDkrVertex(float xPos, float yPos, float zPos, + float red = 1.0f, float green = 1.0f, float blue = 1.0f, float alpha = 1.0f, + float uOffset = 0, float vOffset = 0); + + bool operator==(const GltfDkrVertex& other); + bool equals(DkrVertex *vertex, DkrTexCoords *uv=nullptr, int texWidth=0, int texHeight=0); + + int write_position(float *positions); // Returns number of bytes written. + int write_color(float *colors); // Returns number of bytes written. + int write_uv(float *uvs); // Returns number of bytes written. + + static size_t get_positions_size(); + + static size_t get_colors_size(); + + static size_t get_uv_size(); + + static size_t get_size(); +}; \ No newline at end of file diff --git a/tools/dkr_assets_tool_src/helpers/gltf/gltfHelper.cpp b/tools/dkr_assets_tool_src/helpers/gltf/gltfHelper.cpp new file mode 100644 index 00000000..9dd9293b --- /dev/null +++ b/tools/dkr_assets_tool_src/helpers/gltf/gltfHelper.cpp @@ -0,0 +1,120 @@ +#include "gltfHelper.h" + +// Defines for the tinygltf library. +#define TINYGLTF_IMPLEMENTATION +#define TINYGLTF_USE_CPP14 +#include "libs/tiny_gltf.h" + +GltfFile::GltfFile(const fs::path &filepath) { + std::string err; + std::string warn; + bool loadResult = _tinygltf.LoadASCIIFromFile(&_model, &err, &warn, filepath); + + if(!warn.empty()) { + DebugHelper::warn(warn); + } + + if(!err.empty()) { + DebugHelper::error_no_throw(err); + } + + DebugHelper::assert_(loadResult, "(GltfFile::GltfFile) Failed to load GLTF file ", filepath); + + // Model has successfully loaded. +} + +GltfFile::~GltfFile() { +} + +int GltfFile::get_node_count() { + return _model.nodes.size(); +} + +std::string GltfFile::get_node_name(int node) { + return _model.nodes[node].name; +} + +void GltfFile::get_node_position(int node, double &x, double &y, double &z) { + x = _model.nodes[node].translation[0]; + y = _model.nodes[node].translation[1]; + z = _model.nodes[node].translation[2]; +} + +WriteableGltfFile::WriteableGltfFile(std::string rootName) { + tinygltf::Node rootNode; + tinygltf::Scene scene; + tinygltf::Asset asset; + + rootNode.name = rootName; + + // Root node is node 0. + _model.nodes.push_back(rootNode); + + // Scene should just have the root node. + scene.nodes.push_back(0); + + _model.scenes.push_back(scene); +} + +WriteableGltfFile::~WriteableGltfFile() { + +} + +int WriteableGltfFile::new_node(const std::string nodeName, int parentNode) { + tinygltf::Node newNode; + + int thisIndex = (int)_model.nodes.size(); + + newNode.name = nodeName; + + _model.nodes[parentNode].children.push_back(thisIndex); + + _model.nodes.push_back(newNode); + + return thisIndex; +} + +void WriteableGltfFile::set_node_position(int node, double x, double y, double z) { + if(_model.nodes[node].translation.size() == 0) { + _model.nodes[node].translation.resize(3); + } + _model.nodes[node].translation[0] = x; + _model.nodes[node].translation[1] = y; + _model.nodes[node].translation[2] = z; +} + +void WriteableGltfFile::set_node_scale(int node, double x, double y, double z) { + if(_model.nodes[node].scale.size() == 0) { + _model.nodes[node].scale.resize(3); + } + _model.nodes[node].scale[0] = x; + _model.nodes[node].scale[1] = y; + _model.nodes[node].scale[2] = z; +} + +void WriteableGltfFile::set_node_rotation(int node, double x, double y, double z, double w) { + if(_model.nodes[node].rotation.size() == 0) { + _model.nodes[node].rotation.resize(4); + } + _model.nodes[node].rotation[0] = x; + _model.nodes[node].rotation[1] = y; + _model.nodes[node].rotation[2] = z; + _model.nodes[node].rotation[3] = w; +} + +void WriteableGltfFile::set_node_rotation_y(int node, double y) { + if(_model.nodes[node].rotation.size() == 0) { + _model.nodes[node].rotation.resize(4); + _model.nodes[node].rotation[3] = 1.0; + } + _model.nodes[node].rotation[1] = y; +} + +void WriteableGltfFile::save(const std::string filepath) { + FileHelper::write_folder_if_it_does_not_exist(filepath); + _tinygltf.WriteGltfSceneToFile(&_model, filepath, + true, // embedImages + true, // embedBuffers + true, // pretty print + false); // write binary +} diff --git a/tools/dkr_assets_tool_src/helpers/gltf/gltfHelper.h b/tools/dkr_assets_tool_src/helpers/gltf/gltfHelper.h new file mode 100644 index 00000000..31da8d21 --- /dev/null +++ b/tools/dkr_assets_tool_src/helpers/gltf/gltfHelper.h @@ -0,0 +1,82 @@ +#pragma once + +#include "helpers/debugHelper.h" +#include "helpers/fileHelper.h" +#include +#include "libs/tiny_gltf.h" + +// Read-Only .gltf file +class GltfFile { +public: + GltfFile(const fs::path &filepath); + ~GltfFile(); + + // Node stuff + int get_node_count(); + std::string get_node_name(int node); + void get_node_position(int node, double &x, double &y, double &z); + + template + T get_node_extra(int node, std::string key, T defaultValue) { + tinygltf::Node &gltfNode = _model.nodes[node]; + + if(!gltfNode.extras.IsObject()) { + // This node does not have any extras, just return the default value. + return defaultValue; + } + + if(!gltfNode.extras.Has(key)) { + // Return default value if the key is not in the map. + return defaultValue; + } + + tinygltf::Value val = gltfNode.extras.Get(key); + + return val.Get(); + } + +private: + tinygltf::Model _model; + tinygltf::TinyGLTF _tinygltf; +}; + +// Write-Only .gltf file +class WriteableGltfFile { +public: + WriteableGltfFile(std::string rootNode); + ~WriteableGltfFile(); + + // Node stuff + static const int ROOT_NODE = 0; + + // returns index of the new node. + int new_node(const std::string nodeName, int parentNode = ROOT_NODE); + + void set_node_position(int node, double x, double y, double z); + void set_node_scale(int node, double x, double y, double z); + void set_node_rotation(int node, double x, double y, double z, double w); + void set_node_rotation_y(int node, double y); + + template + void set_node_extra(int node, std::string key, T value) { + if((int)_model.nodes[node].extras.Type() == 0) { + tinygltf::Value::Object initObj; + _model.nodes[node].extras = tinygltf::Value(initObj); + } + + tinygltf::Value::Object &obj = _model.nodes[node].extras.Get(); + + obj[key] = tinygltf::Value(value); + }; + + void save(const std::string filepath); + +private: + tinygltf::Model _model; + tinygltf::TinyGLTF _tinygltf; +}; + +class GltfHelper { +public: + +}; diff --git a/tools/dkr_assets_tool_src/helpers/gltf/gltfPrimitive.cpp b/tools/dkr_assets_tool_src/helpers/gltf/gltfPrimitive.cpp new file mode 100644 index 00000000..12108bef --- /dev/null +++ b/tools/dkr_assets_tool_src/helpers/gltf/gltfPrimitive.cpp @@ -0,0 +1,46 @@ +#include "gltfPrimitive.h" + +GltfPrimitive::GltfPrimitive(DkrVertex *vertices, DkrTriangle *triangles, size_t numTris, TextureHeader *texture, int materialIndex) { + int texW = 0; + int texH = 0; + if(texture != nullptr) { + texW = texture->width; + texH = texture->height; + } + + _materialIndex = materialIndex; + + for(size_t i = 0; i < numTris; i++) { + DkrTriangle *tri = &triangles[i]; + + int index0 = _get_or_set_index(&vertices[tri->vi0], &tri->uv0, texW, texH); + int index1 = _get_or_set_index(&vertices[tri->vi1], &tri->uv1, texW, texH); + int index2 = _get_or_set_index(&vertices[tri->vi2], &tri->uv2, texW, texH); + + _triangles.push_back(new GltfDkrTriangle(index0, index1, index2)); + + if(tri->flags & 0x40) { // Draw backface + _triangles.push_back(new GltfDkrTriangle(index0, index2, index1)); + } + } +} + +GltfPrimitive::~GltfPrimitive() { + // _triangles and _vertices should be deleted automatically from std::vector's deconstructor. +} + +int GltfPrimitive::_get_or_set_index(DkrVertex *vertex, DkrTexCoords *uv, int texWidth, int texHeight) { + GltfDkrVertex *newVertex = new GltfDkrVertex(vertex, uv, texWidth, texHeight); + int i = 0; + while(i < (int)_vertices.size()) { + if(newVertex == _vertices[i]) { + // Found vertex. + delete newVertex; // Was not needed. + return i; + } + i++; + } + _vertices.push_back(newVertex); + return i; +} + diff --git a/tools/dkr_assets_tool_src/helpers/gltf/gltfPrimitive.h b/tools/dkr_assets_tool_src/helpers/gltf/gltfPrimitive.h new file mode 100644 index 00000000..a1446292 --- /dev/null +++ b/tools/dkr_assets_tool_src/helpers/gltf/gltfPrimitive.h @@ -0,0 +1,20 @@ +#pragma once + +#include + +#include "gltfDkrVertex.h" +#include "gltfDkrTriangle.h" +#include "fileTypes/texture.hpp" + + +class GltfPrimitive { +public: + GltfPrimitive(DkrVertex *vertices, DkrTriangle *triangles, size_t numTris, TextureHeader *texture, int materialIndex); + ~GltfPrimitive(); +private: + std::vector _triangles; + std::vector _vertices; + int _materialIndex; + + int _get_or_set_index(DkrVertex *vertex, DkrTexCoords *uv, int texWidth, int texHeight); +}; diff --git a/tools/dkr_assets_tool_src/helpers/gzipHelper.cpp b/tools/dkr_assets_tool_src/helpers/gzipHelper.cpp new file mode 100644 index 00000000..bdad1619 --- /dev/null +++ b/tools/dkr_assets_tool_src/helpers/gzipHelper.cpp @@ -0,0 +1,32 @@ +#include "gzipHelper.h" + +#include "libs/gzip/DKRCompression.h" + +// Compression shouldn't be thread safe, but testing suggests that the mutex isn't necessary? +//#include +//std::mutex gzipMutex; + +std::vector GzipHelper::decompress_gzip(std::vector &compressedData) { + //gzipMutex.lock(); + + // Needed padding to prevent errors with decompressing. + if(compressedData[compressedData.size() - 1] != 0) { + compressedData.push_back(0); + compressedData.push_back(0); + compressedData.push_back(0); + compressedData.push_back(0); + } + DKRCompression compression; + std::vector out = compression.decompressBuffer(compressedData); + //gzipMutex.unlock(); + + return out; +} + +std::vector GzipHelper::compress_gzip(std::vector &uncompressedData) { + //gzipMutex.lock(); + DKRCompression compression; + std::vector out = compression.compressBuffer(uncompressedData); + //gzipMutex.unlock(); + return out; +} diff --git a/tools/dkr_assets_tool_src/helpers/gzipHelper.h b/tools/dkr_assets_tool_src/helpers/gzipHelper.h new file mode 100644 index 00000000..6c3e54e4 --- /dev/null +++ b/tools/dkr_assets_tool_src/helpers/gzipHelper.h @@ -0,0 +1,15 @@ +#pragma once + +#include +#include + +/** + * Singleton class that deals with compressing / decompressing asset data using gzip. + */ +class GzipHelper { +public: + static std::vector decompress_gzip(std::vector &compressedData); + + // Note: uncompressedData will become garbled (Don't use it after this function!). + static std::vector compress_gzip(std::vector &uncompressedData); +}; diff --git a/tools/dkr_assets_tool_src/helpers/imageHelper.cpp b/tools/dkr_assets_tool_src/helpers/imageHelper.cpp new file mode 100644 index 00000000..b5e05989 --- /dev/null +++ b/tools/dkr_assets_tool_src/helpers/imageHelper.cpp @@ -0,0 +1,365 @@ +#include "imageHelper.h" + +#include // for memcpy +#include + +#include "fileHelper.h" +#include "debugHelper.h" +#include "libs/n64graphics/n64graphics.h" +#include "libs/stb_image.h" +#include "helpers/dataHelper.h" + +N64Image::N64Image(fs::path filepath, std::string &format, bool alignData) : _format(format) { + bool isColourImage = (format == "RGBA16") || (format == "RGBA32") || (format == "CI4") || (format == "CI8"); + + DebugHelper::assert(StringHelper::ends_with(filepath, ".png"), + "Only .png images are supported! Invalid image path: ", filepath); + + void *imgData; // Can be either rgba* or ia* n64graphics types. + + // Load image from a .png file, getting the width and height as well. + if(isColourImage) { + imgData = (void *)png2rgba(filepath.c_str(), &_width, &_height); + } else { + imgData = (void *)png2ia(filepath.c_str(), &_width, &_height); + } + + DebugHelper::assert(imgData != nullptr, "(N64Image::N64Image) Could not load image: ", filepath); + + size_t size = ImageHelper::image_size(_width, _height, _format); + + if(alignData) { + size = DataHelper::align16(size); + } + + // Make sure the internal data buffer is large enough. + _data.resize(size); + + // Convert n64graphics data type to _data. + if(isColourImage) { + rgba2raw(&_data[0], (rgba*)imgData, _width, _height, get_bit_depth()); + } else if(format == "I4" || format == "I8") { + i2raw(&_data[0], (ia*)imgData, _width, _height, get_bit_depth()); + } else { + ia2raw(&_data[0], (ia*)imgData, _width, _height, get_bit_depth()); + } + +} + +N64Image::N64Image(int width, int height, std::string &format, bool alignData) : _width(width), _height(height), _format(format) { + int size = width * height; + switch(ImageHelper::bytes_in_format(_format)) { + case 0: // 4-bit format + size /= 2; + break; + case 2: // 16-bit format + size *= 2; + break; + case 4: // 32-bit format + size *= 4; + break; + } + + if(alignData) { + size = DataHelper::align16(size); + } + + _data.resize(size); // Should fill the data with zeroes. +} + +N64Image::~N64Image() { +} + +void N64Image::write_from(uint8_t *inData, size_t dataLength) { + memcpy(&_data[0], inData, dataLength); +} + +void N64Image::copy_to(uint8_t *out) { + memcpy(out, &_data[0], size()); +} + +void N64Image::interlace() { + int bitDepth = get_bit_depth(); + int bufferSize = (bitDepth == 32) ? 8 : 4; + + uint8_t* temp = new uint8_t[bufferSize]; + + int numPixels; + if(bitDepth == 4) { + numPixels = ((_width * _height) / 2); + } else { + numPixels = (_width * _height * (bitDepth / 8)); + } + + int stride = bufferSize * 2; + + int size = numPixels / stride; + + for(int i = 0; i < size; i++) { + int row; + if(bitDepth == 4) { + row = (i * stride) / _width * 2; + } else { + row = (i * stride) / _width / (bitDepth / 8); + } + if(row % 2 == 0) continue; + for(int j = 0; j < bufferSize; j++) { + temp[j] = _data[i * stride + j]; + _data[i * stride + j] = _data[(i * stride + j + bufferSize)]; + _data[(i * stride + j + bufferSize)] = temp[j]; + } + } + + delete[] temp; +} + +void N64Image::flip_vertically() { + int numBytesPerLine = _width; // Convert width into number of bytes per line. + switch(ImageHelper::bytes_in_format(_format)) { + case 0: + numBytesPerLine /= 2; // 2 pixels per byte + break; + case 2: + numBytesPerLine *= 2; // 2 bytes per pixel + break; + case 4: + numBytesPerLine *= 4; // 4 bytes per pixel + break; + // Don't need to do anything for the 8-bit formats. + } + for(int y = 0; y < _height / 2; y++) { + for(int x = 0; x < numBytesPerLine; x++) { + uint8_t temp = _data[y * numBytesPerLine + x]; + _data[y * numBytesPerLine + x] = _data[((_height - y - 1) * numBytesPerLine + x)]; + _data[((_height - y - 1) * numBytesPerLine + x)] = temp; + } + } +} + +size_t N64Image::size() { + return _data.size(); +} + +std::string N64Image::get_format() { + return _format; +} + +int N64Image::get_width() { + return _width; +} + +int N64Image::get_height() { + return _height; +} + +int N64Image::get_bit_depth() { + int byteSize = ImageHelper::bytes_in_format(_format); + switch(byteSize) { + case 4: + return 32; + case 2: + return 16; + case 1: + return 8; + default: + return 4; + } +} + +bool N64Image::is_4bit_format() { + return get_bit_depth() == 4; +} + +// TODO: Figure out a better way to implement this. +uint8_t *N64Image::get_img_as_rgba32() { + if (_format == "RGBA16") { + return reinterpret_cast(raw2rgba(&_data[0], _width, _height, 16)); + } + + uint8_t *out = new uint8_t[_width * _height * 4]; + + if(_format == "RGBA32") { + memcpy(out, &_data[0], _data.size()); + } else if (_format == "IA16") { + for(size_t i = 0; i < _data.size(); i += 2) { + int outIndex = i * 2; + int intensity = _data[i]; + int alpha = _data[i + 1]; + out[outIndex + 0] = intensity; + out[outIndex + 1] = intensity; + out[outIndex + 2] = intensity; + out[outIndex + 3] = alpha; + } + } else if (_format == "IA8") { + for(size_t i = 0; i < _data.size(); i++) { + int outIndex = i * 4; + int intensity = (_data[i] >> 4) & 0xF; + int alpha = _data[i] & 0xF; + out[outIndex + 0] = intensity; + out[outIndex + 1] = intensity; + out[outIndex + 2] = intensity; + out[outIndex + 3] = alpha; + } + } else if (_format == "IA4") { + for(size_t i = 0; i < _data.size(); i++) { + for(size_t j = 0; j < 2; j++) { // Two pixels per byte. + int outIndex = (i * 8) + (j * 4); + int pixelValue = _data[i] >> (j * 4); + int intensity = (pixelValue >> 1) & 7; + int alpha = pixelValue & 1; + out[outIndex + 0] = intensity; + out[outIndex + 1] = intensity; + out[outIndex + 2] = intensity; + out[outIndex + 3] = alpha; + } + } + } else if (_format == "I8") { + for(size_t i = 0; i < _data.size(); i++) { + int outIndex = i * 4; + int intensity = _data[i]; + out[outIndex + 0] = intensity; + out[outIndex + 1] = intensity; + out[outIndex + 2] = intensity; + out[outIndex + 3] = 255; + } + } else if (_format == "I4") { + for(size_t i = 0; i < _data.size(); i++) { + for(size_t j = 0; j < 2; j++) { // Two pixels per byte. + int outIndex = (i * 8) + (j * 4); + int intensity = _data[i] >> (j * 4); + out[outIndex + 0] = intensity; + out[outIndex + 1] = intensity; + out[outIndex + 2] = intensity; + out[outIndex + 3] = 255; + } + } + } else { + // TODO: Support CI4/CI8 + DebugHelper::error("(N64Image::get_img_as_rgba32) Format \"", _format, "\" is currently not supported."); + } + + return out; +} + +// TODO: Figure out a better way to implement this. +uint8_t *N64Image::get_img_as_ia16() { + if(_format == "IA8") { + return reinterpret_cast(raw2ia(&_data[0], _width, _height, 8)); + } else if(_format == "IA4") { + return reinterpret_cast(raw2ia(&_data[0], _width, _height, 4)); + } else if(_format == "I8") { + return reinterpret_cast(raw2i(&_data[0], _width, _height, 8)); + } else if(_format == "I4") { + return reinterpret_cast(raw2i(&_data[0], _width, _height, 4)); + } + + uint8_t *out = new uint8_t[_width * _height * 2]; + + if(_format == "IA16") { + memcpy(out, &_data[0], _data.size()); + } else if (_format == "RGBA32") { + for(size_t i = 0; i < _data.size(); i += 4) { + int outIndex = i / 2; + int red = _data[i + 0]; + int green = _data[i + 1]; + int blue = _data[i + 2]; + int alpha = _data[i + 3]; + + out[outIndex + 0] = (red + green + blue) / 3; + out[outIndex + 1] = alpha; + } + } else if (_format == "RGBA16") { + for(size_t i = 0; i < _data.size(); i += 2) { + int outIndex = i; + int red = ((_data[i] >> 3) & 0x1F); + int green = (((_data[i] & 7) << 2) | ((_data[i + 1] >> 6) & 0x3)) & 0x1F; + int blue = (_data[i + 1] >> 1) & 0x1F; + int alpha = _data[i + 1] & 1; + + out[outIndex + 0] = (red + green + blue) / 3; + out[outIndex + 1] = alpha; + } + } else { + // TODO: Support CI4/CI8 + DebugHelper::error("(N64Image::get_img_as_ia16) Format \"", _format, "\" is currently not supported."); + } + + return out; +} + +void N64Image::save(fs::path finalFilepath) { + if(_format == "CI4" || _format == "CI8") { + DebugHelper::error("(N64Image::save) Format \"", _format, "\" is currently not supported."); + } + + // Make sure the folder of the final filepath exists, so it doesn't cause an error. + FileHelper::write_folder_if_it_does_not_exist(finalFilepath); + + uint8_t *imgData; + if(_format == "RGBA32" || _format == "RGBA16") { + // Save RGBA image. + imgData = get_img_as_rgba32(); + + int result = rgba2png(finalFilepath.c_str(), reinterpret_cast(imgData), _width, _height); // Save RGBA data as a .png file. + DebugHelper::assert(result == 1, "(N64Image::save) stbi_write_png returned ", result, ". Could not save image ", finalFilepath); + DebugHelper::assert(FileHelper::path_exists(finalFilepath), "(N64Image::save) Image ", finalFilepath, " could not be saved."); + } else { + // Save IA image. + imgData = get_img_as_ia16(); + int result = ia2png(finalFilepath.c_str(), reinterpret_cast(imgData), _width, _height); // Save IA data as a .png file. + DebugHelper::assert(result == 1, "(N64Image::save) stbi_write_png returned ", result, ". Could not save image ", finalFilepath); + DebugHelper::assert(FileHelper::path_exists(finalFilepath), "(N64Image::save) Image ", finalFilepath, " could not be saved."); + } + delete[] imgData; +} + +/**********************************************/ + +N64Image ImageHelper::load_image(fs::path filepath, std::string format) { + return N64Image(filepath, format); +} + +std::unordered_map bytesInFormatMap = { + {"RGBA32", 4}, + {"RGBA16", 2}, + {"I8", 1}, + {"I4", 0}, + {"IA16", 2}, + {"IA8", 1}, + {"IA4", 0}, + {"CI8", 1}, + {"CI4", 0} +}; + +int ImageHelper::bytes_in_format(std::string &format) { + if(format.empty()) { + DebugHelper::error("(ImageHelper::bytes_in_format) Format string empty!"); + } + auto it = bytesInFormatMap.find(format); + if(it != bytesInFormatMap.end()) { + return it->second; + } + DebugHelper::error("(ImageHelper::bytes_in_format) Invalid format string \"", format, "\""); + return -1; +} + +size_t ImageHelper::image_size(int width, int height, std::string &format) { + int bytesPerFormat = ImageHelper::bytes_in_format(format); + switch(bytesPerFormat) { + default: // 8-bit format. + return width * height; + case 0: // 4-bit format + return (width * height) / 2; + case 2: // 16-bit format + return width * height * 2; + case 4: // 32-bit format + return width * height * 4; + } +} + +size_t ImageHelper::image_size(fs::path filepath, std::string &format) { + int width, height, channels; + int gotInfo = stbi_info(filepath.c_str(), &width, &height, &channels); + DebugHelper::assert(gotInfo, filepath, " could not be loaded!"); + return image_size(width, height, format); +} diff --git a/tools/dkr_assets_tool_src/helpers/imageHelper.h b/tools/dkr_assets_tool_src/helpers/imageHelper.h new file mode 100644 index 00000000..3e917e43 --- /dev/null +++ b/tools/dkr_assets_tool_src/helpers/imageHelper.h @@ -0,0 +1,56 @@ +#pragma once + +#include "helpers/fileHelper.h" + +#include +#include +#include +#include + +class N64Image { +public: + N64Image(fs::path filepath, std::string &format, bool alignData=false); // Load image from filepath (Currently only .png is supported) + N64Image(int width, int height, std::string &format, bool alignData=false); // Create new image + ~N64Image(); + + void write_from(uint8_t *inData, size_t dataLength); + void copy_to(uint8_t *out); + + void interlace(); + void flip_vertically(); + size_t size(); + std::string get_format(); + bool is_4bit_format(); + + int get_width(); + int get_height(); + int get_bit_depth(); + + uint8_t *get_img_as_rgba32(); // Note: pointer must be freed by caller! + uint8_t *get_img_as_ia16(); // Note: pointer must be freed by caller! + + void save(fs::path finalFilepath); // Saves image (as .png) to the filepath. +private: + int _width; + int _height; + std::string _format; + + std::vector _data; +}; + +/** + * Singleton class that deals with N64 image formats and with saving/loading images. + */ +class ImageHelper { +public: + static ImageHelper& get() { + static ImageHelper instance; + return instance; + } + + static N64Image load_image(fs::path filepath, std::string format="RGBA16"); + static int bytes_in_format(std::string &format); + static size_t image_size(int width, int height, std::string &format); + static size_t image_size(fs::path filepath, std::string &format); // Get byte-size of .png image + +}; diff --git a/tools/dkr_assets_tool_src/helpers/jsonHelper.cpp b/tools/dkr_assets_tool_src/helpers/jsonHelper.cpp new file mode 100644 index 00000000..66b85afa --- /dev/null +++ b/tools/dkr_assets_tool_src/helpers/jsonHelper.cpp @@ -0,0 +1,480 @@ +#include "jsonHelper.h" + +#include +#include +#include + +#include "helpers/fileHelper.h" +#include "helpers/dataHelper.h" +#include "helpers/debugHelper.h" +#include "helpers/stringHelper.h" + +// TODO: Support RapidJSON +#include "libs/json.hpp" // nlohmann JSON library. (https://github.com/nlohmann/json) + +#include "libs/ThreadPool.h" + +using json = nlohmann::json; + +namespace JSON_HELPER_DETAILS { + class JsonFileData { + public: + JsonFileData(std::string filepath) { + std::ifstream f(filepath); + data = json::parse(f); + } + JsonFileData() { + } + json data; + }; +} + +/*******************************************************************************************************/ + +JsonFile::JsonFile(std::string filepath) : _filepath(filepath) { + _data = new JSON_HELPER_DETAILS::JsonFileData(filepath); +} + +JsonFile::~JsonFile() { + delete _data; +} + +std::string JsonFile::get_string(const std::string &ptr, const std::string &defaultValue) { + const json::json_pointer jsonPtr(ptr); // Working with JSON pointers is a LOT faster than normal basic_json + return _data->data.value(jsonPtr, defaultValue); +} + +// Returns the string as lowercase, used when case shouldn't matter. +std::string JsonFile::get_string_lowercase(const std::string &ptr, const std::string &defaultValue) { + std::string out = get_string(ptr, defaultValue); + StringHelper::make_lowercase(out); + return out; +} + +// Returns the string as uppercase, mainly used for texture formats (RGBA16, IA8, etc.) +std::string JsonFile::get_string_uppercase(const std::string &ptr, const std::string &defaultValue) { + std::string out = get_string(ptr, defaultValue); + StringHelper::make_uppercase(out); + return out; +} + +fs::path JsonFile::get_path(const std::string &ptr, const std::string &defaultValue) { + fs::path out = get_string(ptr, defaultValue); + FileHelper::format_folder_string(out); // Make sure the returning string is in valid form. + return out; +} + +void JsonFile::copy_string_to(const std::string &ptr, char *output, size_t maxLengthForOutput, const std::string &defaultValue) { + if(maxLengthForOutput < 1) { + return; + } + std::string outStr; + if(!has(ptr)) { + // JSON file does not have ptr, so just use the defaultValue instead. + outStr = defaultValue; + } else { + // JSON file does have the ptr, but make sure that value is a string. + DebugHelper::assert_(is_value_a_string(ptr), "(JsonFile::copy_string_to) Value at [", ptr, "] is not a string!"); + outStr = get_string(ptr, ""); + } + size_t length = outStr.length(); + if(length > maxLengthForOutput) { + DebugHelper::warn("(JsonFile::copy_string_to) String at [", ptr, "] is too long! Length was ", length, ", but the limit is ", maxLengthForOutput); + length = maxLengthForOutput; + } + outStr.copy(output, length); +} + +int JsonFile::get_int(const std::string &ptr, const int &defaultValue) { + const json::json_pointer jsonPtr(ptr); + return _data->data.value(jsonPtr, defaultValue); +} + +bool JsonFile::get_bool(const std::string &ptr, const bool &defaultValue) { + const json::json_pointer jsonPtr(ptr); + return _data->data.value(jsonPtr, defaultValue); +} + +double JsonFile::get_float(const std::string &ptr, const double &defaultValue) { + const json::json_pointer jsonPtr(ptr); + return _data->data.value(jsonPtr, defaultValue); +} + +template +void JsonFile::get_array(const std::string &ptr, std::vector &arr) { + const json::json_pointer jsonPtr(ptr); + json arrayJson = _data->data[jsonPtr]; + if(!arrayJson.is_array()) { + // Not an array, so don't do anything to the array. + return; + } + size_t arrLen = arrayJson.size(); + for(size_t i = 0; i < arrLen; i++) { + arr.push_back(arrayJson[i]); + } +} + +template void JsonFile::get_array(const std::string &ptr, std::vector &arr); +template void JsonFile::get_array(const std::string &ptr, std::vector &arr); +template void JsonFile::get_array(const std::string &ptr, std::vector &arr); + + +// Returns the index of the element, or -1 if it doesn't exist. +template +int JsonFile::get_index_of_elem_in_array(const std::string &ptr, T elem) { + const json::json_pointer jsonPtr(ptr); + json arrayJson = _data->data[jsonPtr]; + if(!arrayJson.is_array()) { + DebugHelper::error(_filepath, " [", ptr, "] is not an array!"); + } + + auto it = std::find(arrayJson.cbegin(), arrayJson.cend(), elem); + + if (it == arrayJson.end()) { + // Element not found in array + return -1; + } + + return std::distance(arrayJson.cbegin(), it); +} + +template int JsonFile::get_index_of_elem_in_array(const std::string &ptr, std::string elem); +template int JsonFile::get_index_of_elem_in_array(const std::string &ptr, int elem); +template int JsonFile::get_index_of_elem_in_array(const std::string &ptr, bool elem); + +template +T JsonFile::get_elem_from_array(const std::string &ptr, size_t index) { + const json::json_pointer jsonPtr(ptr); + json arrayJson = _data->data[jsonPtr]; + if(!arrayJson.is_array()) { + DebugHelper::error(_filepath, " [", ptr, "] is not an array!"); + } + DebugHelper::assert_(index < arrayJson.size(), _filepath, ": Index ", index," into array [", ptr, "] is out of bounds!"); + return arrayJson[index].get(); +} + +template std::string JsonFile::get_elem_from_array(const std::string &ptr, size_t index); +template int JsonFile::get_elem_from_array(const std::string &ptr, size_t index); +template bool JsonFile::get_elem_from_array(const std::string &ptr, size_t index); +template float JsonFile::get_elem_from_array(const std::string &ptr, size_t index); + +size_t JsonFile::length_of_array(const std::string &ptr) { + const json::json_pointer jsonPtr(ptr); + json arrayJson = _data->data[jsonPtr]; + if(arrayJson.is_null()) { + return 0; + } + if(!arrayJson.is_array()) { + DebugHelper::error(_filepath, " [", ptr, "] is not an array!"); + } + return arrayJson.size(); +} + +size_t JsonFile::length_of_string(const std::string &ptr) { + const json::json_pointer jsonPtr(ptr); + json strJson = _data->data[jsonPtr]; + if(!strJson.is_string()) { + DebugHelper::error(_filepath, " [", ptr, "] is not a string!"); + } + // Apparently strJson.json() doesn't work for string types. :/ + return strJson.get().size(); +} + +bool JsonFile::has(const std::string &ptr) { + const json::json_pointer jsonPtr(ptr); + json data = _data->data[jsonPtr]; + return !data.is_null(); +} + +bool JsonFile::is_value_a_number(const std::string &ptr) { + const json::json_pointer jsonPtr(ptr); + json data = _data->data[jsonPtr]; + return data.is_number(); +} + +bool JsonFile::is_value_a_bool(const std::string &ptr) { + const json::json_pointer jsonPtr(ptr); + json data = _data->data[jsonPtr]; + return data.is_boolean(); +} + +bool JsonFile::is_value_a_string(const std::string &ptr) { + const json::json_pointer jsonPtr(ptr); + json data = _data->data[jsonPtr]; + return data.is_string(); +} + +bool JsonFile::is_value_an_array(const std::string &ptr) { + const json::json_pointer jsonPtr(ptr); + json data = _data->data[jsonPtr]; + return data.is_array(); +} + +bool JsonFile::is_value_an_object(const std::string &ptr) { + const json::json_pointer jsonPtr(ptr); + json data = _data->data[jsonPtr]; + return data.is_object(); +} + +bool JsonFile::is_value_null(const std::string &ptr) { + return !has(ptr); +} + +fs::path JsonFile::get_filepath() { + return _filepath; +} + +JSON_HELPER_DETAILS::JsonFileData *JsonFile::get_data() { + return _data; +} + +/*******************************************************************************************************/ + +/* +class WritableJsonFile { + public: + WritableJsonFile(std::string filepath); + ~WritableJsonFile(); + + std::string set_string(const std::string &ptr, const std::string &value); + int set_int(const std::string &ptr, const int &value); + bool set_bool(const std::string &ptr, const bool &value); + + bool save_file(); + + private: + std::string _filepath; + JSON_HELPER_DETAILS::JsonFileData *_data; +}; +*/ + +WritableJsonFile::WritableJsonFile(std::string outFilepath) : _outFilepath(outFilepath) { + _data = new JSON_HELPER_DETAILS::JsonFileData(); +} + +WritableJsonFile::~WritableJsonFile() { + delete _data; +} + +void WritableJsonFile::new_object(const std::string &ptr) { + const json::json_pointer jsonPtr(ptr); + _data->data[jsonPtr] = json::object(); +} + +void WritableJsonFile::new_array(const std::string &ptr) { + const json::json_pointer jsonPtr(ptr); + _data->data[jsonPtr] = json::array(); +} + +void WritableJsonFile::set_string(const std::string &ptr, const std::string &value) { + const json::json_pointer jsonPtr(ptr); + _data->data[jsonPtr] = value; +} + +void WritableJsonFile::set_path(const std::string &ptr, fs::path value) { + //FileHelper::format_folder_string(value); // Make sure the stored string is in valid form. + set_string(ptr, value); +} + +void WritableJsonFile::set_int(const std::string &ptr, const int value) { + const json::json_pointer jsonPtr(ptr); + _data->data[jsonPtr] = value; +} + +void WritableJsonFile::set_int_if_not_value(const std::string &ptr, const int value, const int checkValue) { + if(value == checkValue) return; + set_int(ptr, value); +} + +void WritableJsonFile::set_int_if_not_zero(const std::string &ptr, const int value) { + WritableJsonFile::set_int_if_not_value(ptr, value, 0); +} + +void WritableJsonFile::set_float(const std::string &ptr, double value, const int precision) { + if(precision > 0) { + double mult = std::pow(10.0, precision); + value = std::round(value * mult) / mult; + } + const json::json_pointer jsonPtr(ptr); + _data->data[jsonPtr] = value; +} + +void WritableJsonFile::set_bool(const std::string &ptr, const bool value) { + const json::json_pointer jsonPtr(ptr); + _data->data[jsonPtr] = value; +} + +void WritableJsonFile::set_bool_if_true(const std::string &ptr, const bool value) { + if(!value) return; + set_bool(ptr, value); +} + +void WritableJsonFile::set_null(const std::string &ptr) { + const json::json_pointer jsonPtr(ptr); + _data->data[jsonPtr] = nullptr; +} + +void WritableJsonFile::save() { + // Make sure the directory exists first + FileHelper::write_folder_if_it_does_not_exist(_outFilepath); + std::ofstream o(_outFilepath); + o << std::setw(4) << _data->data << std::endl; +} + +/*******************************************************************************************************/ + +StatJsonFile::StatJsonFile(fs::path filepath) : _filepath(filepath) { + if(FileHelper::path_exists(filepath)) { + _data = new JSON_HELPER_DETAILS::JsonFileData(filepath); + } else { + _data = new JSON_HELPER_DETAILS::JsonFileData(); + } +} + +StatJsonFile::~StatJsonFile() { + delete _data; +} + +// Returns empty if entry was not found. +std::string StatJsonFile::get_entry(const fs::path &path) { + std::string pathEntry = std::string(path); + StringHelper::replace(pathEntry, "/", "~1"); + const json::json_pointer jsonPtr("/files/" + pathEntry); + return _data->data.value(jsonPtr, ""); +} + +void StatJsonFile::set_entry(const fs::path &path, const std::string &value) { + std::string pathEntry = std::string(path); + StringHelper::replace(pathEntry, "/", "~1"); + const json::json_pointer jsonPtr("/files/" + pathEntry); + _data->data[jsonPtr] = value; +} + +template +T StatJsonFile::get_value(const std::string ptr, T defaultValue) { + const json::json_pointer jsonPtr(ptr); + json jsonData = _data->data[jsonPtr]; + if(jsonData.is_null()) { + return defaultValue; + } + return _data->data.value(jsonPtr, defaultValue); +} + +template std::string StatJsonFile::get_value(const std::string ptr, std::string defaultValue); +template int StatJsonFile::get_value(const std::string ptr, int defaultValue); +template bool StatJsonFile::get_value(const std::string ptr, bool defaultValue); + +template +void StatJsonFile::set_value(const std::string ptr, T value) { + const json::json_pointer jsonPtr(ptr); + _data->data[jsonPtr] = value; +} + +template void StatJsonFile::set_value(const std::string ptr, std::string value); +template void StatJsonFile::set_value(const std::string ptr, int value); +template void StatJsonFile::set_value(const std::string ptr, bool value); + +void StatJsonFile::save() { + FileHelper::write_folder_if_it_does_not_exist(_filepath); + std::ofstream o(_filepath); + o << std::setw(4) << _data->data << std::endl; +} + +/*******************************************************************************************************/ + +bool JsonHelper::get_file(fs::path filepath, JsonFile **out) { + *out = _load_json_from_cache(filepath); + return *out != nullptr; +} + +/******************************************************************/ + +// Prototype here, because of recursion. (Can't have the `json` type be in the header file either) +void json_merge_append(json &dst, json &patch); + +void json_merge_append_step(json &dst, json &patch, const std::string &key) { + if(key == "merge-type") { // ignore merge-type + return; + } + if(dst[key].is_object()) { + // Recursion! + json_merge_append(dst[key], patch[key]); + } else if(dst[key].is_array()) { + // Append patch array to the end of the dst array! + dst[key].insert(dst[key].end(), patch[key].begin(), patch[key].end()); + } else { + dst[key] = patch[key]; + } +} + +void json_merge_append(json &dst, json &patch) { + if(dst.is_object() && patch.is_object()) { + for (json::iterator it = patch.begin(); it != patch.end(); ++it) { + json_merge_append_step(dst, patch, it.key()); + } + } +} + +enum JsonMergeType { + MERGE_PATCH, // RFC 7386 - Arrays get overwritten. + MERGE_APPEND // Like MERGE_PATCH, but arrays get appended to. +}; + +const std::vector JSON_MERGE_TYPE_VALUES = { + "patch", // MERGE_PATCH + "patch-append" // MERGE_APPEND +}; + +// Prefer appending arrays instead of overwriting them! +const std::string DEFAULT_PATCH_TYPE = "patch-append"; + +/******************************************************************/ + +void JsonHelper::patch_json(const fs::path &dstPath, const fs::path &patchPath) { + JsonFile *dstJsonFile = _load_json_from_cache(dstPath); + JsonFile *patchJsonFile = _load_json_from_cache(patchPath); + + DebugHelper::assert_(dstJsonFile != nullptr, "(JsonHelper::patch_json) ", dstPath, " could not be loaded. Make sure it is formatted properly."); + DebugHelper::assert_(patchJsonFile != nullptr, "(JsonHelper::patch_json) ", patchPath, " could not be loaded. Make sure it is formatted properly."); + + std::string mergeTypeStr = patchJsonFile->get_string_lowercase("/merge-type", DEFAULT_PATCH_TYPE); + JsonMergeType mergeType = static_cast(DataHelper::vector_index_of(JSON_MERGE_TYPE_VALUES, mergeTypeStr)); + + JSON_HELPER_DETAILS::JsonFileData *dstJson = dstJsonFile->get_data(); + JSON_HELPER_DETAILS::JsonFileData *patchJson = patchJsonFile->get_data(); + + switch(mergeType) { + case JsonMergeType::MERGE_PATCH: // RFC 7386 + // Arrays will get overwritten. + dstJson->data.merge_patch(patchJson->data); + break; + case JsonMergeType::MERGE_APPEND: + // Like MERGE_PATCH, but arrays get appended to instead of overwritten. + json_merge_append(dstJson->data, patchJson->data); + break; + default: + DebugHelper::error("Invalid merge-type value of \"", mergeTypeStr, "\""); + break; + } + + // Write patched json data to dstPath + _jsonHelperMutex.lock(); + std::ofstream o(dstPath); + o << std::setw(4) << dstJson->data << std::endl; + _jsonHelperMutex.unlock(); +} + +// Returns nullptr if unsuccessful +JsonFile *JsonHelper::_load_json_from_cache(const fs::path &filepath) { + _jsonHelperMutex.lock(); + if(_fileCache.find(filepath) == _fileCache.end()) { + try { + _fileCache[filepath] = new JsonFile(filepath); + } catch (nlohmann::detail::parse_error &err) { + _jsonHelperMutex.unlock(); + return nullptr; + } + } + _jsonHelperMutex.unlock(); + return _fileCache[filepath]; +} \ No newline at end of file diff --git a/tools/dkr_assets_tool_src/helpers/jsonHelper.h b/tools/dkr_assets_tool_src/helpers/jsonHelper.h new file mode 100644 index 00000000..92f00c4b --- /dev/null +++ b/tools/dkr_assets_tool_src/helpers/jsonHelper.h @@ -0,0 +1,129 @@ +#pragma once + +#include +#include +#include +#include +#include +#include // for is_integral_v + +#include "helpers/fileHelper.h" + +namespace JSON_HELPER_DETAILS { + // Only forward declared here, cause I don't want to expose the JSON library in the header. + // This will allow me to change the implementation if I want to in the future. + class JsonFileData; +} + +typedef std::variant JsonKey; +typedef std::variant JsonValue; + +// Read-Only JSON class +class JsonFile { + public: + JsonFile(std::string filepath); + ~JsonFile(); + + std::string get_string(const std::string &ptr, const std::string &defaultValue = ""); + std::string get_string_lowercase(const std::string &ptr, const std::string &defaultValue = ""); + std::string get_string_uppercase(const std::string &ptr, const std::string &defaultValue = ""); + fs::path get_path(const std::string &ptr, const std::string &defaultValue = ""); + void copy_string_to(const std::string &ptr, char *output, size_t maxLengthForOutput, const std::string &defaultValue = ""); + int get_int(const std::string &ptr, const int &defaultValue = -1); + bool get_bool(const std::string &ptr, const bool &defaultValue = false); + double get_float(const std::string &ptr, const double &defaultValue = 0.0); + + template + void get_array(const std::string &ptr, std::vector &arr); + + template + int get_index_of_elem_in_array(const std::string &ptr, T elem); + + template + T get_elem_from_array(const std::string &ptr, size_t index); + + size_t length_of_array(const std::string &ptr); + size_t length_of_string(const std::string &ptr); + bool has(const std::string &ptrStr); + + bool is_value_a_number(const std::string &ptr); + bool is_value_a_bool(const std::string &ptr); + bool is_value_a_string(const std::string &ptr); + bool is_value_an_array(const std::string &ptr); + bool is_value_an_object(const std::string &ptr); + bool is_value_null(const std::string &ptr); + + fs::path get_filepath(); + JSON_HELPER_DETAILS::JsonFileData *get_data(); + private: + std::string _filepath; + JSON_HELPER_DETAILS::JsonFileData *_data; +}; + +// Write-Only JSON class +class WritableJsonFile { + public: + WritableJsonFile(std::string outFilepath); + ~WritableJsonFile(); + + void new_object(const std::string &ptr); + void new_array(const std::string &ptr); + void set_string(const std::string &ptr, const std::string &value); + void set_path(const std::string &ptr, fs::path value); + void set_int(const std::string &ptr, const int value); + void set_int_if_not_value(const std::string &ptr, const int value, const int checkValue); + void set_int_if_not_zero(const std::string &ptr, const int value); + void set_float(const std::string &ptr, double value, const int precision = 0); + void set_bool(const std::string &ptr, const bool value); + void set_bool_if_true(const std::string &ptr, const bool value); + void set_null(const std::string &ptr); + + void save(); + + private: + std::string _outFilepath; + JSON_HELPER_DETAILS::JsonFileData *_data; +}; + +// Represents a json file with limited read/write capability. +class StatJsonFile { + public: + StatJsonFile(fs::path filepath); + ~StatJsonFile(); + + std::string get_entry(const fs::path &path); + void set_entry(const fs::path &path, const std::string &value); + + template + T get_value(const std::string ptr, T defaultValue); + + template + void set_value(const std::string ptr, T value); + + void save(); + private: + fs::path _filepath; + JSON_HELPER_DETAILS::JsonFileData *_data; +}; + +/** + * Singleton class that deals with saving & loading json files. + */ +class JsonHelper { +public: + static JsonHelper& get() { + static JsonHelper instance; + return instance; + } + + bool get_file(fs::path filepath, JsonFile **out); + void patch_json(const fs::path &dst, const fs::path &patch); + +private: + std::unordered_map _fileCache; + std::mutex _jsonHelperMutex; + + // Returns nullptr if unsuccessful + JsonFile *_load_json_from_cache(const fs::path &filepath); + +}; diff --git a/tools/dkr_assets_tool_src/helpers/miscHelper.cpp b/tools/dkr_assets_tool_src/helpers/miscHelper.cpp new file mode 100644 index 00000000..1b694dfc --- /dev/null +++ b/tools/dkr_assets_tool_src/helpers/miscHelper.cpp @@ -0,0 +1,54 @@ +#include "miscHelper.h" + +void MiscHelper::process_cheats_encryption(uint8_t *data, size_t dataSize) { + uint8_t a, b, c, d; + uint32_t sp0, sp1, sp2, sp3; + + size_t numWords = dataSize / 4; + for(size_t i = 0; i < numWords; i++) { + size_t offset = i * 4; + a = (data[offset + 3] & 0xC0) >> 6; + b = (data[offset + 0] & 0xC0); + c = (data[offset + 1] & 0xC0) >> 2; + d = (data[offset + 2] & 0xC0) >> 4; + sp0 = a | b | c | d; + + a = (data[offset + 3] & 0x30) >> 4; + b = (data[offset + 0] & 0x30) << 2; + c = (data[offset + 1] & 0x30); + d = (data[offset + 2] & 0x30) >> 2; + sp1 = a | b | c | d; + + a = (data[offset + 3] & 0x0C) >> 2; + b = (data[offset + 0] & 0x0C) << 4; + c = (data[offset + 1] & 0x0C) << 2; + d = (data[offset + 2] & 0x0C); + sp2 = a | b | c | d; + + a = (data[offset + 3] & 0x03); + b = (data[offset + 0] ) << 6; + c = (data[offset + 1] & 0x03) << 4; + d = (data[offset + 2] & 0x03) << 2; + sp3 = a | b | c | d; + + a = (sp0 & 0xAA) >> 1; + b = (sp0 & 0x55) << 1; + data[offset + 0] = a | b; + + a = (sp1 & 0xAA) >> 1; + b = (sp1 & 0x55) << 1; + data[offset + 1] = a | b; + + a = (sp2 & 0xAA) >> 1; + b = (sp2 & 0x55) << 1; + data[offset + 2] = a | b; + + a = (sp3 & 0xAA) >> 1; + b = (sp3 & 0x55) << 1; + data[offset + 3] = a | b; + } +} + +void MiscHelper::process_cheats_encryption(std::vector &data) { + process_cheats_encryption(&data[0], data.size()); +} \ No newline at end of file diff --git a/tools/dkr_assets_tool_src/helpers/miscHelper.h b/tools/dkr_assets_tool_src/helpers/miscHelper.h new file mode 100644 index 00000000..2ed1ebf6 --- /dev/null +++ b/tools/dkr_assets_tool_src/helpers/miscHelper.h @@ -0,0 +1,11 @@ + #pragma once + +#include +#include +#include + +class MiscHelper { +public: + static void process_cheats_encryption(uint8_t *data, size_t dataSize); + static void process_cheats_encryption(std::vector &data); +}; diff --git a/tools/dkr_assets_tool_src/helpers/regex/match.cpp b/tools/dkr_assets_tool_src/helpers/regex/match.cpp new file mode 100644 index 00000000..8feebd01 --- /dev/null +++ b/tools/dkr_assets_tool_src/helpers/regex/match.cpp @@ -0,0 +1,43 @@ +#include "match.h" + +RegexMatchGroup::RegexMatchGroup(std::string &text, int offset) : _text(text), _offset(offset) { +} + +RegexMatchGroup::~RegexMatchGroup() { +} + +std::string RegexMatchGroup::get_text() { + return _text; +} + +size_t RegexMatchGroup::get_text_length() { + return _text.length(); +} + +int RegexMatchGroup::get_offset() { + return _offset; +} + +RegexMatch::RegexMatch() { +} + +RegexMatch::~RegexMatch() { +} + +size_t RegexMatch::group_count() { + return _groups.size(); +} + +std::string EMPTY_STRING = ""; +RegexMatchGroup EMPTY_GROUP(EMPTY_STRING, -1); + +RegexMatchGroup &RegexMatch::get_group(size_t index) { + if(index >= _groups.size()) { + return EMPTY_GROUP; + } + return _groups[index]; +} + +void RegexMatch::_add_to_group(std::string text, size_t textOffset) { + _groups.push_back(RegexMatchGroup(text, textOffset)); +} diff --git a/tools/dkr_assets_tool_src/helpers/regex/match.h b/tools/dkr_assets_tool_src/helpers/regex/match.h new file mode 100644 index 00000000..db7b634d --- /dev/null +++ b/tools/dkr_assets_tool_src/helpers/regex/match.h @@ -0,0 +1,33 @@ +#pragma once + +#include +#include + +class RegexMatchGroup { +public: + RegexMatchGroup(std::string &text, int offset); + ~RegexMatchGroup(); + + std::string get_text(); + size_t get_text_length(); + + int get_offset(); + +private: + std::string _text; + int _offset; +}; + +class RegexMatch { +public: + RegexMatch(); + ~RegexMatch(); + size_t group_count(); + + RegexMatchGroup &get_group(size_t index); + + // This shouldn't be used outside of RegexHelper. + void _add_to_group(std::string text, size_t textOffset); +private: + std::vector _groups; +}; diff --git a/tools/dkr_assets_tool_src/helpers/regex/regexPcre2.cpp b/tools/dkr_assets_tool_src/helpers/regex/regexPcre2.cpp new file mode 100644 index 00000000..7c43b47c --- /dev/null +++ b/tools/dkr_assets_tool_src/helpers/regex/regexPcre2.cpp @@ -0,0 +1,245 @@ +/** + * PCRE2 version of the regex helper + */ + +#include "regexPcre2.h" + +#include "helpers/debugHelper.h" + +class PCRE2Cache { +public: + static PCRE2Cache& get() { + static PCRE2Cache instance; + return instance; + } + + pcre2_code *compile_regex(const std::string ®ex) { + if(_cache.find(regex) == _cache.end()) { + pcre2_code *re; + int errorcode; + PCRE2_SIZE erroroffset; + re = pcre2_compile( + (PCRE2_SPTR)regex.c_str(), + (PCRE2_SIZE)regex.size(), + PCRE2_MULTILINE, + &errorcode, + &erroroffset, + NULL + ); + _cache[regex] = re; + } + return _cache[regex]; + } + +private: + std::unordered_map _cache; + +}; + +void RegexHelperPcre2::get_matches(const std::string &input, const std::string ®exInput, std::vector &out, int startOffset) { + pcre2_code *re = PCRE2Cache::get().compile_regex(regexInput); + + pcre2_match_context *mcontext = pcre2_match_context_create(NULL); + pcre2_match_data *match_data = pcre2_match_data_create_from_pattern(re, NULL); + PCRE2_SPTR subjectSPTR = (PCRE2_SPTR)input.c_str(); + PCRE2_SIZE subjectLength = (PCRE2_SIZE)input.size(); + PCRE2_SIZE startPos = startOffset; + + while(startPos < subjectLength) { + int numberOfGroups = pcre2_match( + re, + subjectSPTR, + subjectLength, + startPos, + 0, + match_data, + mcontext + ); + + if(numberOfGroups < 2) { + break; + } + + RegexMatch newMatch; + + for(int i = 0; i < numberOfGroups; i++) { + int start = (int)pcre2_get_ovector_pointer(match_data)[2 * i]; + int end = (int)pcre2_get_ovector_pointer(match_data)[2 * i + 1]; + if(start < 0) { + newMatch._add_to_group("", -1); + continue; + } + std::string groupMatch; + size_t groupLen = end - start; + if((size_t)start < input.length() && groupLen > 0) { + groupMatch = input.substr(start, groupLen); + } + int position = start - startPos; + newMatch._add_to_group(groupMatch, position); + } + + out.push_back(newMatch); + + // Set the next start position to the end of the matched string. + startPos = pcre2_get_ovector_pointer(match_data)[1]; + } + + pcre2_match_data_free(match_data); + pcre2_match_context_free(mcontext); +} + +RegexMatch *RegexHelperPcre2::get_first_match(const std::string &input, const std::string ®exInput, int startOffset) { + pcre2_code *re = PCRE2Cache::get().compile_regex(regexInput); + + pcre2_match_context *mcontext = pcre2_match_context_create(NULL); + pcre2_match_data *match_data = pcre2_match_data_create_from_pattern(re, NULL); + PCRE2_SPTR subjectSPTR = (PCRE2_SPTR)input.c_str(); + PCRE2_SIZE subjectLength = (PCRE2_SIZE)input.size(); + + int numberOfGroups = pcre2_match( + re, + subjectSPTR, + subjectLength, + startOffset, + 0, + match_data, + mcontext + ); + + if(numberOfGroups < 2) { + return nullptr; + } + + RegexMatch *newMatch = new RegexMatch(); + + for(int i = 0; i < numberOfGroups; i++) { + int start = (int)pcre2_get_ovector_pointer(match_data)[2 * i]; + int end = (int)pcre2_get_ovector_pointer(match_data)[2 * i + 1]; + if(start < 0) { + newMatch->_add_to_group("", -1); + continue; + } + std::string groupMatch; + size_t groupLen = end - start; + if((size_t)start < input.length() && groupLen > 0) { + groupMatch = input.substr(start, groupLen); + } + int position = start - startOffset; + newMatch->_add_to_group(groupMatch, position); + } + + pcre2_match_data_free(match_data); + pcre2_match_context_free(mcontext); + + return newMatch; +} + +std::string RegexHelperPcre2::get_name() { + return "PCRE2"; +}; + +/* +void RegexHelper::get_matches(const std::string &input, const std::string ®exInput, std::vector &out, int startOffset) { + pcre2_code *re = PCRE2Cache::get().compile_regex(regexInput); + + pcre2_match_context *mcontext = pcre2_match_context_create(NULL); + pcre2_match_data *match_data = pcre2_match_data_create_from_pattern(re, NULL); + PCRE2_SPTR subjectSPTR = (PCRE2_SPTR)input.c_str(); + PCRE2_SIZE subjectLength = (PCRE2_SIZE)input.size(); + PCRE2_SIZE startPos = startOffset; + + while(startPos < subjectLength) { + size_t numberOfGroups = pcre2_match( + re, + subjectSPTR, + subjectLength, + startPos, + 0, + match_data, + mcontext + ); + + if(numberOfGroups < 2) { + break; + } + + RegexMatch newMatch; + + for(size_t i = 0; i < numberOfGroups; i++) { + int start = (int)pcre2_get_ovector_pointer(match_data)[2 * i]; + int end = (int)pcre2_get_ovector_pointer(match_data)[2 * i + 1]; + if(start < 0) { + newMatch._add_to_group("", 0); + continue; + } + //DebugHelper::info("start = ", start, ", end = ", end); + std::string groupMatch; + if((size_t)start < input.length() && end - start > 0) { + groupMatch = input.substr(start, end - start); + } + int position = std::max(0, start); + newMatch._add_to_group(groupMatch, position); + //DebugHelper::info(groupMatch); + } + + out.push_back(newMatch); + + // Set the next start position to the end of the matched string. + startPos = pcre2_get_ovector_pointer(match_data)[1] + 1; + } + + pcre2_match_data_free(match_data); + pcre2_match_context_free(mcontext); + + //DebugHelper::info("matchResult: ", matchResult); +} + +RegexMatch *RegexHelper::get_first_match(const std::string &input, const std::string ®exInput, int startOffset) { + pcre2_code *re = PCRE2Cache::get().compile_regex(regexInput); + + pcre2_match_context *mcontext = pcre2_match_context_create(NULL); + pcre2_match_data *match_data = pcre2_match_data_create_from_pattern(re, NULL); + PCRE2_SPTR subjectSPTR = (PCRE2_SPTR)input.c_str(); + PCRE2_SIZE subjectLength = (PCRE2_SIZE)input.size(); + + size_t numberOfGroups = pcre2_match( + re, + subjectSPTR, + subjectLength, + startOffset, + 0, + match_data, + mcontext + ); + + if(numberOfGroups < 2) { + return nullptr; + } + + RegexMatch *newMatch = new RegexMatch(); + + for(size_t i = 0; i < numberOfGroups; i++) { + int start = (int)pcre2_get_ovector_pointer(match_data)[2 * i]; + int end = (int)pcre2_get_ovector_pointer(match_data)[2 * i + 1]; + if(start < 0) { + newMatch->_add_to_group("", 0); + continue; + } + //DebugHelper::info("start = ", start, ", end = ", end); + + std::string groupMatch; + if((size_t)start < input.length() && end - start > 0) { + groupMatch = input.substr(start, end - start); + } + int position = std::max(0, start - startOffset); + newMatch->_add_to_group(groupMatch, position); + //DebugHelper::info(groupMatch); + } + + pcre2_match_data_free(match_data); + pcre2_match_context_free(mcontext); + + //DebugHelper::error("(RegexHelper::get_first_match) PCRE2 version not implemeted!"); + return newMatch; +} +*/ \ No newline at end of file diff --git a/tools/dkr_assets_tool_src/helpers/regex/regexPcre2.h b/tools/dkr_assets_tool_src/helpers/regex/regexPcre2.h new file mode 100644 index 00000000..6833170d --- /dev/null +++ b/tools/dkr_assets_tool_src/helpers/regex/regexPcre2.h @@ -0,0 +1,18 @@ +/** + * PCRE2 version of the regex helper + */ + +#define PCRE2_CODE_UNIT_WIDTH 8 +#include + +#include +#include + +#include "match.h" + +class RegexHelperPcre2 { +public: + static void get_matches(const std::string &input, const std::string ®exInput, std::vector &out, int startOffset); + static RegexMatch *get_first_match(const std::string &input, const std::string ®exInput, int startOffset); + static std::string get_name(); +}; diff --git a/tools/dkr_assets_tool_src/helpers/regex/regexStd.cpp b/tools/dkr_assets_tool_src/helpers/regex/regexStd.cpp new file mode 100644 index 00000000..0f607cf4 --- /dev/null +++ b/tools/dkr_assets_tool_src/helpers/regex/regexStd.cpp @@ -0,0 +1,50 @@ +/** + * C++11 std version of the regex helper +*/ + +#include "regexStd.h" +#include "helpers/debugHelper.h" + +void RegexHelperStl::get_matches(const std::string &input, const std::string ®exInput, std::vector &out, int startOffset) { + std::regex rgx(regexInput, std::regex_constants::ECMAScript); + std::smatch matches; + std::string::const_iterator searchStart(input.cbegin() + startOffset); + while (std::regex_search(searchStart, input.cend(), matches, rgx)) { + RegexMatch newMatch; + for (size_t i = 0; i < matches.size(); i++) { + std::string text = matches[i].str(); + int pos = matches.position(i); + if(text.empty()) { + pos = -1; + } + newMatch._add_to_group(text, pos); + } + out.push_back(newMatch); + searchStart = matches.suffix().first; + } +} + +RegexMatch *RegexHelperStl::get_first_match(const std::string &input, const std::string ®exInput, int startOffset) { + std::regex rgx(regexInput, std::regex_constants::ECMAScript); + std::smatch matches; + std::string::const_iterator searchStart(input.cbegin() + startOffset); + std::regex_search(searchStart, input.cend(), matches, rgx); + + if(matches.size() < 1) { + return nullptr; // No matches found. + } + RegexMatch *newMatch = new RegexMatch(); + for (size_t i = 0; i < matches.size(); i++) { + std::string text = matches[i].str(); + int pos = matches.position(i); + if(text.empty()) { + pos = -1; + } + newMatch->_add_to_group(text, pos); + } + return newMatch; +} + +std::string RegexHelperStl::get_name() { + return "C++11 STL"; +}; diff --git a/tools/dkr_assets_tool_src/helpers/regex/regexStd.h b/tools/dkr_assets_tool_src/helpers/regex/regexStd.h new file mode 100644 index 00000000..c2479cef --- /dev/null +++ b/tools/dkr_assets_tool_src/helpers/regex/regexStd.h @@ -0,0 +1,15 @@ +/** + * C++11 std version of the regex helper +*/ + +#include +#include + +#include "match.h" + +class RegexHelperStl { +public: + static void get_matches(const std::string &input, const std::string ®exInput, std::vector &out, int startOffset); + static RegexMatch *get_first_match(const std::string &input, const std::string ®exInput, int startOffset); + static std::string get_name(); +}; diff --git a/tools/dkr_assets_tool_src/helpers/regexHelper.cpp b/tools/dkr_assets_tool_src/helpers/regexHelper.cpp new file mode 100644 index 00000000..2b8bfc65 --- /dev/null +++ b/tools/dkr_assets_tool_src/helpers/regexHelper.cpp @@ -0,0 +1,71 @@ +#include "regexHelper.h" +#include "helpers/debugHelper.h" + +#define HAS_PCRE2 __has_include () + +#if HAS_PCRE2 +#include "regex/regexPcre2.h" +#endif + +// default +#include "regex/regexStd.h" + +RegexHelper::RegexHelper() { +#if HAS_PCRE2 + // Set the default engine to PCRE2 if avaliable. + _currentEngine = RegexEngine::PCRE2; +#else + _currentEngine = RegexEngine::STL; +#endif +} + +void RegexHelper::get_matches(const std::string &input, const std::string ®exInput, std::vector &out, int startOffset) { + RegexEngine engine = RegexHelper::get()._currentEngine; + switch(engine){ + case RegexEngine::STL: + RegexHelperStl::get_matches(input, regexInput, out, startOffset); + break; +#if HAS_PCRE2 + case RegexEngine::PCRE2: + RegexHelperPcre2::get_matches(input, regexInput, out, startOffset); + break; +#endif + } +} + +RegexMatch *RegexHelper::get_first_match(const std::string &input, const std::string ®exInput, int startOffset) { + RegexEngine engine = RegexHelper::get()._currentEngine; + switch(engine){ + case RegexEngine::STL: + return RegexHelperStl::get_first_match(input, regexInput, startOffset); +#if HAS_PCRE2 + case RegexEngine::PCRE2: + return RegexHelperPcre2::get_first_match(input, regexInput, startOffset); +#endif + } + return nullptr; +} + +bool RegexHelper::set_engine(RegexEngine engine) { + #if !HAS_PCRE2 + if(engine == RegexEngine::PCRE2) { + DebugHelper::warn("(RegexHelper::set_engine) Your computer does not have PCRE2 installed!"); + return false; + } + #endif + RegexHelper::get()._currentEngine = engine; + return true; +} + +std::string RegexHelper::get_current_engine_name() { + RegexEngine engine = RegexHelper::get()._currentEngine; + switch(engine){ + case RegexEngine::STL: + return RegexHelperStl::get_name(); +#if HAS_PCRE2 + case RegexEngine::PCRE2: + return RegexHelperPcre2::get_name(); +#endif + } + return ""; +} diff --git a/tools/dkr_assets_tool_src/helpers/regexHelper.h b/tools/dkr_assets_tool_src/helpers/regexHelper.h new file mode 100644 index 00000000..fbdef496 --- /dev/null +++ b/tools/dkr_assets_tool_src/helpers/regexHelper.h @@ -0,0 +1,32 @@ +#pragma once + +#include +#include + +#include "regex/match.h" + +// Supported regex engine libraries +enum RegexEngine { + STL, // standard C++11 library + PCRE2 +}; + +class RegexHelper { +public: + static RegexHelper& get() { + static RegexHelper instance; + return instance; + } + + RegexHelper(); + + static void get_matches(const std::string &input, const std::string ®exInput, std::vector &out, int startOffset = 0); + + static RegexMatch *get_first_match(const std::string &input, const std::string ®exInput, int startOffset = 0); + + static bool set_engine(RegexEngine engine); + + static std::string get_current_engine_name(); +private: + RegexEngine _currentEngine; +}; diff --git a/tools/dkr_assets_tool_src/helpers/stringHelper.cpp b/tools/dkr_assets_tool_src/helpers/stringHelper.cpp new file mode 100644 index 00000000..b6fb51ac --- /dev/null +++ b/tools/dkr_assets_tool_src/helpers/stringHelper.cpp @@ -0,0 +1,142 @@ +#include "stringHelper.h" + +#include "helpers/debugHelper.h" + +#include +#include +#include // for std::strchr + +bool StringHelper::has(const std::string &input, const char* substring) { + return input.find(substring) != std::string::npos; +} + +void StringHelper::make_lowercase(std::string& input) { + for(char& character : input) { + character = std::tolower(character); + } +} + +void StringHelper::make_uppercase(std::string& input) { + for(char& character : input) { + character = std::toupper(character); + } +} + +bool StringHelper::starts_with(const std::string &input, const std::string &sub) { + return input.rfind(sub, 0) == 0; +} + +bool StringHelper::ends_with(const std::string &input, const std::string &sub) { + if (sub.size() > input.size()) return false; + return std::equal(input.begin() + input.size() - sub.size(), input.end(), sub.begin()); +} + +const char* WHITESPACE = " \t\n\r\f\v"; + +void StringHelper::rtrim(std::string& input) { + input.erase(input.find_last_not_of(WHITESPACE) + 1); +} + +void StringHelper::ltrim(std::string& input) { + input.erase(0, input.find_first_not_of(WHITESPACE)); +} + +void StringHelper::trim(std::string& input) { + ltrim(input); + rtrim(input); +} + +void StringHelper::remove_all_whitespace(std::string &input) { + input.erase(std::remove_if(input.begin(), input.end(), [](char c) { + return std::strchr(WHITESPACE, c) != nullptr; + }), input.end()); +} + +void StringHelper::replace(std::string &input, std::string oldPattern, std::string newPattern) { + size_t pos = 0; + while((pos = input.find(oldPattern, pos)) != std::string::npos) { + input.replace(pos, oldPattern.length(), newPattern); + pos += newPattern.length(); + } +} + +void StringHelper::split(std::string &input, const char delim, std::vector &out) { + std::stringstream ss(input); + std::string s; + while (std::getline(ss, s, delim)) { + out.push_back(s); + } +} + +void StringHelper::split_and_trim(std::string &input, const char delim, std::vector &out) { + std::stringstream ss(input); + std::string s; + while (std::getline(ss, s, delim)) { + trim(s); + out.push_back(s); + } +} + +int StringHelper::find_closing_brace(const std::string &input, int inputOffset) { + int curOffset = inputOffset; + int limit = input.length(); + + bool encounteredOpeningBrace = false; + int depth = 0; + while(curOffset < limit) { + char inputChar = input[curOffset]; + switch(inputChar) { + case '{': + encounteredOpeningBrace = true; + depth++; + break; + case '}': + DebugHelper::assert(encounteredOpeningBrace, "(StringHelper::find_closing_brace) Got closing brace before an open one!"); + depth--; + if(depth < 1) { + return curOffset; + } + break; + } + curOffset++; + } + + // Could not find a closing brace! + return -1; +} + +std::string StringHelper::upper_snake_case_to_pascal_case(const std::string &input) { + std::stringstream out; + bool isFirst = true; + for(size_t i = 0; i < input.length(); i++) { + if(input[i] == '_') { + isFirst = true; + } else { + if(isFirst) { + out << input[i]; + isFirst = false; + } else { + out << (char)tolower(input[i]); + } + } + } + + return out.str(); +} + +std::string StringHelper::to_hex(uint64_t value, int numDigits) { + std::stringstream ss; + ss << std::hex; + if(numDigits > 0) { + ss << std::setw(numDigits) << std::setfill('0'); + } + ss << value; + return ss.str(); +} + +// Returns offset + length of string + 1 (for null-terminator) +size_t StringHelper::get_ascii_from_data(std::vector &data, size_t offset, std::string &out) { + char *dataAsStr = reinterpret_cast(&data[offset]); + out = std::string(dataAsStr); + return offset + out.length() + 1; +} \ No newline at end of file diff --git a/tools/dkr_assets_tool_src/helpers/stringHelper.h b/tools/dkr_assets_tool_src/helpers/stringHelper.h new file mode 100644 index 00000000..32b42fcb --- /dev/null +++ b/tools/dkr_assets_tool_src/helpers/stringHelper.h @@ -0,0 +1,40 @@ +#pragma once + +#include +#include + +// These are functions that I would've expected to be a part of std::string. (Except for a few) +class StringHelper { +public: + static bool has(const std::string &input, const char* substring); + + static void make_lowercase(std::string &input); + static void make_uppercase(std::string &input); + + static bool starts_with(const std::string &input, const std::string &sub); + static bool ends_with(const std::string &input, const std::string &sub); + + // Trim functions from: https://stackoverflow.com/a/25385766 + static void rtrim(std::string &input); // Trim whitespace from the end of the string + static void ltrim(std::string &input); // Trim whitespace from the start of the string + static void trim(std::string &input); // Trim whitespace from both sides + + static void remove_all_whitespace(std::string &input); + + static void replace(std::string &input, std::string oldPattern, std::string newPattern); + + // Splits the input string by a single character into out, so "A,B,C" would be put into [A,B,C]. input is NOT modified! + static void split(std::string &input, const char delim, std::vector &out); + static void split_and_trim(std::string &input, const char delim, std::vector &out); + + // Returns the index of the closing brace of the first opening brace encountered. Or -1 if none was encountered. + static int find_closing_brace(const std::string &input, int inputOffset=0); + + // Converts `FOO_BAR` to `FooBar`. + static std::string upper_snake_case_to_pascal_case(const std::string &input); + + static std::string to_hex(uint64_t value, int numDigits=0); + + // Returns offset + length of string + 1 (for null-terminator) + static size_t get_ascii_from_data(std::vector &data, size_t offset, std::string &out); +}; diff --git a/tools/dkr_assets_tool_classes/libs/ThreadPool.h b/tools/dkr_assets_tool_src/libs/ThreadPool.h similarity index 98% rename from tools/dkr_assets_tool_classes/libs/ThreadPool.h rename to tools/dkr_assets_tool_src/libs/ThreadPool.h index 3c051dc3..c83f07bb 100644 --- a/tools/dkr_assets_tool_classes/libs/ThreadPool.h +++ b/tools/dkr_assets_tool_src/libs/ThreadPool.h @@ -1,3 +1,5 @@ +// https://github.com/progschj/ThreadPool + #ifndef THREAD_POOL_H #define THREAD_POOL_H diff --git a/tools/dkr_assets_tool_src/libs/argparse.hpp b/tools/dkr_assets_tool_src/libs/argparse.hpp new file mode 100644 index 00000000..6f395fdc --- /dev/null +++ b/tools/dkr_assets_tool_src/libs/argparse.hpp @@ -0,0 +1,2183 @@ +/* + __ _ _ __ __ _ _ __ __ _ _ __ ___ ___ + / _` | '__/ _` | '_ \ / _` | '__/ __|/ _ \ Argument Parser for Modern C++ +| (_| | | | (_| | |_) | (_| | | \__ \ __/ http://github.com/p-ranav/argparse + \__,_|_| \__, | .__/ \__,_|_| |___/\___| + |___/|_| + +Licensed under the MIT License . +SPDX-License-Identifier: MIT +Copyright (c) 2019-2022 Pranav Srinivas Kumar +and other 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. +*/ +#pragma once + +#ifndef ARGPARSE_MODULE_USE_STD_MODULE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +namespace argparse { + +namespace details { // namespace for helper methods + +template +struct HasContainerTraits : std::false_type {}; + +template <> struct HasContainerTraits : std::false_type {}; + +template <> struct HasContainerTraits : std::false_type {}; + +template +struct HasContainerTraits< + T, std::void_t().begin()), + decltype(std::declval().end()), + decltype(std::declval().size())>> : std::true_type {}; + +template +inline constexpr bool IsContainer = HasContainerTraits::value; + +template +struct HasStreamableTraits : std::false_type {}; + +template +struct HasStreamableTraits< + T, + std::void_t() << std::declval())>> + : std::true_type {}; + +template +inline constexpr bool IsStreamable = HasStreamableTraits::value; + +constexpr std::size_t repr_max_container_size = 5; + +template std::string repr(T const &val) { + if constexpr (std::is_same_v) { + return val ? "true" : "false"; + } else if constexpr (std::is_convertible_v) { + return '"' + std::string{std::string_view{val}} + '"'; + } else if constexpr (IsContainer) { + std::stringstream out; + out << "{"; + const auto size = val.size(); + if (size > 1) { + out << repr(*val.begin()); + std::for_each( + std::next(val.begin()), + std::next( + val.begin(), + static_cast( + std::min(size, repr_max_container_size) - 1)), + [&out](const auto &v) { out << " " << repr(v); }); + if (size <= repr_max_container_size) { + out << " "; + } else { + out << "..."; + } + } + if (size > 0) { + out << repr(*std::prev(val.end())); + } + out << "}"; + return out.str(); + } else if constexpr (IsStreamable) { + std::stringstream out; + out << val; + return out.str(); + } else { + return ""; + } +} + +namespace { + +template constexpr bool standard_signed_integer = false; +template <> constexpr bool standard_signed_integer = true; +template <> constexpr bool standard_signed_integer = true; +template <> constexpr bool standard_signed_integer = true; +template <> constexpr bool standard_signed_integer = true; +template <> constexpr bool standard_signed_integer = true; + +template constexpr bool standard_unsigned_integer = false; +template <> constexpr bool standard_unsigned_integer = true; +template <> constexpr bool standard_unsigned_integer = true; +template <> constexpr bool standard_unsigned_integer = true; +template <> constexpr bool standard_unsigned_integer = true; +template <> +constexpr bool standard_unsigned_integer = true; + +} // namespace + +constexpr int radix_2 = 2; +constexpr int radix_8 = 8; +constexpr int radix_10 = 10; +constexpr int radix_16 = 16; + +template +constexpr bool standard_integer = + standard_signed_integer || standard_unsigned_integer; + +template +constexpr decltype(auto) +apply_plus_one_impl(F &&f, Tuple &&t, Extra &&x, + std::index_sequence /*unused*/) { + return std::invoke(std::forward(f), std::get(std::forward(t))..., + std::forward(x)); +} + +template +constexpr decltype(auto) apply_plus_one(F &&f, Tuple &&t, Extra &&x) { + return details::apply_plus_one_impl( + std::forward(f), std::forward(t), std::forward(x), + std::make_index_sequence< + std::tuple_size_v>>{}); +} + +constexpr auto pointer_range(std::string_view s) noexcept { + return std::tuple(s.data(), s.data() + s.size()); +} + +template +constexpr bool starts_with(std::basic_string_view prefix, + std::basic_string_view s) noexcept { + return s.substr(0, prefix.size()) == prefix; +} + +enum class chars_format { + scientific = 0xf1, + fixed = 0xf2, + hex = 0xf4, + binary = 0xf8, + general = fixed | scientific +}; + +struct ConsumeBinaryPrefixResult { + bool is_binary; + std::string_view rest; +}; + +constexpr auto consume_binary_prefix(std::string_view s) + -> ConsumeBinaryPrefixResult { + if (starts_with(std::string_view{"0b"}, s) || + starts_with(std::string_view{"0B"}, s)) { + s.remove_prefix(2); + return {true, s}; + } + return {false, s}; +} + +struct ConsumeHexPrefixResult { + bool is_hexadecimal; + std::string_view rest; +}; + +using namespace std::literals; + +constexpr auto consume_hex_prefix(std::string_view s) + -> ConsumeHexPrefixResult { + if (starts_with("0x"sv, s) || starts_with("0X"sv, s)) { + s.remove_prefix(2); + return {true, s}; + } + return {false, s}; +} + +template +inline auto do_from_chars(std::string_view s) -> T { + T x; + auto [first, last] = pointer_range(s); + auto [ptr, ec] = std::from_chars(first, last, x, Param); + if (ec == std::errc()) { + if (ptr == last) { + return x; + } + throw std::invalid_argument{"pattern '" + std::string(s) + + "' does not match to the end"}; + } + if (ec == std::errc::invalid_argument) { + throw std::invalid_argument{"pattern '" + std::string(s) + "' not found"}; + } + if (ec == std::errc::result_out_of_range) { + throw std::range_error{"'" + std::string(s) + "' not representable"}; + } + return x; // unreachable +} + +template struct parse_number { + auto operator()(std::string_view s) -> T { + return do_from_chars(s); + } +}; + +template struct parse_number { + auto operator()(std::string_view s) -> T { + if (auto [ok, rest] = consume_binary_prefix(s); ok) { + return do_from_chars(rest); + } + throw std::invalid_argument{"pattern not found"}; + } +}; + +template struct parse_number { + auto operator()(std::string_view s) -> T { + if (starts_with("0x"sv, s) || starts_with("0X"sv, s)) { + if (auto [ok, rest] = consume_hex_prefix(s); ok) { + try { + return do_from_chars(rest); + } catch (const std::invalid_argument &err) { + throw std::invalid_argument("Failed to parse '" + std::string(s) + + "' as hexadecimal: " + err.what()); + } catch (const std::range_error &err) { + throw std::range_error("Failed to parse '" + std::string(s) + + "' as hexadecimal: " + err.what()); + } + } + } else { + // Allow passing hex numbers without prefix + // Shape 'x' already has to be specified + try { + return do_from_chars(s); + } catch (const std::invalid_argument &err) { + throw std::invalid_argument("Failed to parse '" + std::string(s) + + "' as hexadecimal: " + err.what()); + } catch (const std::range_error &err) { + throw std::range_error("Failed to parse '" + std::string(s) + + "' as hexadecimal: " + err.what()); + } + } + + throw std::invalid_argument{"pattern '" + std::string(s) + + "' not identified as hexadecimal"}; + } +}; + +template struct parse_number { + auto operator()(std::string_view s) -> T { + auto [ok, rest] = consume_hex_prefix(s); + if (ok) { + try { + return do_from_chars(rest); + } catch (const std::invalid_argument &err) { + throw std::invalid_argument("Failed to parse '" + std::string(s) + + "' as hexadecimal: " + err.what()); + } catch (const std::range_error &err) { + throw std::range_error("Failed to parse '" + std::string(s) + + "' as hexadecimal: " + err.what()); + } + } + + auto [ok_binary, rest_binary] = consume_binary_prefix(s); + if (ok_binary) { + try { + return do_from_chars(rest_binary); + } catch (const std::invalid_argument &err) { + throw std::invalid_argument("Failed to parse '" + std::string(s) + + "' as binary: " + err.what()); + } catch (const std::range_error &err) { + throw std::range_error("Failed to parse '" + std::string(s) + + "' as binary: " + err.what()); + } + } + + if (starts_with("0"sv, s)) { + try { + return do_from_chars(rest); + } catch (const std::invalid_argument &err) { + throw std::invalid_argument("Failed to parse '" + std::string(s) + + "' as octal: " + err.what()); + } catch (const std::range_error &err) { + throw std::range_error("Failed to parse '" + std::string(s) + + "' as octal: " + err.what()); + } + } + + try { + return do_from_chars(rest); + } catch (const std::invalid_argument &err) { + throw std::invalid_argument("Failed to parse '" + std::string(s) + + "' as decimal integer: " + err.what()); + } catch (const std::range_error &err) { + throw std::range_error("Failed to parse '" + std::string(s) + + "' as decimal integer: " + err.what()); + } + } +}; + +namespace { + +template inline const auto generic_strtod = nullptr; +template <> inline const auto generic_strtod = strtof; +template <> inline const auto generic_strtod = strtod; +template <> inline const auto generic_strtod = strtold; + +} // namespace + +template inline auto do_strtod(std::string const &s) -> T { + if (isspace(static_cast(s[0])) || s[0] == '+') { + throw std::invalid_argument{"pattern '" + s + "' not found"}; + } + + auto [first, last] = pointer_range(s); + char *ptr; + + errno = 0; + auto x = generic_strtod(first, &ptr); + if (errno == 0) { + if (ptr == last) { + return x; + } + throw std::invalid_argument{"pattern '" + s + + "' does not match to the end"}; + } + if (errno == ERANGE) { + throw std::range_error{"'" + s + "' not representable"}; + } + return x; // unreachable +} + +template struct parse_number { + auto operator()(std::string const &s) -> T { + if (auto r = consume_hex_prefix(s); r.is_hexadecimal) { + throw std::invalid_argument{ + "chars_format::general does not parse hexfloat"}; + } + if (auto r = consume_binary_prefix(s); r.is_binary) { + throw std::invalid_argument{ + "chars_format::general does not parse binfloat"}; + } + + try { + return do_strtod(s); + } catch (const std::invalid_argument &err) { + throw std::invalid_argument("Failed to parse '" + s + + "' as number: " + err.what()); + } catch (const std::range_error &err) { + throw std::range_error("Failed to parse '" + s + + "' as number: " + err.what()); + } + } +}; + +template struct parse_number { + auto operator()(std::string const &s) -> T { + if (auto r = consume_hex_prefix(s); !r.is_hexadecimal) { + throw std::invalid_argument{"chars_format::hex parses hexfloat"}; + } + if (auto r = consume_binary_prefix(s); r.is_binary) { + throw std::invalid_argument{"chars_format::hex does not parse binfloat"}; + } + + try { + return do_strtod(s); + } catch (const std::invalid_argument &err) { + throw std::invalid_argument("Failed to parse '" + s + + "' as hexadecimal: " + err.what()); + } catch (const std::range_error &err) { + throw std::range_error("Failed to parse '" + s + + "' as hexadecimal: " + err.what()); + } + } +}; + +template struct parse_number { + auto operator()(std::string const &s) -> T { + if (auto r = consume_hex_prefix(s); r.is_hexadecimal) { + throw std::invalid_argument{ + "chars_format::binary does not parse hexfloat"}; + } + if (auto r = consume_binary_prefix(s); !r.is_binary) { + throw std::invalid_argument{"chars_format::binary parses binfloat"}; + } + + return do_strtod(s); + } +}; + +template struct parse_number { + auto operator()(std::string const &s) -> T { + if (auto r = consume_hex_prefix(s); r.is_hexadecimal) { + throw std::invalid_argument{ + "chars_format::scientific does not parse hexfloat"}; + } + if (auto r = consume_binary_prefix(s); r.is_binary) { + throw std::invalid_argument{ + "chars_format::scientific does not parse binfloat"}; + } + if (s.find_first_of("eE") == std::string::npos) { + throw std::invalid_argument{ + "chars_format::scientific requires exponent part"}; + } + + try { + return do_strtod(s); + } catch (const std::invalid_argument &err) { + throw std::invalid_argument("Failed to parse '" + s + + "' as scientific notation: " + err.what()); + } catch (const std::range_error &err) { + throw std::range_error("Failed to parse '" + s + + "' as scientific notation: " + err.what()); + } + } +}; + +template struct parse_number { + auto operator()(std::string const &s) -> T { + if (auto r = consume_hex_prefix(s); r.is_hexadecimal) { + throw std::invalid_argument{ + "chars_format::fixed does not parse hexfloat"}; + } + if (auto r = consume_binary_prefix(s); r.is_binary) { + throw std::invalid_argument{ + "chars_format::fixed does not parse binfloat"}; + } + if (s.find_first_of("eE") != std::string::npos) { + throw std::invalid_argument{ + "chars_format::fixed does not parse exponent part"}; + } + + try { + return do_strtod(s); + } catch (const std::invalid_argument &err) { + throw std::invalid_argument("Failed to parse '" + s + + "' as fixed notation: " + err.what()); + } catch (const std::range_error &err) { + throw std::range_error("Failed to parse '" + s + + "' as fixed notation: " + err.what()); + } + } +}; + +template +std::string join(StrIt first, StrIt last, const std::string &separator) { + if (first == last) { + return ""; + } + std::stringstream value; + value << *first; + ++first; + while (first != last) { + value << separator << *first; + ++first; + } + return value.str(); +} + +template struct can_invoke_to_string { + template + static auto test(int) + -> decltype(std::to_string(std::declval()), std::true_type{}); + + template static auto test(...) -> std::false_type; + + static constexpr bool value = decltype(test(0))::value; +}; + +template struct IsChoiceTypeSupported { + using CleanType = typename std::decay::type; + static const bool value = std::is_integral::value || + std::is_same::value || + std::is_same::value || + std::is_same::value; +}; + +template +std::size_t get_levenshtein_distance(const StringType &s1, + const StringType &s2) { + std::vector> dp( + s1.size() + 1, std::vector(s2.size() + 1, 0)); + + for (std::size_t i = 0; i <= s1.size(); ++i) { + for (std::size_t j = 0; j <= s2.size(); ++j) { + if (i == 0) { + dp[i][j] = j; + } else if (j == 0) { + dp[i][j] = i; + } else if (s1[i - 1] == s2[j - 1]) { + dp[i][j] = dp[i - 1][j - 1]; + } else { + dp[i][j] = 1 + std::min({dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]}); + } + } + } + + return dp[s1.size()][s2.size()]; +} + +template +std::string_view +get_most_similar_string(const std::map &map, + const std::string_view input) { + std::string_view most_similar{}; + std::size_t min_distance = std::numeric_limits::max(); + + for (const auto &entry : map) { + std::size_t distance = get_levenshtein_distance(entry.first, input); + if (distance < min_distance) { + min_distance = distance; + most_similar = entry.first; + } + } + + return most_similar; +} + +} // namespace details + +enum class nargs_pattern { optional, any, at_least_one }; + +enum class default_arguments : unsigned int { + none = 0, + help = 1, + version = 2, + all = help | version, +}; + +inline default_arguments operator&(const default_arguments &a, + const default_arguments &b) { + return static_cast( + static_cast::type>(a) & + static_cast::type>(b)); +} + +class ArgumentParser; + +class Argument { + friend class ArgumentParser; + friend auto operator<<(std::ostream &stream, const ArgumentParser &parser) + -> std::ostream &; + + template + explicit Argument(std::string_view prefix_chars, + std::array &&a, + std::index_sequence /*unused*/) + : m_accepts_optional_like_value(false), + m_is_optional((is_optional(a[I], prefix_chars) || ...)), + m_is_required(false), m_is_repeatable(false), m_is_used(false), + m_prefix_chars(prefix_chars) { + ((void)m_names.emplace_back(a[I]), ...); + std::sort( + m_names.begin(), m_names.end(), [](const auto &lhs, const auto &rhs) { + return lhs.size() == rhs.size() ? lhs < rhs : lhs.size() < rhs.size(); + }); + } + +public: + template + explicit Argument(std::string_view prefix_chars, + std::array &&a) + : Argument(prefix_chars, std::move(a), std::make_index_sequence{}) {} + + Argument &help(std::string help_text) { + m_help = std::move(help_text); + return *this; + } + + Argument &metavar(std::string metavar) { + m_metavar = std::move(metavar); + return *this; + } + + template Argument &default_value(T &&value) { + m_num_args_range = NArgsRange{0, m_num_args_range.get_max()}; + m_default_value_repr = details::repr(value); + + if constexpr (std::is_convertible_v) { + m_default_value_str = std::string{std::string_view{value}}; + } else if constexpr (details::can_invoke_to_string::value) { + m_default_value_str = std::to_string(value); + } + + m_default_value = std::forward(value); + return *this; + } + + Argument &default_value(const char *value) { + return default_value(std::string(value)); + } + + Argument &required() { + m_is_required = true; + return *this; + } + + Argument &implicit_value(std::any value) { + m_implicit_value = std::move(value); + m_num_args_range = NArgsRange{0, 0}; + return *this; + } + + // This is shorthand for: + // program.add_argument("foo") + // .default_value(false) + // .implicit_value(true) + Argument &flag() { + default_value(false); + implicit_value(true); + return *this; + } + + template + auto action(F &&callable, Args &&... bound_args) + -> std::enable_if_t, + Argument &> { + using action_type = std::conditional_t< + std::is_void_v>, + void_action, valued_action>; + if constexpr (sizeof...(Args) == 0) { + m_action.emplace(std::forward(callable)); + } else { + m_action.emplace( + [f = std::forward(callable), + tup = std::make_tuple(std::forward(bound_args)...)]( + std::string const &opt) mutable { + return details::apply_plus_one(f, tup, opt); + }); + } + return *this; + } + + auto &append() { + m_is_repeatable = true; + return *this; + } + + template + auto scan() -> std::enable_if_t, Argument &> { + static_assert(!(std::is_const_v || std::is_volatile_v), + "T should not be cv-qualified"); + auto is_one_of = [](char c, auto... x) constexpr { + return ((c == x) || ...); + }; + + if constexpr (is_one_of(Shape, 'd') && details::standard_integer) { + action(details::parse_number()); + } else if constexpr (is_one_of(Shape, 'i') && + details::standard_integer) { + action(details::parse_number()); + } else if constexpr (is_one_of(Shape, 'u') && + details::standard_unsigned_integer) { + action(details::parse_number()); + } else if constexpr (is_one_of(Shape, 'b') && + details::standard_unsigned_integer) { + action(details::parse_number()); + } else if constexpr (is_one_of(Shape, 'o') && + details::standard_unsigned_integer) { + action(details::parse_number()); + } else if constexpr (is_one_of(Shape, 'x', 'X') && + details::standard_unsigned_integer) { + action(details::parse_number()); + } else if constexpr (is_one_of(Shape, 'a', 'A') && + std::is_floating_point_v) { + action(details::parse_number()); + } else if constexpr (is_one_of(Shape, 'e', 'E') && + std::is_floating_point_v) { + action(details::parse_number()); + } else if constexpr (is_one_of(Shape, 'f', 'F') && + std::is_floating_point_v) { + action(details::parse_number()); + } else if constexpr (is_one_of(Shape, 'g', 'G') && + std::is_floating_point_v) { + action(details::parse_number()); + } else { + static_assert(alignof(T) == 0, "No scan specification for T"); + } + + return *this; + } + + Argument &nargs(std::size_t num_args) { + m_num_args_range = NArgsRange{num_args, num_args}; + return *this; + } + + Argument &nargs(std::size_t num_args_min, std::size_t num_args_max) { + m_num_args_range = NArgsRange{num_args_min, num_args_max}; + return *this; + } + + Argument &nargs(nargs_pattern pattern) { + switch (pattern) { + case nargs_pattern::optional: + m_num_args_range = NArgsRange{0, 1}; + break; + case nargs_pattern::any: + m_num_args_range = + NArgsRange{0, (std::numeric_limits::max)()}; + break; + case nargs_pattern::at_least_one: + m_num_args_range = + NArgsRange{1, (std::numeric_limits::max)()}; + break; + } + return *this; + } + + Argument &remaining() { + m_accepts_optional_like_value = true; + return nargs(nargs_pattern::any); + } + + template void add_choice(T &&choice) { + static_assert(details::IsChoiceTypeSupported::value, + "Only string or integer type supported for choice"); + static_assert(std::is_convertible_v || + details::can_invoke_to_string::value, + "Choice is not convertible to string_type"); + if (!m_choices.has_value()) { + m_choices = std::vector{}; + } + + if constexpr (std::is_convertible_v) { + m_choices.value().push_back( + std::string{std::string_view{std::forward(choice)}}); + } else if constexpr (details::can_invoke_to_string::value) { + m_choices.value().push_back(std::to_string(std::forward(choice))); + } + } + + Argument &choices() { + if (!m_choices.has_value()) { + throw std::runtime_error("Zero choices provided"); + } + return *this; + } + + template + Argument &choices(T &&first, U &&... rest) { + add_choice(std::forward(first)); + choices(std::forward(rest)...); + return *this; + } + + void find_default_value_in_choices_or_throw() const { + + const auto &choices = m_choices.value(); + + if (m_default_value.has_value()) { + if (std::find(choices.begin(), choices.end(), m_default_value_str) == + choices.end()) { + // provided arg not in list of allowed choices + // report error + + std::string choices_as_csv = + std::accumulate(choices.begin(), choices.end(), std::string(), + [](const std::string &a, const std::string &b) { + return a + (a.empty() ? "" : ", ") + b; + }); + + throw std::runtime_error( + std::string{"Invalid default value "} + m_default_value_repr + + " - allowed options: {" + choices_as_csv + "}"); + } + } + } + + template + void find_value_in_choices_or_throw(Iterator it) const { + + const auto &choices = m_choices.value(); + + if (std::find(choices.begin(), choices.end(), *it) == choices.end()) { + // provided arg not in list of allowed choices + // report error + + std::string choices_as_csv = + std::accumulate(choices.begin(), choices.end(), std::string(), + [](const std::string &a, const std::string &b) { + return a + (a.empty() ? "" : ", ") + b; + }); + + throw std::runtime_error(std::string{"Invalid argument "} + + details::repr(*it) + " - allowed options: {" + + choices_as_csv + "}"); + } + } + + template + Iterator consume(Iterator start, Iterator end, + std::string_view used_name = {}) { + if (!m_is_repeatable && m_is_used) { + throw std::runtime_error("Duplicate argument"); + } + m_is_used = true; + m_used_name = used_name; + + if (m_choices.has_value()) { + // Check each value in (start, end) and make sure + // it is in the list of allowed choices/options + std::size_t i = 0; + auto max_number_of_args = m_num_args_range.get_max(); + for (auto it = start; it != end; ++it) { + if (i == max_number_of_args) { + break; + } + find_value_in_choices_or_throw(it); + i += 1; + } + } + + const auto num_args_max = m_num_args_range.get_max(); + const auto num_args_min = m_num_args_range.get_min(); + std::size_t dist = 0; + if (num_args_max == 0) { + m_values.emplace_back(m_implicit_value); + std::visit([](const auto &f) { f({}); }, m_action); + return start; + } + if ((dist = static_cast(std::distance(start, end))) >= + num_args_min) { + if (num_args_max < dist) { + end = std::next(start, static_cast( + num_args_max)); + } + if (!m_accepts_optional_like_value) { + end = std::find_if( + start, end, + std::bind(is_optional, std::placeholders::_1, m_prefix_chars)); + dist = static_cast(std::distance(start, end)); + if (dist < num_args_min) { + throw std::runtime_error("Too few arguments"); + } + } + + struct ActionApply { + void operator()(valued_action &f) { + std::transform(first, last, std::back_inserter(self.m_values), f); + } + + void operator()(void_action &f) { + std::for_each(first, last, f); + if (!self.m_default_value.has_value()) { + if (!self.m_accepts_optional_like_value) { + self.m_values.resize( + static_cast(std::distance(first, last))); + } + } + } + + Iterator first, last; + Argument &self; + }; + std::visit(ActionApply{start, end, *this}, m_action); + return end; + } + if (m_default_value.has_value()) { + return start; + } + throw std::runtime_error("Too few arguments for '" + + std::string(m_used_name) + "'."); + } + + /* + * @throws std::runtime_error if argument values are not valid + */ + void validate() const { + if (m_is_optional) { + // TODO: check if an implicit value was programmed for this argument + if (!m_is_used && !m_default_value.has_value() && m_is_required) { + throw_required_arg_not_used_error(); + } + if (m_is_used && m_is_required && m_values.empty()) { + throw_required_arg_no_value_provided_error(); + } + } else { + if (!m_num_args_range.contains(m_values.size()) && + !m_default_value.has_value()) { + throw_nargs_range_validation_error(); + } + } + + if (m_choices.has_value()) { + // Make sure the default value (if provided) + // is in the list of choices + find_default_value_in_choices_or_throw(); + } + } + + std::string get_names_csv(char separator = ',') const { + return std::accumulate( + m_names.begin(), m_names.end(), std::string{""}, + [&](const std::string &result, const std::string &name) { + return result.empty() ? name : result + separator + name; + }); + } + + std::string get_usage_full() const { + std::stringstream usage; + + usage << get_names_csv('/'); + const std::string metavar = !m_metavar.empty() ? m_metavar : "VAR"; + if (m_num_args_range.get_max() > 0) { + usage << " " << metavar; + if (m_num_args_range.get_max() > 1) { + usage << "..."; + } + } + return usage.str(); + } + + std::string get_inline_usage() const { + std::stringstream usage; + // Find the longest variant to show in the usage string + std::string longest_name = m_names.front(); + for (const auto &s : m_names) { + if (s.size() > longest_name.size()) { + longest_name = s; + } + } + if (!m_is_required) { + usage << "["; + } + usage << longest_name; + const std::string metavar = !m_metavar.empty() ? m_metavar : "VAR"; + if (m_num_args_range.get_max() > 0) { + usage << " " << metavar; + if (m_num_args_range.get_max() > 1) { + usage << "..."; + } + } + if (!m_is_required) { + usage << "]"; + } + return usage.str(); + } + + std::size_t get_arguments_length() const { + + std::size_t names_size = std::accumulate( + std::begin(m_names), std::end(m_names), std::size_t(0), + [](const auto &sum, const auto &s) { return sum + s.size(); }); + + if (is_positional(m_names.front(), m_prefix_chars)) { + // A set metavar means this replaces the names + if (!m_metavar.empty()) { + // Indent and metavar + return 2 + m_metavar.size(); + } + + // Indent and space-separated + return 2 + names_size + (m_names.size() - 1); + } + // Is an option - include both names _and_ metavar + // size = text + (", " between names) + std::size_t size = names_size + 2 * (m_names.size() - 1); + if (!m_metavar.empty() && m_num_args_range == NArgsRange{1, 1}) { + size += m_metavar.size() + 1; + } + return size + 2; // indent + } + + friend std::ostream &operator<<(std::ostream &stream, + const Argument &argument) { + std::stringstream name_stream; + name_stream << " "; // indent + if (argument.is_positional(argument.m_names.front(), + argument.m_prefix_chars)) { + if (!argument.m_metavar.empty()) { + name_stream << argument.m_metavar; + } else { + name_stream << details::join(argument.m_names.begin(), + argument.m_names.end(), " "); + } + } else { + name_stream << details::join(argument.m_names.begin(), + argument.m_names.end(), ", "); + // If we have a metavar, and one narg - print the metavar + if (!argument.m_metavar.empty() && + argument.m_num_args_range == NArgsRange{1, 1}) { + name_stream << " " << argument.m_metavar; + } + } + + // align multiline help message + auto stream_width = stream.width(); + auto name_padding = std::string(name_stream.str().size(), ' '); + auto pos = std::string::size_type{}; + auto prev = std::string::size_type{}; + auto first_line = true; + auto hspace = " "; // minimal space between name and help message + stream << name_stream.str(); + std::string_view help_view(argument.m_help); + while ((pos = argument.m_help.find('\n', prev)) != std::string::npos) { + auto line = help_view.substr(prev, pos - prev + 1); + if (first_line) { + stream << hspace << line; + first_line = false; + } else { + stream.width(stream_width); + stream << name_padding << hspace << line; + } + prev += pos - prev + 1; + } + if (first_line) { + stream << hspace << argument.m_help; + } else { + auto leftover = help_view.substr(prev, argument.m_help.size() - prev); + if (!leftover.empty()) { + stream.width(stream_width); + stream << name_padding << hspace << leftover; + } + } + + // print nargs spec + if (!argument.m_help.empty()) { + stream << " "; + } + stream << argument.m_num_args_range; + + if (argument.m_default_value.has_value() && + argument.m_num_args_range != NArgsRange{0, 0}) { + stream << "[default: " << argument.m_default_value_repr << "]"; + } else if (argument.m_is_required) { + stream << "[required]"; + } + stream << "\n"; + return stream; + } + + template bool operator!=(const T &rhs) const { + return !(*this == rhs); + } + + /* + * Compare to an argument value of known type + * @throws std::logic_error in case of incompatible types + */ + template bool operator==(const T &rhs) const { + if constexpr (!details::IsContainer) { + return get() == rhs; + } else { + using ValueType = typename T::value_type; + auto lhs = get(); + return std::equal(std::begin(lhs), std::end(lhs), std::begin(rhs), + std::end(rhs), [](const auto &a, const auto &b) { + return std::any_cast(a) == b; + }); + } + } + +private: + class NArgsRange { + std::size_t m_min; + std::size_t m_max; + + public: + NArgsRange(std::size_t minimum, std::size_t maximum) + : m_min(minimum), m_max(maximum) { + if (minimum > maximum) { + throw std::logic_error("Range of number of arguments is invalid"); + } + } + + bool contains(std::size_t value) const { + return value >= m_min && value <= m_max; + } + + bool is_exact() const { return m_min == m_max; } + + bool is_right_bounded() const { + return m_max < (std::numeric_limits::max)(); + } + + std::size_t get_min() const { return m_min; } + + std::size_t get_max() const { return m_max; } + + // Print help message + friend auto operator<<(std::ostream &stream, const NArgsRange &range) + -> std::ostream & { + if (range.m_min == range.m_max) { + if (range.m_min != 0 && range.m_min != 1) { + stream << "[nargs: " << range.m_min << "] "; + } + } else { + if (range.m_max == (std::numeric_limits::max)()) { + stream << "[nargs: " << range.m_min << " or more] "; + } else { + stream << "[nargs=" << range.m_min << ".." << range.m_max << "] "; + } + } + return stream; + } + + bool operator==(const NArgsRange &rhs) const { + return rhs.m_min == m_min && rhs.m_max == m_max; + } + + bool operator!=(const NArgsRange &rhs) const { return !(*this == rhs); } + }; + + void throw_nargs_range_validation_error() const { + std::stringstream stream; + if (!m_used_name.empty()) { + stream << m_used_name << ": "; + } else { + stream << m_names.front() << ": "; + } + if (m_num_args_range.is_exact()) { + stream << m_num_args_range.get_min(); + } else if (m_num_args_range.is_right_bounded()) { + stream << m_num_args_range.get_min() << " to " + << m_num_args_range.get_max(); + } else { + stream << m_num_args_range.get_min() << " or more"; + } + stream << " argument(s) expected. " << m_values.size() << " provided."; + throw std::runtime_error(stream.str()); + } + + void throw_required_arg_not_used_error() const { + std::stringstream stream; + stream << m_names.front() << ": required."; + throw std::runtime_error(stream.str()); + } + + void throw_required_arg_no_value_provided_error() const { + std::stringstream stream; + stream << m_used_name << ": no value provided."; + throw std::runtime_error(stream.str()); + } + + static constexpr int eof = std::char_traits::eof(); + + static auto lookahead(std::string_view s) -> int { + if (s.empty()) { + return eof; + } + return static_cast(static_cast(s[0])); + } + + /* + * decimal-literal: + * '0' + * nonzero-digit digit-sequence_opt + * integer-part fractional-part + * fractional-part + * integer-part '.' exponent-part_opt + * integer-part exponent-part + * + * integer-part: + * digit-sequence + * + * fractional-part: + * '.' post-decimal-point + * + * post-decimal-point: + * digit-sequence exponent-part_opt + * + * exponent-part: + * 'e' post-e + * 'E' post-e + * + * post-e: + * sign_opt digit-sequence + * + * sign: one of + * '+' '-' + */ + static bool is_decimal_literal(std::string_view s) { + auto is_digit = [](auto c) constexpr { + switch (c) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return true; + default: + return false; + } + }; + + // precondition: we have consumed or will consume at least one digit + auto consume_digits = [=](std::string_view sd) { + // NOLINTNEXTLINE(readability-qualified-auto) + auto it = std::find_if_not(std::begin(sd), std::end(sd), is_digit); + return sd.substr(static_cast(it - std::begin(sd))); + }; + + switch (lookahead(s)) { + case '0': { + s.remove_prefix(1); + if (s.empty()) { + return true; + } + goto integer_part; + } + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': { + s = consume_digits(s); + if (s.empty()) { + return true; + } + goto integer_part_consumed; + } + case '.': { + s.remove_prefix(1); + goto post_decimal_point; + } + default: + return false; + } + + integer_part: + s = consume_digits(s); + integer_part_consumed: + switch (lookahead(s)) { + case '.': { + s.remove_prefix(1); + if (is_digit(lookahead(s))) { + goto post_decimal_point; + } else { + goto exponent_part_opt; + } + } + case 'e': + case 'E': { + s.remove_prefix(1); + goto post_e; + } + default: + return false; + } + + post_decimal_point: + if (is_digit(lookahead(s))) { + s = consume_digits(s); + goto exponent_part_opt; + } + return false; + + exponent_part_opt: + switch (lookahead(s)) { + case eof: + return true; + case 'e': + case 'E': { + s.remove_prefix(1); + goto post_e; + } + default: + return false; + } + + post_e: + switch (lookahead(s)) { + case '-': + case '+': + s.remove_prefix(1); + } + if (is_digit(lookahead(s))) { + s = consume_digits(s); + return s.empty(); + } + return false; + } + + static bool is_optional(std::string_view name, + std::string_view prefix_chars) { + return !is_positional(name, prefix_chars); + } + + /* + * positional: + * _empty_ + * '-' + * '-' decimal-literal + * !'-' anything + */ + static bool is_positional(std::string_view name, + std::string_view prefix_chars) { + auto first = lookahead(name); + + if (first == eof) { + return true; + } else if (prefix_chars.find(static_cast(first)) != + std::string_view::npos) { + name.remove_prefix(1); + if (name.empty()) { + return true; + } + return is_decimal_literal(name); + } + return true; + } + + /* + * Get argument value given a type + * @throws std::logic_error in case of incompatible types + */ + template T get() const { + if (!m_values.empty()) { + if constexpr (details::IsContainer) { + return any_cast_container(m_values); + } else { + return std::any_cast(m_values.front()); + } + } + if (m_default_value.has_value()) { + return std::any_cast(m_default_value); + } + if constexpr (details::IsContainer) { + if (!m_accepts_optional_like_value) { + return any_cast_container(m_values); + } + } + + throw std::logic_error("No value provided for '" + m_names.back() + "'."); + } + + /* + * Get argument value given a type. + * @pre The object has no default value. + * @returns The stored value if any, std::nullopt otherwise. + */ + template auto present() const -> std::optional { + if (m_default_value.has_value()) { + throw std::logic_error("Argument with default value always presents"); + } + if (m_values.empty()) { + return std::nullopt; + } + if constexpr (details::IsContainer) { + return any_cast_container(m_values); + } + return std::any_cast(m_values.front()); + } + + template + static auto any_cast_container(const std::vector &operand) -> T { + using ValueType = typename T::value_type; + + T result; + std::transform( + std::begin(operand), std::end(operand), std::back_inserter(result), + [](const auto &value) { return std::any_cast(value); }); + return result; + } + + std::vector m_names; + std::string_view m_used_name; + std::string m_help; + std::string m_metavar; + std::any m_default_value; + std::string m_default_value_repr; + std::optional + m_default_value_str; // used for checking default_value against choices + std::any m_implicit_value; + std::optional> m_choices{std::nullopt}; + using valued_action = std::function; + using void_action = std::function; + std::variant m_action{ + std::in_place_type, + [](const std::string &value) { return value; }}; + std::vector m_values; + NArgsRange m_num_args_range{1, 1}; + // Bit field of bool values. Set default value in ctor. + bool m_accepts_optional_like_value : 1; + bool m_is_optional : 1; + bool m_is_required : 1; + bool m_is_repeatable : 1; + bool m_is_used : 1; + std::string_view m_prefix_chars; // ArgumentParser has the prefix_chars +}; + +class ArgumentParser { +public: + explicit ArgumentParser(std::string program_name = {}, + std::string version = "1.0", + default_arguments add_args = default_arguments::all, + bool exit_on_default_arguments = true, + std::ostream &os = std::cout) + : m_program_name(std::move(program_name)), m_version(std::move(version)), + m_exit_on_default_arguments(exit_on_default_arguments), + m_parser_path(m_program_name) { + if ((add_args & default_arguments::help) == default_arguments::help) { + add_argument("-h", "--help") + .action([&](const auto & /*unused*/) { + os << help().str(); + if (m_exit_on_default_arguments) { + std::exit(0); + } + }) + .default_value(false) + .help("shows help message and exits") + .implicit_value(true) + .nargs(0); + } + if ((add_args & default_arguments::version) == default_arguments::version) { + add_argument("-v", "--version") + .action([&](const auto & /*unused*/) { + os << m_version << std::endl; + if (m_exit_on_default_arguments) { + std::exit(0); + } + }) + .default_value(false) + .help("prints version information and exits") + .implicit_value(true) + .nargs(0); + } + } + + ~ArgumentParser() = default; + + // ArgumentParser is meant to be used in a single function. + // Setup everything and parse arguments in one place. + // + // ArgumentParser internally uses std::string_views, + // references, iterators, etc. + // Many of these elements become invalidated after a copy or move. + ArgumentParser(const ArgumentParser &other) = delete; + ArgumentParser &operator=(const ArgumentParser &other) = delete; + ArgumentParser(ArgumentParser &&) noexcept = delete; + ArgumentParser &operator=(ArgumentParser &&) = delete; + + explicit operator bool() const { + auto arg_used = std::any_of(m_argument_map.cbegin(), m_argument_map.cend(), + [](auto &it) { return it.second->m_is_used; }); + auto subparser_used = + std::any_of(m_subparser_used.cbegin(), m_subparser_used.cend(), + [](auto &it) { return it.second; }); + + return m_is_parsed && (arg_used || subparser_used); + } + + // Parameter packing + // Call add_argument with variadic number of string arguments + template Argument &add_argument(Targs... f_args) { + using array_of_sv = std::array; + auto argument = + m_optional_arguments.emplace(std::cend(m_optional_arguments), + m_prefix_chars, array_of_sv{f_args...}); + + if (!argument->m_is_optional) { + m_positional_arguments.splice(std::cend(m_positional_arguments), + m_optional_arguments, argument); + } + + index_argument(argument); + return *argument; + } + + class MutuallyExclusiveGroup { + friend class ArgumentParser; + + public: + MutuallyExclusiveGroup() = delete; + + explicit MutuallyExclusiveGroup(ArgumentParser &parent, + bool required = false) + : m_parent(parent), m_required(required), m_elements({}) {} + + MutuallyExclusiveGroup(const MutuallyExclusiveGroup &other) = delete; + MutuallyExclusiveGroup & + operator=(const MutuallyExclusiveGroup &other) = delete; + + MutuallyExclusiveGroup(MutuallyExclusiveGroup &&other) noexcept + : m_parent(other.m_parent), m_required(other.m_required), + m_elements(std::move(other.m_elements)) { + other.m_elements.clear(); + } + + template Argument &add_argument(Targs... f_args) { + auto &argument = m_parent.add_argument(std::forward(f_args)...); + m_elements.push_back(&argument); + return argument; + } + + private: + ArgumentParser &m_parent; + bool m_required{false}; + std::vector m_elements{}; + }; + + MutuallyExclusiveGroup &add_mutually_exclusive_group(bool required = false) { + m_mutually_exclusive_groups.emplace_back(*this, required); + return m_mutually_exclusive_groups.back(); + } + + // Parameter packed add_parents method + // Accepts a variadic number of ArgumentParser objects + template + ArgumentParser &add_parents(const Targs &... f_args) { + for (const ArgumentParser &parent_parser : {std::ref(f_args)...}) { + for (const auto &argument : parent_parser.m_positional_arguments) { + auto it = m_positional_arguments.insert( + std::cend(m_positional_arguments), argument); + index_argument(it); + } + for (const auto &argument : parent_parser.m_optional_arguments) { + auto it = m_optional_arguments.insert(std::cend(m_optional_arguments), + argument); + index_argument(it); + } + } + return *this; + } + + ArgumentParser &add_description(std::string description) { + m_description = std::move(description); + return *this; + } + + ArgumentParser &add_epilog(std::string epilog) { + m_epilog = std::move(epilog); + return *this; + } + + /* Getter for arguments and subparsers. + * @throws std::logic_error in case of an invalid argument or subparser name + */ + template T &at(std::string_view name) { + if constexpr (std::is_same_v) { + return (*this)[name]; + } else { + auto subparser_it = m_subparser_map.find(name); + if (subparser_it != m_subparser_map.end()) { + return subparser_it->second->get(); + } + throw std::logic_error("No such subparser: " + std::string(name)); + } + } + + ArgumentParser &set_prefix_chars(std::string prefix_chars) { + m_prefix_chars = std::move(prefix_chars); + return *this; + } + + ArgumentParser &set_assign_chars(std::string assign_chars) { + m_assign_chars = std::move(assign_chars); + return *this; + } + + /* Call parse_args_internal - which does all the work + * Then, validate the parsed arguments + * This variant is used mainly for testing + * @throws std::runtime_error in case of any invalid argument + */ + void parse_args(const std::vector &arguments) { + parse_args_internal(arguments); + // Check if all arguments are parsed + for ([[maybe_unused]] const auto &[unused, argument] : m_argument_map) { + argument->validate(); + } + + // Check each mutually exclusive group and make sure + // there are no constraint violations + for (const auto &group : m_mutually_exclusive_groups) { + auto mutex_argument_used{false}; + Argument *mutex_argument_it{nullptr}; + for (Argument *arg : group.m_elements) { + if (!mutex_argument_used && arg->m_is_used) { + mutex_argument_used = true; + mutex_argument_it = arg; + } else if (mutex_argument_used && arg->m_is_used) { + // Violation + throw std::runtime_error("Argument '" + arg->get_usage_full() + + "' not allowed with '" + + mutex_argument_it->get_usage_full() + "'"); + } + } + + if (!mutex_argument_used && group.m_required) { + // at least one argument from the group is + // required + std::string argument_names{}; + std::size_t i = 0; + std::size_t size = group.m_elements.size(); + for (Argument *arg : group.m_elements) { + if (i + 1 == size) { + // last + argument_names += "'" + arg->get_usage_full() + "' "; + } else { + argument_names += "'" + arg->get_usage_full() + "' or "; + } + i += 1; + } + throw std::runtime_error("One of the arguments " + argument_names + + "is required"); + } + } + } + + /* Call parse_known_args_internal - which does all the work + * Then, validate the parsed arguments + * This variant is used mainly for testing + * @throws std::runtime_error in case of any invalid argument + */ + std::vector + parse_known_args(const std::vector &arguments) { + auto unknown_arguments = parse_known_args_internal(arguments); + // Check if all arguments are parsed + for ([[maybe_unused]] const auto &[unused, argument] : m_argument_map) { + argument->validate(); + } + return unknown_arguments; + } + + /* Main entry point for parsing command-line arguments using this + * ArgumentParser + * @throws std::runtime_error in case of any invalid argument + */ + // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays) + void parse_args(int argc, const char *const argv[]) { + parse_args({argv, argv + argc}); + } + + /* Main entry point for parsing command-line arguments using this + * ArgumentParser + * @throws std::runtime_error in case of any invalid argument + */ + // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays) + auto parse_known_args(int argc, const char *const argv[]) { + return parse_known_args({argv, argv + argc}); + } + + /* Getter for options with default values. + * @throws std::logic_error if parse_args() has not been previously called + * @throws std::logic_error if there is no such option + * @throws std::logic_error if the option has no value + * @throws std::bad_any_cast if the option is not of type T + */ + template T get(std::string_view arg_name) const { + if (!m_is_parsed) { + throw std::logic_error("Nothing parsed, no arguments are available."); + } + return (*this)[arg_name].get(); + } + + /* Getter for options without default values. + * @pre The option has no default value. + * @throws std::logic_error if there is no such option + * @throws std::bad_any_cast if the option is not of type T + */ + template + auto present(std::string_view arg_name) const -> std::optional { + return (*this)[arg_name].present(); + } + + /* Getter that returns true for user-supplied options. Returns false if not + * user-supplied, even with a default value. + */ + auto is_used(std::string_view arg_name) const { + return (*this)[arg_name].m_is_used; + } + + /* Getter that returns true if a subcommand is used. + */ + auto is_subcommand_used(std::string_view subcommand_name) const { + return m_subparser_used.at(subcommand_name); + } + + /* Getter that returns true if a subcommand is used. + */ + auto is_subcommand_used(const ArgumentParser &subparser) const { + return is_subcommand_used(subparser.m_program_name); + } + + /* Indexing operator. Return a reference to an Argument object + * Used in conjunction with Argument.operator== e.g., parser["foo"] == true + * @throws std::logic_error in case of an invalid argument name + */ + Argument &operator[](std::string_view arg_name) const { + auto it = m_argument_map.find(arg_name); + if (it != m_argument_map.end()) { + return *(it->second); + } + if (!is_valid_prefix_char(arg_name.front())) { + std::string name(arg_name); + const auto legal_prefix_char = get_any_valid_prefix_char(); + const auto prefix = std::string(1, legal_prefix_char); + + // "-" + arg_name + name = prefix + name; + it = m_argument_map.find(name); + if (it != m_argument_map.end()) { + return *(it->second); + } + // "--" + arg_name + name = prefix + name; + it = m_argument_map.find(name); + if (it != m_argument_map.end()) { + return *(it->second); + } + } + throw std::logic_error("No such argument: " + std::string(arg_name)); + } + + // Print help message + friend auto operator<<(std::ostream &stream, const ArgumentParser &parser) + -> std::ostream & { + stream.setf(std::ios_base::left); + + auto longest_arg_length = parser.get_length_of_longest_argument(); + + stream << parser.usage() << "\n\n"; + + if (!parser.m_description.empty()) { + stream << parser.m_description << "\n\n"; + } + + if (!parser.m_positional_arguments.empty()) { + stream << "Positional arguments:\n"; + } + + for (const auto &argument : parser.m_positional_arguments) { + stream.width(static_cast(longest_arg_length)); + stream << argument; + } + + if (!parser.m_optional_arguments.empty()) { + stream << (parser.m_positional_arguments.empty() ? "" : "\n") + << "Optional arguments:\n"; + } + + for (const auto &argument : parser.m_optional_arguments) { + stream.width(static_cast(longest_arg_length)); + stream << argument; + } + + bool has_visible_subcommands = std::any_of( + parser.m_subparser_map.begin(), parser.m_subparser_map.end(), + [](auto &p) { return !p.second->get().m_suppress; }); + + if (has_visible_subcommands) { + stream << (parser.m_positional_arguments.empty() + ? (parser.m_optional_arguments.empty() ? "" : "\n") + : "\n") + << "Subcommands:\n"; + for (const auto &[command, subparser] : parser.m_subparser_map) { + if (subparser->get().m_suppress) { + continue; + } + + stream << std::setw(2) << " "; + stream << std::setw(static_cast(longest_arg_length - 2)) + << command; + stream << " " << subparser->get().m_description << "\n"; + } + } + + if (!parser.m_epilog.empty()) { + stream << '\n'; + stream << parser.m_epilog << "\n\n"; + } + + return stream; + } + + // Format help message + auto help() const -> std::stringstream { + std::stringstream out; + out << *this; + return out; + } + + // Format usage part of help only + auto usage() const -> std::string { + std::stringstream stream; + + stream << "Usage: " << this->m_program_name; + + // Add any options inline here + for (const auto &argument : this->m_optional_arguments) { + stream << " " << argument.get_inline_usage(); + } + // Put positional arguments after the optionals + for (const auto &argument : this->m_positional_arguments) { + if (!argument.m_metavar.empty()) { + stream << " " << argument.m_metavar; + } else { + stream << " " << argument.m_names.front(); + } + } + // Put subcommands after positional arguments + if (!m_subparser_map.empty()) { + stream << " {"; + std::size_t i{0}; + for (const auto &[command, subparser] : m_subparser_map) { + if (subparser->get().m_suppress) { + continue; + } + + if (i == 0) { + stream << command; + } else { + stream << "," << command; + } + ++i; + } + stream << "}"; + } + + return stream.str(); + } + + // Printing the one and only help message + // I've stuck with a simple message format, nothing fancy. + [[deprecated("Use cout << program; instead. See also help().")]] std::string + print_help() const { + auto out = help(); + std::cout << out.rdbuf(); + return out.str(); + } + + void add_subparser(ArgumentParser &parser) { + parser.m_parser_path = m_program_name + " " + parser.m_program_name; + auto it = m_subparsers.emplace(std::cend(m_subparsers), parser); + m_subparser_map.insert_or_assign(parser.m_program_name, it); + m_subparser_used.insert_or_assign(parser.m_program_name, false); + } + + void set_suppress(bool suppress) { m_suppress = suppress; } + +private: + bool is_valid_prefix_char(char c) const { + return m_prefix_chars.find(c) != std::string::npos; + } + + char get_any_valid_prefix_char() const { return m_prefix_chars[0]; } + + /* + * Pre-process this argument list. Anything starting with "--", that + * contains an =, where the prefix before the = has an entry in the + * options table, should be split. + */ + std::vector + preprocess_arguments(const std::vector &raw_arguments) const { + std::vector arguments{}; + for (const auto &arg : raw_arguments) { + + const auto argument_starts_with_prefix_chars = + [this](const std::string &a) -> bool { + if (!a.empty()) { + + const auto legal_prefix = [this](char c) -> bool { + return m_prefix_chars.find(c) != std::string::npos; + }; + + // Windows-style + // if '/' is a legal prefix char + // then allow single '/' followed by argument name, followed by an + // assign char, e.g., ':' e.g., 'test.exe /A:Foo' + const auto windows_style = legal_prefix('/'); + + if (windows_style) { + if (legal_prefix(a[0])) { + return true; + } + } else { + // Slash '/' is not a legal prefix char + // For all other characters, only support long arguments + // i.e., the argument must start with 2 prefix chars, e.g, + // '--foo' e,g, './test --foo=Bar -DARG=yes' + if (a.size() > 1) { + return (legal_prefix(a[0]) && legal_prefix(a[1])); + } + } + } + return false; + }; + + // Check that: + // - We don't have an argument named exactly this + // - The argument starts with a prefix char, e.g., "--" + // - The argument contains an assign char, e.g., "=" + auto assign_char_pos = arg.find_first_of(m_assign_chars); + + if (m_argument_map.find(arg) == m_argument_map.end() && + argument_starts_with_prefix_chars(arg) && + assign_char_pos != std::string::npos) { + // Get the name of the potential option, and check it exists + std::string opt_name = arg.substr(0, assign_char_pos); + if (m_argument_map.find(opt_name) != m_argument_map.end()) { + // This is the name of an option! Split it into two parts + arguments.push_back(std::move(opt_name)); + arguments.push_back(arg.substr(assign_char_pos + 1)); + continue; + } + } + // If we've fallen through to here, then it's a standard argument + arguments.push_back(arg); + } + return arguments; + } + + /* + * @throws std::runtime_error in case of any invalid argument + */ + void parse_args_internal(const std::vector &raw_arguments) { + auto arguments = preprocess_arguments(raw_arguments); + if (m_program_name.empty() && !arguments.empty()) { + m_program_name = arguments.front(); + } + auto end = std::end(arguments); + auto positional_argument_it = std::begin(m_positional_arguments); + for (auto it = std::next(std::begin(arguments)); it != end;) { + const auto ¤t_argument = *it; + if (Argument::is_positional(current_argument, m_prefix_chars)) { + if (positional_argument_it == std::end(m_positional_arguments)) { + + std::string_view maybe_command = current_argument; + + // Check sub-parsers + auto subparser_it = m_subparser_map.find(maybe_command); + if (subparser_it != m_subparser_map.end()) { + + // build list of remaining args + const auto unprocessed_arguments = + std::vector(it, end); + + // invoke subparser + m_is_parsed = true; + m_subparser_used[maybe_command] = true; + return subparser_it->second->get().parse_args( + unprocessed_arguments); + } + + if (m_positional_arguments.empty()) { + + // Ask the user if they argument they provided was a typo + // for some sub-parser, + // e.g., user provided `git totes` instead of `git notes` + if (!m_subparser_map.empty()) { + throw std::runtime_error( + "Failed to parse '" + current_argument + "', did you mean '" + + std::string{details::get_most_similar_string( + m_subparser_map, current_argument)} + + "'"); + } + + // Ask the user if they meant to use a specific optional argument + if (!m_optional_arguments.empty()) { + for (const auto &opt : m_optional_arguments) { + if (!opt.m_implicit_value.has_value()) { + // not a flag, requires a value + if (!opt.m_is_used) { + throw std::runtime_error( + "Zero positional arguments expected, did you mean " + + opt.get_usage_full()); + } + } + } + + throw std::runtime_error("Zero positional arguments expected"); + } else { + throw std::runtime_error("Zero positional arguments expected"); + } + } else { + throw std::runtime_error("Maximum number of positional arguments " + "exceeded, failed to parse '" + + current_argument + "'"); + } + } + auto argument = positional_argument_it++; + it = argument->consume(it, end); + continue; + } + + auto arg_map_it = m_argument_map.find(current_argument); + if (arg_map_it != m_argument_map.end()) { + auto argument = arg_map_it->second; + it = argument->consume(std::next(it), end, arg_map_it->first); + } else if (const auto &compound_arg = current_argument; + compound_arg.size() > 1 && + is_valid_prefix_char(compound_arg[0]) && + !is_valid_prefix_char(compound_arg[1])) { + ++it; + for (std::size_t j = 1; j < compound_arg.size(); j++) { + auto hypothetical_arg = std::string{'-', compound_arg[j]}; + auto arg_map_it2 = m_argument_map.find(hypothetical_arg); + if (arg_map_it2 != m_argument_map.end()) { + auto argument = arg_map_it2->second; + it = argument->consume(it, end, arg_map_it2->first); + } else { + throw std::runtime_error("Unknown argument: " + current_argument); + } + } + } else { + throw std::runtime_error("Unknown argument: " + current_argument); + } + } + m_is_parsed = true; + } + + /* + * Like parse_args_internal but collects unused args into a vector + */ + std::vector + parse_known_args_internal(const std::vector &raw_arguments) { + auto arguments = preprocess_arguments(raw_arguments); + + std::vector unknown_arguments{}; + + if (m_program_name.empty() && !arguments.empty()) { + m_program_name = arguments.front(); + } + auto end = std::end(arguments); + auto positional_argument_it = std::begin(m_positional_arguments); + for (auto it = std::next(std::begin(arguments)); it != end;) { + const auto ¤t_argument = *it; + if (Argument::is_positional(current_argument, m_prefix_chars)) { + if (positional_argument_it == std::end(m_positional_arguments)) { + + std::string_view maybe_command = current_argument; + + // Check sub-parsers + auto subparser_it = m_subparser_map.find(maybe_command); + if (subparser_it != m_subparser_map.end()) { + + // build list of remaining args + const auto unprocessed_arguments = + std::vector(it, end); + + // invoke subparser + m_is_parsed = true; + m_subparser_used[maybe_command] = true; + return subparser_it->second->get().parse_known_args_internal( + unprocessed_arguments); + } + + // save current argument as unknown and go to next argument + unknown_arguments.push_back(current_argument); + ++it; + } else { + // current argument is the value of a positional argument + // consume it + auto argument = positional_argument_it++; + it = argument->consume(it, end); + } + continue; + } + + auto arg_map_it = m_argument_map.find(current_argument); + if (arg_map_it != m_argument_map.end()) { + auto argument = arg_map_it->second; + it = argument->consume(std::next(it), end, arg_map_it->first); + } else if (const auto &compound_arg = current_argument; + compound_arg.size() > 1 && + is_valid_prefix_char(compound_arg[0]) && + !is_valid_prefix_char(compound_arg[1])) { + ++it; + for (std::size_t j = 1; j < compound_arg.size(); j++) { + auto hypothetical_arg = std::string{'-', compound_arg[j]}; + auto arg_map_it2 = m_argument_map.find(hypothetical_arg); + if (arg_map_it2 != m_argument_map.end()) { + auto argument = arg_map_it2->second; + it = argument->consume(it, end, arg_map_it2->first); + } else { + unknown_arguments.push_back(current_argument); + break; + } + } + } else { + // current argument is an optional-like argument that is unknown + // save it and move to next argument + unknown_arguments.push_back(current_argument); + ++it; + } + } + m_is_parsed = true; + return unknown_arguments; + } + + // Used by print_help. + std::size_t get_length_of_longest_argument() const { + if (m_argument_map.empty()) { + return 0; + } + std::size_t max_size = 0; + for ([[maybe_unused]] const auto &[unused, argument] : m_argument_map) { + max_size = + std::max(max_size, argument->get_arguments_length()); + } + for ([[maybe_unused]] const auto &[command, unused] : m_subparser_map) { + max_size = std::max(max_size, command.size()); + } + return max_size; + } + + using argument_it = std::list::iterator; + using mutex_group_it = std::vector::iterator; + using argument_parser_it = + std::list>::iterator; + + void index_argument(argument_it it) { + for (const auto &name : std::as_const(it->m_names)) { + m_argument_map.insert_or_assign(name, it); + } + } + + std::string m_program_name; + std::string m_version; + std::string m_description; + std::string m_epilog; + bool m_exit_on_default_arguments = true; + std::string m_prefix_chars{"-"}; + std::string m_assign_chars{"="}; + bool m_is_parsed = false; + std::list m_positional_arguments; + std::list m_optional_arguments; + std::map m_argument_map; + std::string m_parser_path; + std::list> m_subparsers; + std::map m_subparser_map; + std::map m_subparser_used; + std::vector m_mutually_exclusive_groups; + bool m_suppress = false; +}; + +} // namespace argparse \ No newline at end of file diff --git a/tools/dkr_assets_tool_src/libs/bimap.hpp b/tools/dkr_assets_tool_src/libs/bimap.hpp new file mode 100644 index 00000000..f4c63c53 --- /dev/null +++ b/tools/dkr_assets_tool_src/libs/bimap.hpp @@ -0,0 +1,165 @@ +#pragma once + +#include +#include + +namespace stde +{ + using namespace std; + + template< + class _KeyType, + class _ValueType, + class _Key_Container = std::set<_KeyType>, + class _Mapped_Container = std::set<_ValueType>> + class bimap + { + public: + class const_iterator : public iterator< + std::bidirectional_iterator_tag, + std::pair> + { + public: + typedef const_iterator self_type; + typedef pair value_type; + typedef int difference_type; + explicit const_iterator(const value_type& value) : m_data(std::move(value)) { } + const self_type& operator++() { ++m_data.first; ++m_data.second; return *this; } + const value_type& operator*() { return m_data; } + bool operator==(const self_type& rhs) { return m_data.first == rhs.m_data.first; } + bool operator!=(const self_type& rhs) { return m_data.first != rhs.m_data.first; } + private: + value_type m_data; + }; + using key_type = _KeyType; + using value_type = _ValueType; + using rkey_type = _ValueType; + using rvalue_type = _KeyType; + private: + using _Tree = _Key_Container; + using _RTree = _Mapped_Container; + using _Tree_Node = std::pair; + using _RTree_Node = std::pair; + private: + // Test for the container types + static_assert( + is_same_v, + "bimap::key_type has to match _Container_Type::key_type!"); + static_assert( + is_same_v, + "bimap::rkey_type has to match _Reverse_Container_Type::key_type!"); + private: + _Tree m_key_tree; + _RTree m_value_tree; + private: + /* Inner helper functions */ + inline size_t index_of_key(const key_type& key) const + { + const auto k_itr = m_key_tree.find(key); + const auto offset = static_cast(std::distance(m_key_tree.begin(), k_itr)); + return (offset < m_key_tree.size() ? offset : 0); + } + inline size_t index_of_value(const value_type& value) const + { + const auto v_itr = m_value_tree.find(value); + const auto offset = static_cast(std::distance(m_value_tree.begin(), v_itr)); + return (offset < m_value_tree.size() ? offset : 0); + } + inline value_type value_at_index(size_t index) const + { + auto v_itr = m_value_tree.begin(); + std::advance(v_itr, index); + return *v_itr; + } + inline key_type key_at_index(size_t index) const + { + auto k_itr = m_key_tree.begin(); + std::advance(k_itr, index); + return *k_itr; + } + public: + /* Constructors */ + bimap() = default; + bimap(std::initializer_list<_Tree_Node> init) + { + for (const auto& elem : init) + insert(elem); + } + public: + /* Iterator functions */ + const_iterator begin() const { return const_iterator({ m_key_tree.begin(), m_value_tree.begin() }); } + const_iterator end() const { return const_iterator({ m_key_tree.end(), m_value_tree.end() }); } + public: + /* Modification functions */ + void insert(_Tree_Node&& node) + { + m_key_tree.emplace_hint(m_key_tree.begin(), std::move(node.first)); + m_value_tree.emplace_hint(m_value_tree.begin(), std::move(node.second)); + } + void insert(const _Tree_Node& node) + { + m_key_tree.emplace_hint(m_key_tree.begin(), std::move(node.first)); + m_value_tree.emplace_hint(m_value_tree.begin(), std::move(node.second)); + } + void insert(const key_type& key, const value_type& value) + { + m_key_tree.emplace_hint(m_key_tree.begin(), std::move(key)); + m_value_tree.emplace_hint(m_value_tree.begin(), std::move(value)); + } + void erase_key(const key_type& key) + { + const auto k_itr = m_key_tree.find(key); + const auto offset = std::distance(m_key_tree.begin(), k_itr); + auto v_itr = m_value_tree.begin(); + std::advance(v_itr, offset); + m_key_tree.erase(k_itr); + m_value_tree.erase(v_itr); + } + void erase_value(const value_type& value) + { + const auto v_itr = m_value_tree.find(value); + const auto offset = std::distance(m_value_tree.begin(), v_itr); + auto k_itr = m_key_tree.begin(); + std::advance(k_itr, offset); + m_key_tree.erase(k_itr); + m_value_tree.erase(v_itr); + } + public: + /* Helper functions */ + bool has_key(const key_type& key) const + { + return m_key_tree.find(key) != m_key_tree.end(); + } + bool has_value(const value_type& value) const + { + return m_value_tree.find(value) != m_value_tree.end(); + } + value_type get_value(const key_type& key) const + { + const auto offset = index_of_key(key); + auto v_itr = m_value_tree.begin(); + std::advance(v_itr, offset); + return *v_itr; + } + key_type get_key(const value_type& value) const + { + const auto offset = index_of_value(value); + auto k_itr = m_key_tree.begin(); + std::advance(k_itr, offset); + return *k_itr; + } + size_t size() const + { + return m_key_tree.size(); + } + }; + + template< + class _KeyType, + class _ValueType> + using unordered_bimap = bimap< + _KeyType, + _ValueType, + std::unordered_set<_KeyType>, + std::unordered_set<_ValueType>>; +} diff --git a/tools/dkr_assets_tool_classes/libs/calculator.hpp b/tools/dkr_assets_tool_src/libs/calculator.hpp similarity index 100% rename from tools/dkr_assets_tool_classes/libs/calculator.hpp rename to tools/dkr_assets_tool_src/libs/calculator.hpp diff --git a/tools/dkr_assets_tool_classes/libs/DKRCompression.cpp b/tools/dkr_assets_tool_src/libs/gzip/DKRCompression.cpp similarity index 97% rename from tools/dkr_assets_tool_classes/libs/DKRCompression.cpp rename to tools/dkr_assets_tool_src/libs/gzip/DKRCompression.cpp index eb3bc1c2..342bdeec 100644 --- a/tools/dkr_assets_tool_classes/libs/DKRCompression.cpp +++ b/tools/dkr_assets_tool_src/libs/gzip/DKRCompression.cpp @@ -52,7 +52,7 @@ bool DKRCompression::writeBinaryFile(std::vector& output, std::string f try { std::ofstream wf(filename.c_str(), std::ios::out | std::ios::binary); - for(int i = 0; i < output.size(); i++) + for(size_t i = 0; i < output.size(); i++) wf.write((char *)&output[i], 1); wf.close(); } diff --git a/tools/dkr_assets_tool_classes/libs/DKRCompression.h b/tools/dkr_assets_tool_src/libs/gzip/DKRCompression.h similarity index 100% rename from tools/dkr_assets_tool_classes/libs/DKRCompression.h rename to tools/dkr_assets_tool_src/libs/gzip/DKRCompression.h diff --git a/tools/dkr_assets_tool_classes/libs/DKRGzip.c b/tools/dkr_assets_tool_src/libs/gzip/DKRGzip.c similarity index 99% rename from tools/dkr_assets_tool_classes/libs/DKRGzip.c rename to tools/dkr_assets_tool_src/libs/gzip/DKRGzip.c index 5a5f7f38..6a25580e 100644 --- a/tools/dkr_assets_tool_classes/libs/DKRGzip.c +++ b/tools/dkr_assets_tool_src/libs/gzip/DKRGzip.c @@ -727,7 +727,7 @@ u32 updcrc(char *bytes, u32 numBytes) { int read_buf(char *buf, u32 size){ u32 len; - if(incnt + size >= inbufSize) { + if((int)(incnt + size) >= inbufSize) { len = inbufSize - incnt; } else { len = size; @@ -1632,13 +1632,12 @@ void rsync_roll(u32 start, u32 num) { * IN assertion: strstart is set to the end of the current match. */ #define FLUSH_BLOCK(eof) \ - flush_block(block_start >= 0 ? (char*)&window[(unsigned)block_start] : \ - (char*)NULL, (long)strstart - block_start, flush-1, (eof)) + flush_block((char*)&window[(unsigned)block_start], (long)strstart - block_start, flush-1, (eof)) void deflate() { IPos hash_head; /* head of hash chain */ IPos prev_match; /* previous match */ - int flush; /* set if current block must be flushed */ + int flush=0; /* set if current block must be flushed */ int match_available = 0; /* set if previous match exists */ u32 match_length = MIN_MATCH-1; /* length of best match */ diff --git a/tools/dkr_assets_tool_classes/libs/DKRGzip.h b/tools/dkr_assets_tool_src/libs/gzip/DKRGzip.h similarity index 100% rename from tools/dkr_assets_tool_classes/libs/DKRGzip.h rename to tools/dkr_assets_tool_src/libs/gzip/DKRGzip.h diff --git a/tools/dkr_assets_tool_classes/libs/GECompression.cpp b/tools/dkr_assets_tool_src/libs/gzip/GECompression.cpp similarity index 99% rename from tools/dkr_assets_tool_classes/libs/GECompression.cpp rename to tools/dkr_assets_tool_src/libs/gzip/GECompression.cpp index 6ecd971a..064776ba 100644 --- a/tools/dkr_assets_tool_classes/libs/GECompression.cpp +++ b/tools/dkr_assets_tool_src/libs/gzip/GECompression.cpp @@ -159,7 +159,7 @@ unsigned long GECompression::GetNBits(int nBits) { if (bytesIndex >= maxByteSize) return 0; // bad decompression - if (bytesIndex >= compressedBufferSize) + if ((int)bytesIndex >= compressedBufferSize) return 0; // bad decompression bitsCache = ((bitsCache) | (compressedBuffer[bytesIndex] << bitsRemain)); bitsRemain = bitsRemain + 8; @@ -178,7 +178,7 @@ unsigned long GECompression::GetNBitsAndPreserve(int nBits) { if (bytesIndex >= maxByteSize) return 0; // bad decompression - if (bytesIndex >= compressedBufferSize) + if ((int)bytesIndex >= compressedBufferSize) return 0; // bad decompression bitsCache = ((bitsCache) | (compressedBuffer[bytesIndex] << bitsRemain)); bitsRemain = bitsRemain + 8; @@ -1059,7 +1059,7 @@ void GECompression::CreateGlobalDecompressionTable(int bit1TableChoice, int size else { unsigned long tempWord = moreWords[moreWordsIndex]; - if (tempWord= 0x100) localTableEntry.flags = 0xf; @@ -1100,7 +1100,7 @@ void GECompression::CreateGlobalDecompressionTable(int bit1TableChoice, int size } } }*/ - while ((1< nu_accum_a3) + while ((unsigned long)(1< nu_accum_a3) { if ((thisTableStart+nu_accum_a3) > 0xFFFF) { @@ -1122,7 +1122,7 @@ void GECompression::CreateGlobalDecompressionTable(int bit1TableChoice, int size tempLv = tempLv >> 1; } bitPattern = bitPattern ^ tempLv; - while((bitPattern & ((1 << stemp2_v1)-1)) != seventeenints2[blockNum]) + while((unsigned long)(bitPattern & ((1 << stemp2_v1)-1)) != seventeenints2[blockNum]) { blockNum = blockNum- 1; stemp2_v1=0; @@ -1262,7 +1262,7 @@ bool GECompression::DecompressBasedOnTable(int startIndex1, int startIndex2, int unsigned long endOffset2 = GetNBits(entry2.flags); unsigned long start = fileSize-endOffset1-endOffset2; unsigned long end = start + copyLen; - for (int x = start; x < end; x++) + for (unsigned long x = start; x < end; x++) { if ((((signed long) start) < 0) || ((((signed long) end) < 0)) || ((start > maxByteSize)) || ((end > maxByteSize))) { diff --git a/tools/dkr_assets_tool_classes/libs/GECompression.h b/tools/dkr_assets_tool_src/libs/gzip/GECompression.h similarity index 100% rename from tools/dkr_assets_tool_classes/libs/GECompression.h rename to tools/dkr_assets_tool_src/libs/gzip/GECompression.h diff --git a/tools/dkr_assets_tool_src/libs/json.hpp b/tools/dkr_assets_tool_src/libs/json.hpp new file mode 100644 index 00000000..a6b4a1f2 --- /dev/null +++ b/tools/dkr_assets_tool_src/libs/json.hpp @@ -0,0 +1,26755 @@ +/* + __ _____ _____ _____ + __| | __| | | | JSON for Modern C++ +| | |__ | | | | | | version 3.10.4 +|_____|_____|_____|_|___| https://github.com/nlohmann/json + +Licensed under the MIT License . +SPDX-License-Identifier: MIT +Copyright (c) 2013-2019 Niels Lohmann . + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#pragma once + +#ifndef INCLUDE_NLOHMANN_JSON_HPP_ +#define INCLUDE_NLOHMANN_JSON_HPP_ + +#define NLOHMANN_JSON_VERSION_MAJOR 3 +#define NLOHMANN_JSON_VERSION_MINOR 10 +#define NLOHMANN_JSON_VERSION_PATCH 4 + +#include // all_of, find, for_each +#include // nullptr_t, ptrdiff_t, size_t +#include // hash, less +#include // initializer_list +#ifndef JSON_NO_IO + #include // istream, ostream +#endif // JSON_NO_IO +#include // random_access_iterator_tag +#include // unique_ptr +#include // accumulate +#include // string, stoi, to_string +#include // declval, forward, move, pair, swap +#include // vector + +// #include + + +#include +#include + +// #include + + +#include // transform +#include // array +#include // forward_list +#include // inserter, front_inserter, end +#include // map +#include // string +#include // tuple, make_tuple +#include // is_arithmetic, is_same, is_enum, underlying_type, is_convertible +#include // unordered_map +#include // pair, declval +#include // valarray + +// #include + + +#include // exception +#include // runtime_error +#include // to_string +#include // vector + +// #include + + +#include // array +#include // size_t +#include // uint8_t +#include // string + +namespace nlohmann +{ +namespace detail +{ +/////////////////////////// +// JSON type enumeration // +/////////////////////////// + +/*! +@brief the JSON type enumeration + +This enumeration collects the different JSON types. It is internally used to +distinguish the stored values, and the functions @ref basic_json::is_null(), +@ref basic_json::is_object(), @ref basic_json::is_array(), +@ref basic_json::is_string(), @ref basic_json::is_boolean(), +@ref basic_json::is_number() (with @ref basic_json::is_number_integer(), +@ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()), +@ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and +@ref basic_json::is_structured() rely on it. + +@note There are three enumeration entries (number_integer, number_unsigned, and +number_float), because the library distinguishes these three types for numbers: +@ref basic_json::number_unsigned_t is used for unsigned integers, +@ref basic_json::number_integer_t is used for signed integers, and +@ref basic_json::number_float_t is used for floating-point numbers or to +approximate integers which do not fit in the limits of their respective type. + +@sa see @ref basic_json::basic_json(const value_t value_type) -- create a JSON +value with the default value for a given type + +@since version 1.0.0 +*/ +enum class value_t : std::uint8_t +{ + null, ///< null value + object, ///< object (unordered set of name/value pairs) + array, ///< array (ordered collection of values) + string, ///< string value + boolean, ///< boolean value + number_integer, ///< number value (signed integer) + number_unsigned, ///< number value (unsigned integer) + number_float, ///< number value (floating-point) + binary, ///< binary array (ordered collection of bytes) + discarded ///< discarded by the parser callback function +}; + +/*! +@brief comparison operator for JSON types + +Returns an ordering that is similar to Python: +- order: null < boolean < number < object < array < string < binary +- furthermore, each type is not smaller than itself +- discarded values are not comparable +- binary is represented as a b"" string in python and directly comparable to a + string; however, making a binary array directly comparable with a string would + be surprising behavior in a JSON file. + +@since version 1.0.0 +*/ +inline bool operator<(const value_t lhs, const value_t rhs) noexcept +{ + static constexpr std::array order = {{ + 0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */, + 1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */, + 6 /* binary */ + } + }; + + const auto l_index = static_cast(lhs); + const auto r_index = static_cast(rhs); + return l_index < order.size() && r_index < order.size() && order[l_index] < order[r_index]; +} +} // namespace detail +} // namespace nlohmann + +// #include + + +#include +// #include + + +#include // declval, pair +// #include + + +/* Hedley - https://nemequ.github.io/hedley + * Created by Evan Nemerson + * + * To the extent possible under law, the author(s) have dedicated all + * copyright and related and neighboring rights to this software to + * the public domain worldwide. This software is distributed without + * any warranty. + * + * For details, see . + * SPDX-License-Identifier: CC0-1.0 + */ + +#if !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < 15) +#if defined(JSON_HEDLEY_VERSION) + #undef JSON_HEDLEY_VERSION +#endif +#define JSON_HEDLEY_VERSION 15 + +#if defined(JSON_HEDLEY_STRINGIFY_EX) + #undef JSON_HEDLEY_STRINGIFY_EX +#endif +#define JSON_HEDLEY_STRINGIFY_EX(x) #x + +#if defined(JSON_HEDLEY_STRINGIFY) + #undef JSON_HEDLEY_STRINGIFY +#endif +#define JSON_HEDLEY_STRINGIFY(x) JSON_HEDLEY_STRINGIFY_EX(x) + +#if defined(JSON_HEDLEY_CONCAT_EX) + #undef JSON_HEDLEY_CONCAT_EX +#endif +#define JSON_HEDLEY_CONCAT_EX(a,b) a##b + +#if defined(JSON_HEDLEY_CONCAT) + #undef JSON_HEDLEY_CONCAT +#endif +#define JSON_HEDLEY_CONCAT(a,b) JSON_HEDLEY_CONCAT_EX(a,b) + +#if defined(JSON_HEDLEY_CONCAT3_EX) + #undef JSON_HEDLEY_CONCAT3_EX +#endif +#define JSON_HEDLEY_CONCAT3_EX(a,b,c) a##b##c + +#if defined(JSON_HEDLEY_CONCAT3) + #undef JSON_HEDLEY_CONCAT3 +#endif +#define JSON_HEDLEY_CONCAT3(a,b,c) JSON_HEDLEY_CONCAT3_EX(a,b,c) + +#if defined(JSON_HEDLEY_VERSION_ENCODE) + #undef JSON_HEDLEY_VERSION_ENCODE +#endif +#define JSON_HEDLEY_VERSION_ENCODE(major,minor,revision) (((major) * 1000000) + ((minor) * 1000) + (revision)) + +#if defined(JSON_HEDLEY_VERSION_DECODE_MAJOR) + #undef JSON_HEDLEY_VERSION_DECODE_MAJOR +#endif +#define JSON_HEDLEY_VERSION_DECODE_MAJOR(version) ((version) / 1000000) + +#if defined(JSON_HEDLEY_VERSION_DECODE_MINOR) + #undef JSON_HEDLEY_VERSION_DECODE_MINOR +#endif +#define JSON_HEDLEY_VERSION_DECODE_MINOR(version) (((version) % 1000000) / 1000) + +#if defined(JSON_HEDLEY_VERSION_DECODE_REVISION) + #undef JSON_HEDLEY_VERSION_DECODE_REVISION +#endif +#define JSON_HEDLEY_VERSION_DECODE_REVISION(version) ((version) % 1000) + +#if defined(JSON_HEDLEY_GNUC_VERSION) + #undef JSON_HEDLEY_GNUC_VERSION +#endif +#if defined(__GNUC__) && defined(__GNUC_PATCHLEVEL__) + #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) +#elif defined(__GNUC__) + #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, 0) +#endif + +#if defined(JSON_HEDLEY_GNUC_VERSION_CHECK) + #undef JSON_HEDLEY_GNUC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_GNUC_VERSION) + #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GNUC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_MSVC_VERSION) + #undef JSON_HEDLEY_MSVC_VERSION +#endif +#if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140000000) && !defined(__ICL) + #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 10000000, (_MSC_FULL_VER % 10000000) / 100000, (_MSC_FULL_VER % 100000) / 100) +#elif defined(_MSC_FULL_VER) && !defined(__ICL) + #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 1000000, (_MSC_FULL_VER % 1000000) / 10000, (_MSC_FULL_VER % 10000) / 10) +#elif defined(_MSC_VER) && !defined(__ICL) + #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_VER / 100, _MSC_VER % 100, 0) +#endif + +#if defined(JSON_HEDLEY_MSVC_VERSION_CHECK) + #undef JSON_HEDLEY_MSVC_VERSION_CHECK +#endif +#if !defined(JSON_HEDLEY_MSVC_VERSION) + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (0) +#elif defined(_MSC_VER) && (_MSC_VER >= 1400) + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 10000000) + (minor * 100000) + (patch))) +#elif defined(_MSC_VER) && (_MSC_VER >= 1200) + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 1000000) + (minor * 10000) + (patch))) +#else + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_VER >= ((major * 100) + (minor))) +#endif + +#if defined(JSON_HEDLEY_INTEL_VERSION) + #undef JSON_HEDLEY_INTEL_VERSION +#endif +#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) && !defined(__ICL) + #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, __INTEL_COMPILER_UPDATE) +#elif defined(__INTEL_COMPILER) && !defined(__ICL) + #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0) +#endif + +#if defined(JSON_HEDLEY_INTEL_VERSION_CHECK) + #undef JSON_HEDLEY_INTEL_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_INTEL_VERSION) + #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_INTEL_CL_VERSION) + #undef JSON_HEDLEY_INTEL_CL_VERSION +#endif +#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) && defined(__ICL) + #define JSON_HEDLEY_INTEL_CL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER, __INTEL_COMPILER_UPDATE, 0) +#endif + +#if defined(JSON_HEDLEY_INTEL_CL_VERSION_CHECK) + #undef JSON_HEDLEY_INTEL_CL_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_INTEL_CL_VERSION) + #define JSON_HEDLEY_INTEL_CL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_CL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_INTEL_CL_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_PGI_VERSION) + #undef JSON_HEDLEY_PGI_VERSION +#endif +#if defined(__PGI) && defined(__PGIC__) && defined(__PGIC_MINOR__) && defined(__PGIC_PATCHLEVEL__) + #define JSON_HEDLEY_PGI_VERSION JSON_HEDLEY_VERSION_ENCODE(__PGIC__, __PGIC_MINOR__, __PGIC_PATCHLEVEL__) +#endif + +#if defined(JSON_HEDLEY_PGI_VERSION_CHECK) + #undef JSON_HEDLEY_PGI_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_PGI_VERSION) + #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PGI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_SUNPRO_VERSION) + #undef JSON_HEDLEY_SUNPRO_VERSION +#endif +#if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), (__SUNPRO_C & 0xf) * 10) +#elif defined(__SUNPRO_C) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_C >> 8) & 0xf, (__SUNPRO_C >> 4) & 0xf, (__SUNPRO_C) & 0xf) +#elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), (__SUNPRO_CC & 0xf) * 10) +#elif defined(__SUNPRO_CC) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_CC >> 8) & 0xf, (__SUNPRO_CC >> 4) & 0xf, (__SUNPRO_CC) & 0xf) +#endif + +#if defined(JSON_HEDLEY_SUNPRO_VERSION_CHECK) + #undef JSON_HEDLEY_SUNPRO_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_SUNPRO_VERSION) + #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_SUNPRO_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION) + #undef JSON_HEDLEY_EMSCRIPTEN_VERSION +#endif +#if defined(__EMSCRIPTEN__) + #define JSON_HEDLEY_EMSCRIPTEN_VERSION JSON_HEDLEY_VERSION_ENCODE(__EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__) +#endif + +#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK) + #undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION) + #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_EMSCRIPTEN_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_ARM_VERSION) + #undef JSON_HEDLEY_ARM_VERSION +#endif +#if defined(__CC_ARM) && defined(__ARMCOMPILER_VERSION) + #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCOMPILER_VERSION / 1000000, (__ARMCOMPILER_VERSION % 1000000) / 10000, (__ARMCOMPILER_VERSION % 10000) / 100) +#elif defined(__CC_ARM) && defined(__ARMCC_VERSION) + #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCC_VERSION / 1000000, (__ARMCC_VERSION % 1000000) / 10000, (__ARMCC_VERSION % 10000) / 100) +#endif + +#if defined(JSON_HEDLEY_ARM_VERSION_CHECK) + #undef JSON_HEDLEY_ARM_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_ARM_VERSION) + #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_ARM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_IBM_VERSION) + #undef JSON_HEDLEY_IBM_VERSION +#endif +#if defined(__ibmxl__) + #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ibmxl_version__, __ibmxl_release__, __ibmxl_modification__) +#elif defined(__xlC__) && defined(__xlC_ver__) + #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, (__xlC_ver__ >> 8) & 0xff) +#elif defined(__xlC__) + #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, 0) +#endif + +#if defined(JSON_HEDLEY_IBM_VERSION_CHECK) + #undef JSON_HEDLEY_IBM_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_IBM_VERSION) + #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IBM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_VERSION) + #undef JSON_HEDLEY_TI_VERSION +#endif +#if \ + defined(__TI_COMPILER_VERSION__) && \ + ( \ + defined(__TMS470__) || defined(__TI_ARM__) || \ + defined(__MSP430__) || \ + defined(__TMS320C2000__) \ + ) +#if (__TI_COMPILER_VERSION__ >= 16000000) + #define JSON_HEDLEY_TI_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif +#endif + +#if defined(JSON_HEDLEY_TI_VERSION_CHECK) + #undef JSON_HEDLEY_TI_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_VERSION) + #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL2000_VERSION) + #undef JSON_HEDLEY_TI_CL2000_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C2000__) + #define JSON_HEDLEY_TI_CL2000_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL2000_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CL2000_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL2000_VERSION) + #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL2000_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL430_VERSION) + #undef JSON_HEDLEY_TI_CL430_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__MSP430__) + #define JSON_HEDLEY_TI_CL430_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL430_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CL430_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL430_VERSION) + #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL430_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_ARMCL_VERSION) + #undef JSON_HEDLEY_TI_ARMCL_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && (defined(__TMS470__) || defined(__TI_ARM__)) + #define JSON_HEDLEY_TI_ARMCL_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_ARMCL_VERSION_CHECK) + #undef JSON_HEDLEY_TI_ARMCL_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_ARMCL_VERSION) + #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_ARMCL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL6X_VERSION) + #undef JSON_HEDLEY_TI_CL6X_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C6X__) + #define JSON_HEDLEY_TI_CL6X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL6X_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CL6X_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL6X_VERSION) + #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL6X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL7X_VERSION) + #undef JSON_HEDLEY_TI_CL7X_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__C7000__) + #define JSON_HEDLEY_TI_CL7X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL7X_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CL7X_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL7X_VERSION) + #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL7X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CLPRU_VERSION) + #undef JSON_HEDLEY_TI_CLPRU_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__PRU__) + #define JSON_HEDLEY_TI_CLPRU_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CLPRU_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CLPRU_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CLPRU_VERSION) + #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CLPRU_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_CRAY_VERSION) + #undef JSON_HEDLEY_CRAY_VERSION +#endif +#if defined(_CRAYC) + #if defined(_RELEASE_PATCHLEVEL) + #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, _RELEASE_PATCHLEVEL) + #else + #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, 0) + #endif +#endif + +#if defined(JSON_HEDLEY_CRAY_VERSION_CHECK) + #undef JSON_HEDLEY_CRAY_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_CRAY_VERSION) + #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_CRAY_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_IAR_VERSION) + #undef JSON_HEDLEY_IAR_VERSION +#endif +#if defined(__IAR_SYSTEMS_ICC__) + #if __VER__ > 1000 + #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE((__VER__ / 1000000), ((__VER__ / 1000) % 1000), (__VER__ % 1000)) + #else + #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE(__VER__ / 100, __VER__ % 100, 0) + #endif +#endif + +#if defined(JSON_HEDLEY_IAR_VERSION_CHECK) + #undef JSON_HEDLEY_IAR_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_IAR_VERSION) + #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IAR_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TINYC_VERSION) + #undef JSON_HEDLEY_TINYC_VERSION +#endif +#if defined(__TINYC__) + #define JSON_HEDLEY_TINYC_VERSION JSON_HEDLEY_VERSION_ENCODE(__TINYC__ / 1000, (__TINYC__ / 100) % 10, __TINYC__ % 100) +#endif + +#if defined(JSON_HEDLEY_TINYC_VERSION_CHECK) + #undef JSON_HEDLEY_TINYC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TINYC_VERSION) + #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TINYC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_DMC_VERSION) + #undef JSON_HEDLEY_DMC_VERSION +#endif +#if defined(__DMC__) + #define JSON_HEDLEY_DMC_VERSION JSON_HEDLEY_VERSION_ENCODE(__DMC__ >> 8, (__DMC__ >> 4) & 0xf, __DMC__ & 0xf) +#endif + +#if defined(JSON_HEDLEY_DMC_VERSION_CHECK) + #undef JSON_HEDLEY_DMC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_DMC_VERSION) + #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_DMC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_COMPCERT_VERSION) + #undef JSON_HEDLEY_COMPCERT_VERSION +#endif +#if defined(__COMPCERT_VERSION__) + #define JSON_HEDLEY_COMPCERT_VERSION JSON_HEDLEY_VERSION_ENCODE(__COMPCERT_VERSION__ / 10000, (__COMPCERT_VERSION__ / 100) % 100, __COMPCERT_VERSION__ % 100) +#endif + +#if defined(JSON_HEDLEY_COMPCERT_VERSION_CHECK) + #undef JSON_HEDLEY_COMPCERT_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_COMPCERT_VERSION) + #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_COMPCERT_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_PELLES_VERSION) + #undef JSON_HEDLEY_PELLES_VERSION +#endif +#if defined(__POCC__) + #define JSON_HEDLEY_PELLES_VERSION JSON_HEDLEY_VERSION_ENCODE(__POCC__ / 100, __POCC__ % 100, 0) +#endif + +#if defined(JSON_HEDLEY_PELLES_VERSION_CHECK) + #undef JSON_HEDLEY_PELLES_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_PELLES_VERSION) + #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PELLES_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_MCST_LCC_VERSION) + #undef JSON_HEDLEY_MCST_LCC_VERSION +#endif +#if defined(__LCC__) && defined(__LCC_MINOR__) + #define JSON_HEDLEY_MCST_LCC_VERSION JSON_HEDLEY_VERSION_ENCODE(__LCC__ / 100, __LCC__ % 100, __LCC_MINOR__) +#endif + +#if defined(JSON_HEDLEY_MCST_LCC_VERSION_CHECK) + #undef JSON_HEDLEY_MCST_LCC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_MCST_LCC_VERSION) + #define JSON_HEDLEY_MCST_LCC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_MCST_LCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_MCST_LCC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_GCC_VERSION) + #undef JSON_HEDLEY_GCC_VERSION +#endif +#if \ + defined(JSON_HEDLEY_GNUC_VERSION) && \ + !defined(__clang__) && \ + !defined(JSON_HEDLEY_INTEL_VERSION) && \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_ARM_VERSION) && \ + !defined(JSON_HEDLEY_CRAY_VERSION) && \ + !defined(JSON_HEDLEY_TI_VERSION) && \ + !defined(JSON_HEDLEY_TI_ARMCL_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL430_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL2000_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL6X_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL7X_VERSION) && \ + !defined(JSON_HEDLEY_TI_CLPRU_VERSION) && \ + !defined(__COMPCERT__) && \ + !defined(JSON_HEDLEY_MCST_LCC_VERSION) + #define JSON_HEDLEY_GCC_VERSION JSON_HEDLEY_GNUC_VERSION +#endif + +#if defined(JSON_HEDLEY_GCC_VERSION_CHECK) + #undef JSON_HEDLEY_GCC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_GCC_VERSION) + #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_HAS_ATTRIBUTE +#endif +#if \ + defined(__has_attribute) && \ + ( \ + (!defined(JSON_HEDLEY_IAR_VERSION) || JSON_HEDLEY_IAR_VERSION_CHECK(8,5,9)) \ + ) +# define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) __has_attribute(attribute) +#else +# define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE +#endif +#if defined(__has_attribute) + #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_HAS_ATTRIBUTE(attribute) +#else + #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE +#endif +#if defined(__has_attribute) + #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_HAS_ATTRIBUTE(attribute) +#else + #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE +#endif +#if \ + defined(__has_cpp_attribute) && \ + defined(__cplusplus) && \ + (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) __has_cpp_attribute(attribute) +#else + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) (0) +#endif + +#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS) + #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS +#endif +#if !defined(__cplusplus) || !defined(__has_cpp_attribute) + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) +#elif \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_IAR_VERSION) && \ + (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) && \ + (!defined(JSON_HEDLEY_MSVC_VERSION) || JSON_HEDLEY_MSVC_VERSION_CHECK(19,20,0)) + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(ns::attribute) +#else + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE +#endif +#if defined(__has_cpp_attribute) && defined(__cplusplus) + #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) +#else + #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE +#endif +#if defined(__has_cpp_attribute) && defined(__cplusplus) + #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) +#else + #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_BUILTIN) + #undef JSON_HEDLEY_HAS_BUILTIN +#endif +#if defined(__has_builtin) + #define JSON_HEDLEY_HAS_BUILTIN(builtin) __has_builtin(builtin) +#else + #define JSON_HEDLEY_HAS_BUILTIN(builtin) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_BUILTIN) + #undef JSON_HEDLEY_GNUC_HAS_BUILTIN +#endif +#if defined(__has_builtin) + #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) +#else + #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_BUILTIN) + #undef JSON_HEDLEY_GCC_HAS_BUILTIN +#endif +#if defined(__has_builtin) + #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) +#else + #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_FEATURE) + #undef JSON_HEDLEY_HAS_FEATURE +#endif +#if defined(__has_feature) + #define JSON_HEDLEY_HAS_FEATURE(feature) __has_feature(feature) +#else + #define JSON_HEDLEY_HAS_FEATURE(feature) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_FEATURE) + #undef JSON_HEDLEY_GNUC_HAS_FEATURE +#endif +#if defined(__has_feature) + #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) +#else + #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_FEATURE) + #undef JSON_HEDLEY_GCC_HAS_FEATURE +#endif +#if defined(__has_feature) + #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) +#else + #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_EXTENSION) + #undef JSON_HEDLEY_HAS_EXTENSION +#endif +#if defined(__has_extension) + #define JSON_HEDLEY_HAS_EXTENSION(extension) __has_extension(extension) +#else + #define JSON_HEDLEY_HAS_EXTENSION(extension) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_EXTENSION) + #undef JSON_HEDLEY_GNUC_HAS_EXTENSION +#endif +#if defined(__has_extension) + #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) +#else + #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_EXTENSION) + #undef JSON_HEDLEY_GCC_HAS_EXTENSION +#endif +#if defined(__has_extension) + #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) +#else + #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) + #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) __has_declspec_attribute(attribute) +#else + #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) + #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) +#else + #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) + #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) +#else + #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_WARNING) + #undef JSON_HEDLEY_HAS_WARNING +#endif +#if defined(__has_warning) + #define JSON_HEDLEY_HAS_WARNING(warning) __has_warning(warning) +#else + #define JSON_HEDLEY_HAS_WARNING(warning) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_WARNING) + #undef JSON_HEDLEY_GNUC_HAS_WARNING +#endif +#if defined(__has_warning) + #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) +#else + #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_WARNING) + #undef JSON_HEDLEY_GCC_HAS_WARNING +#endif +#if defined(__has_warning) + #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) +#else + #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if \ + (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ + defined(__clang__) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,0,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,17) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(8,0,0) || \ + (JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) && defined(__C99_PRAGMA_OPERATOR)) + #define JSON_HEDLEY_PRAGMA(value) _Pragma(#value) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) + #define JSON_HEDLEY_PRAGMA(value) __pragma(value) +#else + #define JSON_HEDLEY_PRAGMA(value) +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_PUSH) + #undef JSON_HEDLEY_DIAGNOSTIC_PUSH +#endif +#if defined(JSON_HEDLEY_DIAGNOSTIC_POP) + #undef JSON_HEDLEY_DIAGNOSTIC_POP +#endif +#if defined(__clang__) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("clang diagnostic push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("clang diagnostic pop") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("GCC diagnostic pop") +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH __pragma(warning(push)) + #define JSON_HEDLEY_DIAGNOSTIC_POP __pragma(warning(pop)) +#elif JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("pop") +#elif \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,4,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("diag_push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("diag_pop") +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") +#else + #define JSON_HEDLEY_DIAGNOSTIC_PUSH + #define JSON_HEDLEY_DIAGNOSTIC_POP +#endif + +/* JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ is for + HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ +#endif +#if defined(__cplusplus) +# if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat") +# if JSON_HEDLEY_HAS_WARNING("-Wc++17-extensions") +# if JSON_HEDLEY_HAS_WARNING("-Wc++1z-extensions") +# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ + _Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \ + _Pragma("clang diagnostic ignored \"-Wc++1z-extensions\"") \ + xpr \ + JSON_HEDLEY_DIAGNOSTIC_POP +# else +# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ + _Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \ + xpr \ + JSON_HEDLEY_DIAGNOSTIC_POP +# endif +# else +# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ + xpr \ + JSON_HEDLEY_DIAGNOSTIC_POP +# endif +# endif +#endif +#if !defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(x) x +#endif + +#if defined(JSON_HEDLEY_CONST_CAST) + #undef JSON_HEDLEY_CONST_CAST +#endif +#if defined(__cplusplus) +# define JSON_HEDLEY_CONST_CAST(T, expr) (const_cast(expr)) +#elif \ + JSON_HEDLEY_HAS_WARNING("-Wcast-qual") || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) +# define JSON_HEDLEY_CONST_CAST(T, expr) (__extension__ ({ \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL \ + ((T) (expr)); \ + JSON_HEDLEY_DIAGNOSTIC_POP \ + })) +#else +# define JSON_HEDLEY_CONST_CAST(T, expr) ((T) (expr)) +#endif + +#if defined(JSON_HEDLEY_REINTERPRET_CAST) + #undef JSON_HEDLEY_REINTERPRET_CAST +#endif +#if defined(__cplusplus) + #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) (reinterpret_cast(expr)) +#else + #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) ((T) (expr)) +#endif + +#if defined(JSON_HEDLEY_STATIC_CAST) + #undef JSON_HEDLEY_STATIC_CAST +#endif +#if defined(__cplusplus) + #define JSON_HEDLEY_STATIC_CAST(T, expr) (static_cast(expr)) +#else + #define JSON_HEDLEY_STATIC_CAST(T, expr) ((T) (expr)) +#endif + +#if defined(JSON_HEDLEY_CPP_CAST) + #undef JSON_HEDLEY_CPP_CAST +#endif +#if defined(__cplusplus) +# if JSON_HEDLEY_HAS_WARNING("-Wold-style-cast") +# define JSON_HEDLEY_CPP_CAST(T, expr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wold-style-cast\"") \ + ((T) (expr)) \ + JSON_HEDLEY_DIAGNOSTIC_POP +# elif JSON_HEDLEY_IAR_VERSION_CHECK(8,3,0) +# define JSON_HEDLEY_CPP_CAST(T, expr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("diag_suppress=Pe137") \ + JSON_HEDLEY_DIAGNOSTIC_POP +# else +# define JSON_HEDLEY_CPP_CAST(T, expr) ((T) (expr)) +# endif +#else +# define JSON_HEDLEY_CPP_CAST(T, expr) (expr) +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wdeprecated-declarations") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warning(disable:1478 1786)") +#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:1478 1786)) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(20,7,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1216,1444,1445") +#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:4996)) +#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444") +#elif \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1291,1718") +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && !defined(__cplusplus) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)") +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && defined(__cplusplus) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,symdeprecated,symdeprecated2)") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress=Pe1444,Pe1215") +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warn(disable:2241)") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("warning(disable:161)") +#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:161)) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 1675") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("GCC diagnostic ignored \"-Wunknown-pragmas\"") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:4068)) +#elif \ + JSON_HEDLEY_TI_VERSION_CHECK(16,9,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") +#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress=Pe161") +#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 161") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-attributes") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("clang diagnostic ignored \"-Wunknown-attributes\"") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("warning(disable:1292)") +#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:1292)) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:5030)) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(20,7,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097,1098") +#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097") +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("error_messages(off,attrskipunsup)") +#elif \ + JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1173") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress=Pe1097") +#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wcast-qual") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("clang diagnostic ignored \"-Wcast-qual\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("warning(disable:2203 2331)") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("GCC diagnostic ignored \"-Wcast-qual\"") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunused-function") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("clang diagnostic ignored \"-Wunused-function\"") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("GCC diagnostic ignored \"-Wunused-function\"") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(1,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION __pragma(warning(disable:4505)) +#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("diag_suppress 3142") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION +#endif + +#if defined(JSON_HEDLEY_DEPRECATED) + #undef JSON_HEDLEY_DEPRECATED +#endif +#if defined(JSON_HEDLEY_DEPRECATED_FOR) + #undef JSON_HEDLEY_DEPRECATED_FOR +#endif +#if \ + JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated("Since " # since)) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated("Since " #since "; use " #replacement)) +#elif \ + (JSON_HEDLEY_HAS_EXTENSION(attribute_deprecated_with_message) && !defined(JSON_HEDLEY_IAR_VERSION)) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(18,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__("Since " #since))) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__("Since " #since "; use " #replacement))) +#elif defined(__cplusplus) && (__cplusplus >= 201402L) + #define JSON_HEDLEY_DEPRECATED(since) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since)]]) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since "; use " #replacement)]]) +#elif \ + JSON_HEDLEY_HAS_ATTRIBUTE(deprecated) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) + #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__)) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__)) +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ + JSON_HEDLEY_PELLES_VERSION_CHECK(6,50,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated) +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DEPRECATED(since) _Pragma("deprecated") + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) _Pragma("deprecated") +#else + #define JSON_HEDLEY_DEPRECATED(since) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) +#endif + +#if defined(JSON_HEDLEY_UNAVAILABLE) + #undef JSON_HEDLEY_UNAVAILABLE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(warning) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_UNAVAILABLE(available_since) __attribute__((__warning__("Not available until " #available_since))) +#else + #define JSON_HEDLEY_UNAVAILABLE(available_since) +#endif + +#if defined(JSON_HEDLEY_WARN_UNUSED_RESULT) + #undef JSON_HEDLEY_WARN_UNUSED_RESULT +#endif +#if defined(JSON_HEDLEY_WARN_UNUSED_RESULT_MSG) + #undef JSON_HEDLEY_WARN_UNUSED_RESULT_MSG +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(warn_unused_result) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__)) + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) __attribute__((__warn_unused_result__)) +#elif (JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard) >= 201907L) + #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard(msg)]]) +#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard) + #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) +#elif defined(_Check_return_) /* SAL */ + #define JSON_HEDLEY_WARN_UNUSED_RESULT _Check_return_ + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) _Check_return_ +#else + #define JSON_HEDLEY_WARN_UNUSED_RESULT + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) +#endif + +#if defined(JSON_HEDLEY_SENTINEL) + #undef JSON_HEDLEY_SENTINEL +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(sentinel) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_SENTINEL(position) __attribute__((__sentinel__(position))) +#else + #define JSON_HEDLEY_SENTINEL(position) +#endif + +#if defined(JSON_HEDLEY_NO_RETURN) + #undef JSON_HEDLEY_NO_RETURN +#endif +#if JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_NO_RETURN __noreturn +#elif \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__)) +#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L + #define JSON_HEDLEY_NO_RETURN _Noreturn +#elif defined(__cplusplus) && (__cplusplus >= 201103L) + #define JSON_HEDLEY_NO_RETURN JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[noreturn]]) +#elif \ + JSON_HEDLEY_HAS_ATTRIBUTE(noreturn) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,2,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) + #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__)) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) + #define JSON_HEDLEY_NO_RETURN _Pragma("does_not_return") +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_NO_RETURN __declspec(noreturn) +#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus) + #define JSON_HEDLEY_NO_RETURN _Pragma("FUNC_NEVER_RETURNS;") +#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0) + #define JSON_HEDLEY_NO_RETURN __attribute((noreturn)) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0) + #define JSON_HEDLEY_NO_RETURN __declspec(noreturn) +#else + #define JSON_HEDLEY_NO_RETURN +#endif + +#if defined(JSON_HEDLEY_NO_ESCAPE) + #undef JSON_HEDLEY_NO_ESCAPE +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(noescape) + #define JSON_HEDLEY_NO_ESCAPE __attribute__((__noescape__)) +#else + #define JSON_HEDLEY_NO_ESCAPE +#endif + +#if defined(JSON_HEDLEY_UNREACHABLE) + #undef JSON_HEDLEY_UNREACHABLE +#endif +#if defined(JSON_HEDLEY_UNREACHABLE_RETURN) + #undef JSON_HEDLEY_UNREACHABLE_RETURN +#endif +#if defined(JSON_HEDLEY_ASSUME) + #undef JSON_HEDLEY_ASSUME +#endif +#if \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_ASSUME(expr) __assume(expr) +#elif JSON_HEDLEY_HAS_BUILTIN(__builtin_assume) + #define JSON_HEDLEY_ASSUME(expr) __builtin_assume(expr) +#elif \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) + #if defined(__cplusplus) + #define JSON_HEDLEY_ASSUME(expr) std::_nassert(expr) + #else + #define JSON_HEDLEY_ASSUME(expr) _nassert(expr) + #endif +#endif +#if \ + (JSON_HEDLEY_HAS_BUILTIN(__builtin_unreachable) && (!defined(JSON_HEDLEY_ARM_VERSION))) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(18,10,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,5) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(10,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_UNREACHABLE() __builtin_unreachable() +#elif defined(JSON_HEDLEY_ASSUME) + #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0) +#endif +#if !defined(JSON_HEDLEY_ASSUME) + #if defined(JSON_HEDLEY_UNREACHABLE) + #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, ((expr) ? 1 : (JSON_HEDLEY_UNREACHABLE(), 1))) + #else + #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, expr) + #endif +#endif +#if defined(JSON_HEDLEY_UNREACHABLE) + #if \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) + #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (JSON_HEDLEY_STATIC_CAST(void, JSON_HEDLEY_ASSUME(0)), (value)) + #else + #define JSON_HEDLEY_UNREACHABLE_RETURN(value) JSON_HEDLEY_UNREACHABLE() + #endif +#else + #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (value) +#endif +#if !defined(JSON_HEDLEY_UNREACHABLE) + #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0) +#endif + +JSON_HEDLEY_DIAGNOSTIC_PUSH +#if JSON_HEDLEY_HAS_WARNING("-Wpedantic") + #pragma clang diagnostic ignored "-Wpedantic" +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat-pedantic") && defined(__cplusplus) + #pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +#endif +#if JSON_HEDLEY_GCC_HAS_WARNING("-Wvariadic-macros",4,0,0) + #if defined(__clang__) + #pragma clang diagnostic ignored "-Wvariadic-macros" + #elif defined(JSON_HEDLEY_GCC_VERSION) + #pragma GCC diagnostic ignored "-Wvariadic-macros" + #endif +#endif +#if defined(JSON_HEDLEY_NON_NULL) + #undef JSON_HEDLEY_NON_NULL +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(nonnull) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) + #define JSON_HEDLEY_NON_NULL(...) __attribute__((__nonnull__(__VA_ARGS__))) +#else + #define JSON_HEDLEY_NON_NULL(...) +#endif +JSON_HEDLEY_DIAGNOSTIC_POP + +#if defined(JSON_HEDLEY_PRINTF_FORMAT) + #undef JSON_HEDLEY_PRINTF_FORMAT +#endif +#if defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && !defined(__USE_MINGW_ANSI_STDIO) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(ms_printf, string_idx, first_to_check))) +#elif defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && defined(__USE_MINGW_ANSI_STDIO) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(gnu_printf, string_idx, first_to_check))) +#elif \ + JSON_HEDLEY_HAS_ATTRIBUTE(format) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(__printf__, string_idx, first_to_check))) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(6,0,0) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __declspec(vaformat(printf,string_idx,first_to_check)) +#else + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) +#endif + +#if defined(JSON_HEDLEY_CONSTEXPR) + #undef JSON_HEDLEY_CONSTEXPR +#endif +#if defined(__cplusplus) + #if __cplusplus >= 201103L + #define JSON_HEDLEY_CONSTEXPR JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(constexpr) + #endif +#endif +#if !defined(JSON_HEDLEY_CONSTEXPR) + #define JSON_HEDLEY_CONSTEXPR +#endif + +#if defined(JSON_HEDLEY_PREDICT) + #undef JSON_HEDLEY_PREDICT +#endif +#if defined(JSON_HEDLEY_LIKELY) + #undef JSON_HEDLEY_LIKELY +#endif +#if defined(JSON_HEDLEY_UNLIKELY) + #undef JSON_HEDLEY_UNLIKELY +#endif +#if defined(JSON_HEDLEY_UNPREDICTABLE) + #undef JSON_HEDLEY_UNPREDICTABLE +#endif +#if JSON_HEDLEY_HAS_BUILTIN(__builtin_unpredictable) + #define JSON_HEDLEY_UNPREDICTABLE(expr) __builtin_unpredictable((expr)) +#endif +#if \ + (JSON_HEDLEY_HAS_BUILTIN(__builtin_expect_with_probability) && !defined(JSON_HEDLEY_PGI_VERSION)) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(9,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) +# define JSON_HEDLEY_PREDICT(expr, value, probability) __builtin_expect_with_probability( (expr), (value), (probability)) +# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) __builtin_expect_with_probability(!!(expr), 1 , (probability)) +# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) __builtin_expect_with_probability(!!(expr), 0 , (probability)) +# define JSON_HEDLEY_LIKELY(expr) __builtin_expect (!!(expr), 1 ) +# define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect (!!(expr), 0 ) +#elif \ + (JSON_HEDLEY_HAS_BUILTIN(__builtin_expect) && !defined(JSON_HEDLEY_INTEL_CL_VERSION)) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,27) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) +# define JSON_HEDLEY_PREDICT(expr, expected, probability) \ + (((probability) >= 0.9) ? __builtin_expect((expr), (expected)) : (JSON_HEDLEY_STATIC_CAST(void, expected), (expr))) +# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) \ + (__extension__ ({ \ + double hedley_probability_ = (probability); \ + ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 1) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 0) : !!(expr))); \ + })) +# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) \ + (__extension__ ({ \ + double hedley_probability_ = (probability); \ + ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 0) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 1) : !!(expr))); \ + })) +# define JSON_HEDLEY_LIKELY(expr) __builtin_expect(!!(expr), 1) +# define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0) +#else +# define JSON_HEDLEY_PREDICT(expr, expected, probability) (JSON_HEDLEY_STATIC_CAST(void, expected), (expr)) +# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) (!!(expr)) +# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) (!!(expr)) +# define JSON_HEDLEY_LIKELY(expr) (!!(expr)) +# define JSON_HEDLEY_UNLIKELY(expr) (!!(expr)) +#endif +#if !defined(JSON_HEDLEY_UNPREDICTABLE) + #define JSON_HEDLEY_UNPREDICTABLE(expr) JSON_HEDLEY_PREDICT(expr, 1, 0.5) +#endif + +#if defined(JSON_HEDLEY_MALLOC) + #undef JSON_HEDLEY_MALLOC +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(malloc) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_MALLOC __attribute__((__malloc__)) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) + #define JSON_HEDLEY_MALLOC _Pragma("returns_new_memory") +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_MALLOC __declspec(restrict) +#else + #define JSON_HEDLEY_MALLOC +#endif + +#if defined(JSON_HEDLEY_PURE) + #undef JSON_HEDLEY_PURE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(pure) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(2,96,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) +# define JSON_HEDLEY_PURE __attribute__((__pure__)) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) +# define JSON_HEDLEY_PURE _Pragma("does_not_write_global_data") +#elif defined(__cplusplus) && \ + ( \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) \ + ) +# define JSON_HEDLEY_PURE _Pragma("FUNC_IS_PURE;") +#else +# define JSON_HEDLEY_PURE +#endif + +#if defined(JSON_HEDLEY_CONST) + #undef JSON_HEDLEY_CONST +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(const) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(2,5,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_CONST __attribute__((__const__)) +#elif \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) + #define JSON_HEDLEY_CONST _Pragma("no_side_effect") +#else + #define JSON_HEDLEY_CONST JSON_HEDLEY_PURE +#endif + +#if defined(JSON_HEDLEY_RESTRICT) + #undef JSON_HEDLEY_RESTRICT +#endif +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && !defined(__cplusplus) + #define JSON_HEDLEY_RESTRICT restrict +#elif \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,4) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ + defined(__clang__) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_RESTRICT __restrict +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,3,0) && !defined(__cplusplus) + #define JSON_HEDLEY_RESTRICT _Restrict +#else + #define JSON_HEDLEY_RESTRICT +#endif + +#if defined(JSON_HEDLEY_INLINE) + #undef JSON_HEDLEY_INLINE +#endif +#if \ + (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ + (defined(__cplusplus) && (__cplusplus >= 199711L)) + #define JSON_HEDLEY_INLINE inline +#elif \ + defined(JSON_HEDLEY_GCC_VERSION) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(6,2,0) + #define JSON_HEDLEY_INLINE __inline__ +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,1,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_INLINE __inline +#else + #define JSON_HEDLEY_INLINE +#endif + +#if defined(JSON_HEDLEY_ALWAYS_INLINE) + #undef JSON_HEDLEY_ALWAYS_INLINE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(always_inline) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) +# define JSON_HEDLEY_ALWAYS_INLINE __attribute__((__always_inline__)) JSON_HEDLEY_INLINE +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) +# define JSON_HEDLEY_ALWAYS_INLINE __forceinline +#elif defined(__cplusplus) && \ + ( \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) \ + ) +# define JSON_HEDLEY_ALWAYS_INLINE _Pragma("FUNC_ALWAYS_INLINE;") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) +# define JSON_HEDLEY_ALWAYS_INLINE _Pragma("inline=forced") +#else +# define JSON_HEDLEY_ALWAYS_INLINE JSON_HEDLEY_INLINE +#endif + +#if defined(JSON_HEDLEY_NEVER_INLINE) + #undef JSON_HEDLEY_NEVER_INLINE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(noinline) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) + #define JSON_HEDLEY_NEVER_INLINE __attribute__((__noinline__)) +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(10,2,0) + #define JSON_HEDLEY_NEVER_INLINE _Pragma("noinline") +#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus) + #define JSON_HEDLEY_NEVER_INLINE _Pragma("FUNC_CANNOT_INLINE;") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_NEVER_INLINE _Pragma("inline=never") +#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0) + #define JSON_HEDLEY_NEVER_INLINE __attribute((noinline)) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0) + #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline) +#else + #define JSON_HEDLEY_NEVER_INLINE +#endif + +#if defined(JSON_HEDLEY_PRIVATE) + #undef JSON_HEDLEY_PRIVATE +#endif +#if defined(JSON_HEDLEY_PUBLIC) + #undef JSON_HEDLEY_PUBLIC +#endif +#if defined(JSON_HEDLEY_IMPORT) + #undef JSON_HEDLEY_IMPORT +#endif +#if defined(_WIN32) || defined(__CYGWIN__) +# define JSON_HEDLEY_PRIVATE +# define JSON_HEDLEY_PUBLIC __declspec(dllexport) +# define JSON_HEDLEY_IMPORT __declspec(dllimport) +#else +# if \ + JSON_HEDLEY_HAS_ATTRIBUTE(visibility) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ + ( \ + defined(__TI_EABI__) && \ + ( \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) \ + ) \ + ) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) +# define JSON_HEDLEY_PRIVATE __attribute__((__visibility__("hidden"))) +# define JSON_HEDLEY_PUBLIC __attribute__((__visibility__("default"))) +# else +# define JSON_HEDLEY_PRIVATE +# define JSON_HEDLEY_PUBLIC +# endif +# define JSON_HEDLEY_IMPORT extern +#endif + +#if defined(JSON_HEDLEY_NO_THROW) + #undef JSON_HEDLEY_NO_THROW +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(nothrow) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_NO_THROW __attribute__((__nothrow__)) +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,1,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) + #define JSON_HEDLEY_NO_THROW __declspec(nothrow) +#else + #define JSON_HEDLEY_NO_THROW +#endif + +#if defined(JSON_HEDLEY_FALL_THROUGH) + #undef JSON_HEDLEY_FALL_THROUGH +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(fallthrough) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(7,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_FALL_THROUGH __attribute__((__fallthrough__)) +#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(clang,fallthrough) + #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[clang::fallthrough]]) +#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(fallthrough) + #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[fallthrough]]) +#elif defined(__fallthrough) /* SAL */ + #define JSON_HEDLEY_FALL_THROUGH __fallthrough +#else + #define JSON_HEDLEY_FALL_THROUGH +#endif + +#if defined(JSON_HEDLEY_RETURNS_NON_NULL) + #undef JSON_HEDLEY_RETURNS_NON_NULL +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(returns_nonnull) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_RETURNS_NON_NULL __attribute__((__returns_nonnull__)) +#elif defined(_Ret_notnull_) /* SAL */ + #define JSON_HEDLEY_RETURNS_NON_NULL _Ret_notnull_ +#else + #define JSON_HEDLEY_RETURNS_NON_NULL +#endif + +#if defined(JSON_HEDLEY_ARRAY_PARAM) + #undef JSON_HEDLEY_ARRAY_PARAM +#endif +#if \ + defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ + !defined(__STDC_NO_VLA__) && \ + !defined(__cplusplus) && \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_TINYC_VERSION) + #define JSON_HEDLEY_ARRAY_PARAM(name) (name) +#else + #define JSON_HEDLEY_ARRAY_PARAM(name) +#endif + +#if defined(JSON_HEDLEY_IS_CONSTANT) + #undef JSON_HEDLEY_IS_CONSTANT +#endif +#if defined(JSON_HEDLEY_REQUIRE_CONSTEXPR) + #undef JSON_HEDLEY_REQUIRE_CONSTEXPR +#endif +/* JSON_HEDLEY_IS_CONSTEXPR_ is for + HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ +#if defined(JSON_HEDLEY_IS_CONSTEXPR_) + #undef JSON_HEDLEY_IS_CONSTEXPR_ +#endif +#if \ + JSON_HEDLEY_HAS_BUILTIN(__builtin_constant_p) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,19) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) && !defined(__cplusplus)) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_IS_CONSTANT(expr) __builtin_constant_p(expr) +#endif +#if !defined(__cplusplus) +# if \ + JSON_HEDLEY_HAS_BUILTIN(__builtin_types_compatible_p) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,24) +#if defined(__INTPTR_TYPE__) + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0)), int*) +#else + #include + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((intptr_t) ((expr) * 0)) : (int*) 0)), int*) +#endif +# elif \ + ( \ + defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && \ + !defined(JSON_HEDLEY_SUNPRO_VERSION) && \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_IAR_VERSION)) || \ + (JSON_HEDLEY_HAS_EXTENSION(c_generic_selections) && !defined(JSON_HEDLEY_IAR_VERSION)) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,3,0) +#if defined(__INTPTR_TYPE__) + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0), int*: 1, void*: 0) +#else + #include + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((intptr_t) * 0) : (int*) 0), int*: 1, void*: 0) +#endif +# elif \ + defined(JSON_HEDLEY_GCC_VERSION) || \ + defined(JSON_HEDLEY_INTEL_VERSION) || \ + defined(JSON_HEDLEY_TINYC_VERSION) || \ + defined(JSON_HEDLEY_TI_ARMCL_VERSION) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(18,12,0) || \ + defined(JSON_HEDLEY_TI_CL2000_VERSION) || \ + defined(JSON_HEDLEY_TI_CL6X_VERSION) || \ + defined(JSON_HEDLEY_TI_CL7X_VERSION) || \ + defined(JSON_HEDLEY_TI_CLPRU_VERSION) || \ + defined(__clang__) +# define JSON_HEDLEY_IS_CONSTEXPR_(expr) ( \ + sizeof(void) != \ + sizeof(*( \ + 1 ? \ + ((void*) ((expr) * 0L) ) : \ +((struct { char v[sizeof(void) * 2]; } *) 1) \ + ) \ + ) \ + ) +# endif +#endif +#if defined(JSON_HEDLEY_IS_CONSTEXPR_) + #if !defined(JSON_HEDLEY_IS_CONSTANT) + #define JSON_HEDLEY_IS_CONSTANT(expr) JSON_HEDLEY_IS_CONSTEXPR_(expr) + #endif + #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (JSON_HEDLEY_IS_CONSTEXPR_(expr) ? (expr) : (-1)) +#else + #if !defined(JSON_HEDLEY_IS_CONSTANT) + #define JSON_HEDLEY_IS_CONSTANT(expr) (0) + #endif + #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (expr) +#endif + +#if defined(JSON_HEDLEY_BEGIN_C_DECLS) + #undef JSON_HEDLEY_BEGIN_C_DECLS +#endif +#if defined(JSON_HEDLEY_END_C_DECLS) + #undef JSON_HEDLEY_END_C_DECLS +#endif +#if defined(JSON_HEDLEY_C_DECL) + #undef JSON_HEDLEY_C_DECL +#endif +#if defined(__cplusplus) + #define JSON_HEDLEY_BEGIN_C_DECLS extern "C" { + #define JSON_HEDLEY_END_C_DECLS } + #define JSON_HEDLEY_C_DECL extern "C" +#else + #define JSON_HEDLEY_BEGIN_C_DECLS + #define JSON_HEDLEY_END_C_DECLS + #define JSON_HEDLEY_C_DECL +#endif + +#if defined(JSON_HEDLEY_STATIC_ASSERT) + #undef JSON_HEDLEY_STATIC_ASSERT +#endif +#if \ + !defined(__cplusplus) && ( \ + (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || \ + (JSON_HEDLEY_HAS_FEATURE(c_static_assert) && !defined(JSON_HEDLEY_INTEL_CL_VERSION)) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(6,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + defined(_Static_assert) \ + ) +# define JSON_HEDLEY_STATIC_ASSERT(expr, message) _Static_assert(expr, message) +#elif \ + (defined(__cplusplus) && (__cplusplus >= 201103L)) || \ + JSON_HEDLEY_MSVC_VERSION_CHECK(16,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) +# define JSON_HEDLEY_STATIC_ASSERT(expr, message) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(static_assert(expr, message)) +#else +# define JSON_HEDLEY_STATIC_ASSERT(expr, message) +#endif + +#if defined(JSON_HEDLEY_NULL) + #undef JSON_HEDLEY_NULL +#endif +#if defined(__cplusplus) + #if __cplusplus >= 201103L + #define JSON_HEDLEY_NULL JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(nullptr) + #elif defined(NULL) + #define JSON_HEDLEY_NULL NULL + #else + #define JSON_HEDLEY_NULL JSON_HEDLEY_STATIC_CAST(void*, 0) + #endif +#elif defined(NULL) + #define JSON_HEDLEY_NULL NULL +#else + #define JSON_HEDLEY_NULL ((void*) 0) +#endif + +#if defined(JSON_HEDLEY_MESSAGE) + #undef JSON_HEDLEY_MESSAGE +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") +# define JSON_HEDLEY_MESSAGE(msg) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + JSON_HEDLEY_PRAGMA(message msg) \ + JSON_HEDLEY_DIAGNOSTIC_POP +#elif \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message msg) +#elif JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(_CRI message msg) +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg)) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg)) +#else +# define JSON_HEDLEY_MESSAGE(msg) +#endif + +#if defined(JSON_HEDLEY_WARNING) + #undef JSON_HEDLEY_WARNING +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") +# define JSON_HEDLEY_WARNING(msg) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + JSON_HEDLEY_PRAGMA(clang warning msg) \ + JSON_HEDLEY_DIAGNOSTIC_POP +#elif \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,8,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) +# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(GCC warning msg) +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) +# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(message(msg)) +#else +# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_MESSAGE(msg) +#endif + +#if defined(JSON_HEDLEY_REQUIRE) + #undef JSON_HEDLEY_REQUIRE +#endif +#if defined(JSON_HEDLEY_REQUIRE_MSG) + #undef JSON_HEDLEY_REQUIRE_MSG +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(diagnose_if) +# if JSON_HEDLEY_HAS_WARNING("-Wgcc-compat") +# define JSON_HEDLEY_REQUIRE(expr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ + __attribute__((diagnose_if(!(expr), #expr, "error"))) \ + JSON_HEDLEY_DIAGNOSTIC_POP +# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ + __attribute__((diagnose_if(!(expr), msg, "error"))) \ + JSON_HEDLEY_DIAGNOSTIC_POP +# else +# define JSON_HEDLEY_REQUIRE(expr) __attribute__((diagnose_if(!(expr), #expr, "error"))) +# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) __attribute__((diagnose_if(!(expr), msg, "error"))) +# endif +#else +# define JSON_HEDLEY_REQUIRE(expr) +# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) +#endif + +#if defined(JSON_HEDLEY_FLAGS) + #undef JSON_HEDLEY_FLAGS +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(flag_enum) && (!defined(__cplusplus) || JSON_HEDLEY_HAS_WARNING("-Wbitfield-enum-conversion")) + #define JSON_HEDLEY_FLAGS __attribute__((__flag_enum__)) +#else + #define JSON_HEDLEY_FLAGS +#endif + +#if defined(JSON_HEDLEY_FLAGS_CAST) + #undef JSON_HEDLEY_FLAGS_CAST +#endif +#if JSON_HEDLEY_INTEL_VERSION_CHECK(19,0,0) +# define JSON_HEDLEY_FLAGS_CAST(T, expr) (__extension__ ({ \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("warning(disable:188)") \ + ((T) (expr)); \ + JSON_HEDLEY_DIAGNOSTIC_POP \ + })) +#else +# define JSON_HEDLEY_FLAGS_CAST(T, expr) JSON_HEDLEY_STATIC_CAST(T, expr) +#endif + +#if defined(JSON_HEDLEY_EMPTY_BASES) + #undef JSON_HEDLEY_EMPTY_BASES +#endif +#if \ + (JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,23918) && !JSON_HEDLEY_MSVC_VERSION_CHECK(20,0,0)) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_EMPTY_BASES __declspec(empty_bases) +#else + #define JSON_HEDLEY_EMPTY_BASES +#endif + +/* Remaining macros are deprecated. */ + +#if defined(JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK) + #undef JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK +#endif +#if defined(__clang__) + #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) (0) +#else + #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_CLANG_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE +#endif +#define JSON_HEDLEY_CLANG_HAS_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_ATTRIBUTE(attribute) + +#if defined(JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE +#endif +#define JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) + +#if defined(JSON_HEDLEY_CLANG_HAS_BUILTIN) + #undef JSON_HEDLEY_CLANG_HAS_BUILTIN +#endif +#define JSON_HEDLEY_CLANG_HAS_BUILTIN(builtin) JSON_HEDLEY_HAS_BUILTIN(builtin) + +#if defined(JSON_HEDLEY_CLANG_HAS_FEATURE) + #undef JSON_HEDLEY_CLANG_HAS_FEATURE +#endif +#define JSON_HEDLEY_CLANG_HAS_FEATURE(feature) JSON_HEDLEY_HAS_FEATURE(feature) + +#if defined(JSON_HEDLEY_CLANG_HAS_EXTENSION) + #undef JSON_HEDLEY_CLANG_HAS_EXTENSION +#endif +#define JSON_HEDLEY_CLANG_HAS_EXTENSION(extension) JSON_HEDLEY_HAS_EXTENSION(extension) + +#if defined(JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE +#endif +#define JSON_HEDLEY_CLANG_HAS_DECLSPEC_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) + +#if defined(JSON_HEDLEY_CLANG_HAS_WARNING) + #undef JSON_HEDLEY_CLANG_HAS_WARNING +#endif +#define JSON_HEDLEY_CLANG_HAS_WARNING(warning) JSON_HEDLEY_HAS_WARNING(warning) + +#endif /* !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < X) */ + +// #include + + +#include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +template struct make_void +{ + using type = void; +}; +template using void_t = typename make_void::type; +} // namespace detail +} // namespace nlohmann + + +// https://en.cppreference.com/w/cpp/experimental/is_detected +namespace nlohmann +{ +namespace detail +{ +struct nonesuch +{ + nonesuch() = delete; + ~nonesuch() = delete; + nonesuch(nonesuch const&) = delete; + nonesuch(nonesuch const&&) = delete; + void operator=(nonesuch const&) = delete; + void operator=(nonesuch&&) = delete; +}; + +template class Op, + class... Args> +struct detector +{ + using value_t = std::false_type; + using type = Default; +}; + +template class Op, class... Args> +struct detector>, Op, Args...> +{ + using value_t = std::true_type; + using type = Op; +}; + +template class Op, class... Args> +using is_detected = typename detector::value_t; + +template class Op, class... Args> +struct is_detected_lazy : is_detected { }; + +template class Op, class... Args> +using detected_t = typename detector::type; + +template class Op, class... Args> +using detected_or = detector; + +template class Op, class... Args> +using detected_or_t = typename detected_or::type; + +template class Op, class... Args> +using is_detected_exact = std::is_same>; + +template class Op, class... Args> +using is_detected_convertible = + std::is_convertible, To>; +} // namespace detail +} // namespace nlohmann + + +// This file contains all internal macro definitions +// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them + +// exclude unsupported compilers +#if !defined(JSON_SKIP_UNSUPPORTED_COMPILER_CHECK) + #if defined(__clang__) + #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 + #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" + #endif + #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) + #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800 + #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" + #endif + #endif +#endif + +// C++ language standard detection +// if the user manually specified the used c++ version this is skipped +#if !defined(JSON_HAS_CPP_20) && !defined(JSON_HAS_CPP_17) && !defined(JSON_HAS_CPP_14) && !defined(JSON_HAS_CPP_11) + #if (defined(__cplusplus) && __cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) + #define JSON_HAS_CPP_20 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 + #elif (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 + #elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) + #define JSON_HAS_CPP_14 + #endif + // the cpp 11 flag is always specified because it is the minimal required version + #define JSON_HAS_CPP_11 +#endif + +// disable documentation warnings on clang +#if defined(__clang__) + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wdocumentation" + #pragma clang diagnostic ignored "-Wdocumentation-unknown-command" +#endif + +// allow to disable exceptions +#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION) + #define JSON_THROW(exception) throw exception + #define JSON_TRY try + #define JSON_CATCH(exception) catch(exception) + #define JSON_INTERNAL_CATCH(exception) catch(exception) +#else + #include + #define JSON_THROW(exception) std::abort() + #define JSON_TRY if(true) + #define JSON_CATCH(exception) if(false) + #define JSON_INTERNAL_CATCH(exception) if(false) +#endif + +// override exception macros +#if defined(JSON_THROW_USER) + #undef JSON_THROW + #define JSON_THROW JSON_THROW_USER +#endif +#if defined(JSON_TRY_USER) + #undef JSON_TRY + #define JSON_TRY JSON_TRY_USER +#endif +#if defined(JSON_CATCH_USER) + #undef JSON_CATCH + #define JSON_CATCH JSON_CATCH_USER + #undef JSON_INTERNAL_CATCH + #define JSON_INTERNAL_CATCH JSON_CATCH_USER +#endif +#if defined(JSON_INTERNAL_CATCH_USER) + #undef JSON_INTERNAL_CATCH + #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER +#endif + +// allow to override assert +#if !defined(JSON_ASSERT) + #include // assert + #define JSON_ASSERT(x) assert(x) +#endif + +// allow to access some private functions (needed by the test suite) +#if defined(JSON_TESTS_PRIVATE) + #define JSON_PRIVATE_UNLESS_TESTED public +#else + #define JSON_PRIVATE_UNLESS_TESTED private +#endif + +/*! +@brief macro to briefly define a mapping between an enum and JSON +@def NLOHMANN_JSON_SERIALIZE_ENUM +@since version 3.4.0 +*/ +#define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...) \ + template \ + inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \ + { \ + static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if(std::begin(m), std::end(m), \ + [e](const std::pair& ej_pair) -> bool \ + { \ + return ej_pair.first == e; \ + }); \ + j = ((it != std::end(m)) ? it : std::begin(m))->second; \ + } \ + template \ + inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \ + { \ + static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if(std::begin(m), std::end(m), \ + [&j](const std::pair& ej_pair) -> bool \ + { \ + return ej_pair.second == j; \ + }); \ + e = ((it != std::end(m)) ? it : std::begin(m))->first; \ + } + +// Ugly macros to avoid uglier copy-paste when specializing basic_json. They +// may be removed in the future once the class is split. + +#define NLOHMANN_BASIC_JSON_TPL_DECLARATION \ + template class ObjectType, \ + template class ArrayType, \ + class StringType, class BooleanType, class NumberIntegerType, \ + class NumberUnsignedType, class NumberFloatType, \ + template class AllocatorType, \ + template class JSONSerializer, \ + class BinaryType> + +#define NLOHMANN_BASIC_JSON_TPL \ + basic_json + +// Macros to simplify conversion from/to types + +#define NLOHMANN_JSON_EXPAND( x ) x +#define NLOHMANN_JSON_GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, NAME,...) NAME +#define NLOHMANN_JSON_PASTE(...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_GET_MACRO(__VA_ARGS__, \ + NLOHMANN_JSON_PASTE64, \ + NLOHMANN_JSON_PASTE63, \ + NLOHMANN_JSON_PASTE62, \ + NLOHMANN_JSON_PASTE61, \ + NLOHMANN_JSON_PASTE60, \ + NLOHMANN_JSON_PASTE59, \ + NLOHMANN_JSON_PASTE58, \ + NLOHMANN_JSON_PASTE57, \ + NLOHMANN_JSON_PASTE56, \ + NLOHMANN_JSON_PASTE55, \ + NLOHMANN_JSON_PASTE54, \ + NLOHMANN_JSON_PASTE53, \ + NLOHMANN_JSON_PASTE52, \ + NLOHMANN_JSON_PASTE51, \ + NLOHMANN_JSON_PASTE50, \ + NLOHMANN_JSON_PASTE49, \ + NLOHMANN_JSON_PASTE48, \ + NLOHMANN_JSON_PASTE47, \ + NLOHMANN_JSON_PASTE46, \ + NLOHMANN_JSON_PASTE45, \ + NLOHMANN_JSON_PASTE44, \ + NLOHMANN_JSON_PASTE43, \ + NLOHMANN_JSON_PASTE42, \ + NLOHMANN_JSON_PASTE41, \ + NLOHMANN_JSON_PASTE40, \ + NLOHMANN_JSON_PASTE39, \ + NLOHMANN_JSON_PASTE38, \ + NLOHMANN_JSON_PASTE37, \ + NLOHMANN_JSON_PASTE36, \ + NLOHMANN_JSON_PASTE35, \ + NLOHMANN_JSON_PASTE34, \ + NLOHMANN_JSON_PASTE33, \ + NLOHMANN_JSON_PASTE32, \ + NLOHMANN_JSON_PASTE31, \ + NLOHMANN_JSON_PASTE30, \ + NLOHMANN_JSON_PASTE29, \ + NLOHMANN_JSON_PASTE28, \ + NLOHMANN_JSON_PASTE27, \ + NLOHMANN_JSON_PASTE26, \ + NLOHMANN_JSON_PASTE25, \ + NLOHMANN_JSON_PASTE24, \ + NLOHMANN_JSON_PASTE23, \ + NLOHMANN_JSON_PASTE22, \ + NLOHMANN_JSON_PASTE21, \ + NLOHMANN_JSON_PASTE20, \ + NLOHMANN_JSON_PASTE19, \ + NLOHMANN_JSON_PASTE18, \ + NLOHMANN_JSON_PASTE17, \ + NLOHMANN_JSON_PASTE16, \ + NLOHMANN_JSON_PASTE15, \ + NLOHMANN_JSON_PASTE14, \ + NLOHMANN_JSON_PASTE13, \ + NLOHMANN_JSON_PASTE12, \ + NLOHMANN_JSON_PASTE11, \ + NLOHMANN_JSON_PASTE10, \ + NLOHMANN_JSON_PASTE9, \ + NLOHMANN_JSON_PASTE8, \ + NLOHMANN_JSON_PASTE7, \ + NLOHMANN_JSON_PASTE6, \ + NLOHMANN_JSON_PASTE5, \ + NLOHMANN_JSON_PASTE4, \ + NLOHMANN_JSON_PASTE3, \ + NLOHMANN_JSON_PASTE2, \ + NLOHMANN_JSON_PASTE1)(__VA_ARGS__)) +#define NLOHMANN_JSON_PASTE2(func, v1) func(v1) +#define NLOHMANN_JSON_PASTE3(func, v1, v2) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE2(func, v2) +#define NLOHMANN_JSON_PASTE4(func, v1, v2, v3) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE3(func, v2, v3) +#define NLOHMANN_JSON_PASTE5(func, v1, v2, v3, v4) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE4(func, v2, v3, v4) +#define NLOHMANN_JSON_PASTE6(func, v1, v2, v3, v4, v5) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE5(func, v2, v3, v4, v5) +#define NLOHMANN_JSON_PASTE7(func, v1, v2, v3, v4, v5, v6) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE6(func, v2, v3, v4, v5, v6) +#define NLOHMANN_JSON_PASTE8(func, v1, v2, v3, v4, v5, v6, v7) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE7(func, v2, v3, v4, v5, v6, v7) +#define NLOHMANN_JSON_PASTE9(func, v1, v2, v3, v4, v5, v6, v7, v8) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE8(func, v2, v3, v4, v5, v6, v7, v8) +#define NLOHMANN_JSON_PASTE10(func, v1, v2, v3, v4, v5, v6, v7, v8, v9) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE9(func, v2, v3, v4, v5, v6, v7, v8, v9) +#define NLOHMANN_JSON_PASTE11(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE10(func, v2, v3, v4, v5, v6, v7, v8, v9, v10) +#define NLOHMANN_JSON_PASTE12(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE11(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) +#define NLOHMANN_JSON_PASTE13(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE12(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) +#define NLOHMANN_JSON_PASTE14(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE13(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) +#define NLOHMANN_JSON_PASTE15(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE14(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) +#define NLOHMANN_JSON_PASTE16(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE15(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) +#define NLOHMANN_JSON_PASTE17(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE16(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) +#define NLOHMANN_JSON_PASTE18(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE17(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) +#define NLOHMANN_JSON_PASTE19(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE18(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) +#define NLOHMANN_JSON_PASTE20(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE19(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) +#define NLOHMANN_JSON_PASTE21(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE20(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) +#define NLOHMANN_JSON_PASTE22(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE21(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) +#define NLOHMANN_JSON_PASTE23(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE22(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) +#define NLOHMANN_JSON_PASTE24(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE23(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) +#define NLOHMANN_JSON_PASTE25(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE24(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) +#define NLOHMANN_JSON_PASTE26(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE25(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) +#define NLOHMANN_JSON_PASTE27(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE26(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) +#define NLOHMANN_JSON_PASTE28(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE27(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) +#define NLOHMANN_JSON_PASTE29(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE28(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) +#define NLOHMANN_JSON_PASTE30(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE29(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) +#define NLOHMANN_JSON_PASTE31(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE30(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) +#define NLOHMANN_JSON_PASTE32(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE31(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) +#define NLOHMANN_JSON_PASTE33(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE32(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) +#define NLOHMANN_JSON_PASTE34(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE33(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) +#define NLOHMANN_JSON_PASTE35(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE34(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) +#define NLOHMANN_JSON_PASTE36(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE35(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) +#define NLOHMANN_JSON_PASTE37(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE36(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) +#define NLOHMANN_JSON_PASTE38(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE37(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) +#define NLOHMANN_JSON_PASTE39(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE38(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) +#define NLOHMANN_JSON_PASTE40(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE39(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) +#define NLOHMANN_JSON_PASTE41(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE40(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) +#define NLOHMANN_JSON_PASTE42(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE41(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) +#define NLOHMANN_JSON_PASTE43(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE42(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) +#define NLOHMANN_JSON_PASTE44(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE43(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) +#define NLOHMANN_JSON_PASTE45(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE44(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) +#define NLOHMANN_JSON_PASTE46(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE45(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) +#define NLOHMANN_JSON_PASTE47(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE46(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) +#define NLOHMANN_JSON_PASTE48(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE47(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) +#define NLOHMANN_JSON_PASTE49(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE48(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) +#define NLOHMANN_JSON_PASTE50(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE49(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) +#define NLOHMANN_JSON_PASTE51(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE50(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) +#define NLOHMANN_JSON_PASTE52(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE51(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) +#define NLOHMANN_JSON_PASTE53(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE52(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) +#define NLOHMANN_JSON_PASTE54(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE53(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) +#define NLOHMANN_JSON_PASTE55(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE54(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) +#define NLOHMANN_JSON_PASTE56(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE55(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) +#define NLOHMANN_JSON_PASTE57(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE56(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) +#define NLOHMANN_JSON_PASTE58(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE57(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) +#define NLOHMANN_JSON_PASTE59(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE58(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) +#define NLOHMANN_JSON_PASTE60(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE59(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) +#define NLOHMANN_JSON_PASTE61(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE60(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) +#define NLOHMANN_JSON_PASTE62(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE61(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) +#define NLOHMANN_JSON_PASTE63(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE62(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) +#define NLOHMANN_JSON_PASTE64(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE63(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) + +#define NLOHMANN_JSON_TO(v1) nlohmann_json_j[#v1] = nlohmann_json_t.v1; +#define NLOHMANN_JSON_FROM(v1) nlohmann_json_j.at(#v1).get_to(nlohmann_json_t.v1); + +/*! +@brief macro +@def NLOHMANN_DEFINE_TYPE_INTRUSIVE +@since version 3.9.0 +*/ +#define NLOHMANN_DEFINE_TYPE_INTRUSIVE(Type, ...) \ + friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } + +/*! +@brief macro +@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE +@since version 3.9.0 +*/ +#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Type, ...) \ + inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } + + +// inspired from https://stackoverflow.com/a/26745591 +// allows to call any std function as if (e.g. with begin): +// using std::begin; begin(x); +// +// it allows using the detected idiom to retrieve the return type +// of such an expression +#define NLOHMANN_CAN_CALL_STD_FUNC_IMPL(std_name) \ + namespace detail { \ + using std::std_name; \ + \ + template \ + using result_of_##std_name = decltype(std_name(std::declval()...)); \ + } \ + \ + namespace detail2 { \ + struct std_name##_tag \ + { \ + }; \ + \ + template \ + std_name##_tag std_name(T&&...); \ + \ + template \ + using result_of_##std_name = decltype(std_name(std::declval()...)); \ + \ + template \ + struct would_call_std_##std_name \ + { \ + static constexpr auto const value = ::nlohmann::detail:: \ + is_detected_exact::value; \ + }; \ + } /* namespace detail2 */ \ + \ + template \ + struct would_call_std_##std_name : detail2::would_call_std_##std_name \ + { \ + } + +#ifndef JSON_USE_IMPLICIT_CONVERSIONS + #define JSON_USE_IMPLICIT_CONVERSIONS 1 +#endif + +#if JSON_USE_IMPLICIT_CONVERSIONS + #define JSON_EXPLICIT +#else + #define JSON_EXPLICIT explicit +#endif + +#ifndef JSON_DIAGNOSTICS + #define JSON_DIAGNOSTICS 0 +#endif + + +namespace nlohmann +{ +namespace detail +{ + +/*! +@brief replace all occurrences of a substring by another string + +@param[in,out] s the string to manipulate; changed so that all + occurrences of @a f are replaced with @a t +@param[in] f the substring to replace with @a t +@param[in] t the string to replace @a f + +@pre The search string @a f must not be empty. **This precondition is +enforced with an assertion.** + +@since version 2.0.0 +*/ +inline void replace_substring(std::string& s, const std::string& f, + const std::string& t) +{ + JSON_ASSERT(!f.empty()); + for (auto pos = s.find(f); // find first occurrence of f + pos != std::string::npos; // make sure f was found + s.replace(pos, f.size(), t), // replace with t, and + pos = s.find(f, pos + t.size())) // find next occurrence of f + {} +} + +/*! + * @brief string escaping as described in RFC 6901 (Sect. 4) + * @param[in] s string to escape + * @return escaped string + * + * Note the order of escaping "~" to "~0" and "/" to "~1" is important. + */ +inline std::string escape(std::string s) +{ + replace_substring(s, "~", "~0"); + replace_substring(s, "/", "~1"); + return s; +} + +/*! + * @brief string unescaping as described in RFC 6901 (Sect. 4) + * @param[in] s string to unescape + * @return unescaped string + * + * Note the order of escaping "~1" to "/" and "~0" to "~" is important. + */ +static void unescape(std::string& s) +{ + replace_substring(s, "~1", "/"); + replace_substring(s, "~0", "~"); +} + +} // namespace detail +} // namespace nlohmann + +// #include + + +#include // size_t + +namespace nlohmann +{ +namespace detail +{ +/// struct to capture the start position of the current token +struct position_t +{ + /// the total number of characters read + std::size_t chars_read_total = 0; + /// the number of characters read in the current line + std::size_t chars_read_current_line = 0; + /// the number of lines read + std::size_t lines_read = 0; + + /// conversion to size_t to preserve SAX interface + constexpr operator size_t() const + { + return chars_read_total; + } +}; + +} // namespace detail +} // namespace nlohmann + +// #include + + +namespace nlohmann +{ +namespace detail +{ +//////////////// +// exceptions // +//////////////// + +/*! +@brief general exception of the @ref basic_json class + +This class is an extension of `std::exception` objects with a member @a id for +exception ids. It is used as the base class for all exceptions thrown by the +@ref basic_json class. This class can hence be used as "wildcard" to catch +exceptions. + +Subclasses: +- @ref parse_error for exceptions indicating a parse error +- @ref invalid_iterator for exceptions indicating errors with iterators +- @ref type_error for exceptions indicating executing a member function with + a wrong type +- @ref out_of_range for exceptions indicating access out of the defined range +- @ref other_error for exceptions indicating other library errors + +@internal +@note To have nothrow-copy-constructible exceptions, we internally use + `std::runtime_error` which can cope with arbitrary-length error messages. + Intermediate strings are built with static functions and then passed to + the actual constructor. +@endinternal + +@liveexample{The following code shows how arbitrary library exceptions can be +caught.,exception} + +@since version 3.0.0 +*/ +class exception : public std::exception +{ + public: + /// returns the explanatory string + const char* what() const noexcept override + { + return m.what(); + } + + /// the id of the exception + const int id; // NOLINT(cppcoreguidelines-non-private-member-variables-in-classes) + + protected: + JSON_HEDLEY_NON_NULL(3) + exception(int id_, const char* what_arg) : id(id_), m(what_arg) {} + + static std::string name(const std::string& ename, int id_) + { + return "[json.exception." + ename + "." + std::to_string(id_) + "] "; + } + + template + static std::string diagnostics(const BasicJsonType& leaf_element) + { +#if JSON_DIAGNOSTICS + std::vector tokens; + for (const auto* current = &leaf_element; current->m_parent != nullptr; current = current->m_parent) + { + switch (current->m_parent->type()) + { + case value_t::array: + { + for (std::size_t i = 0; i < current->m_parent->m_value.array->size(); ++i) + { + if (¤t->m_parent->m_value.array->operator[](i) == current) + { + tokens.emplace_back(std::to_string(i)); + break; + } + } + break; + } + + case value_t::object: + { + for (const auto& element : *current->m_parent->m_value.object) + { + if (&element.second == current) + { + tokens.emplace_back(element.first.c_str()); + break; + } + } + break; + } + + case value_t::null: // LCOV_EXCL_LINE + case value_t::string: // LCOV_EXCL_LINE + case value_t::boolean: // LCOV_EXCL_LINE + case value_t::number_integer: // LCOV_EXCL_LINE + case value_t::number_unsigned: // LCOV_EXCL_LINE + case value_t::number_float: // LCOV_EXCL_LINE + case value_t::binary: // LCOV_EXCL_LINE + case value_t::discarded: // LCOV_EXCL_LINE + default: // LCOV_EXCL_LINE + break; // LCOV_EXCL_LINE + } + } + + if (tokens.empty()) + { + return ""; + } + + return "(" + std::accumulate(tokens.rbegin(), tokens.rend(), std::string{}, + [](const std::string & a, const std::string & b) + { + return a + "/" + detail::escape(b); + }) + ") "; +#else + static_cast(leaf_element); + return ""; +#endif + } + + private: + /// an exception object as storage for error messages + std::runtime_error m; +}; + +/*! +@brief exception indicating a parse error + +This exception is thrown by the library when a parse error occurs. Parse errors +can occur during the deserialization of JSON text, CBOR, MessagePack, as well +as when using JSON Patch. + +Member @a byte holds the byte index of the last read character in the input +file. + +Exceptions have ids 1xx. + +name / id | example message | description +------------------------------ | --------------- | ------------------------- +json.exception.parse_error.101 | parse error at 2: unexpected end of input; expected string literal | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @a byte indicates the error position. +json.exception.parse_error.102 | parse error at 14: missing or wrong low surrogate | JSON uses the `\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\uxxxx` entries ("surrogate pairs"). This error indicates that the surrogate pair is incomplete or contains an invalid code point. +json.exception.parse_error.103 | parse error: code points above 0x10FFFF are invalid | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid. +json.exception.parse_error.104 | parse error: JSON patch must be an array of objects | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects. +json.exception.parse_error.105 | parse error: operation must have string member 'op' | An operation of a JSON Patch document must contain exactly one "op" member, whose value indicates the operation to perform. Its value must be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors. +json.exception.parse_error.106 | parse error: array index '01' must not begin with '0' | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number without a leading `0`. +json.exception.parse_error.107 | parse error: JSON pointer must be empty or begin with '/' - was: 'foo' | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character. +json.exception.parse_error.108 | parse error: escape character '~' must be followed with '0' or '1' | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. +json.exception.parse_error.109 | parse error: array index 'one' is not a number | A JSON Pointer array index must be a number. +json.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read. +json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xF8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read. +json.exception.parse_error.113 | parse error at 2: expected a CBOR string; last byte: 0x98 | While parsing a map key, a value that is not a string has been read. +json.exception.parse_error.114 | parse error: Unsupported BSON record type 0x0F | The parsing of the corresponding BSON record type is not implemented (yet). +json.exception.parse_error.115 | parse error at byte 5: syntax error while parsing UBJSON high-precision number: invalid number text: 1A | A UBJSON high-precision number could not be parsed. + +@note For an input with n bytes, 1 is the index of the first character and n+1 + is the index of the terminating null byte or the end of file. This also + holds true when reading a byte vector (CBOR or MessagePack). + +@liveexample{The following code shows how a `parse_error` exception can be +caught.,parse_error} + +@sa - @ref exception for the base class of the library exceptions +@sa - @ref invalid_iterator for exceptions indicating errors with iterators +@sa - @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa - @ref out_of_range for exceptions indicating access out of the defined range +@sa - @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class parse_error : public exception +{ + public: + /*! + @brief create a parse error exception + @param[in] id_ the id of the exception + @param[in] pos the position where the error occurred (or with + chars_read_total=0 if the position cannot be + determined) + @param[in] what_arg the explanatory string + @return parse_error object + */ + template + static parse_error create(int id_, const position_t& pos, const std::string& what_arg, const BasicJsonType& context) + { + std::string w = exception::name("parse_error", id_) + "parse error" + + position_string(pos) + ": " + exception::diagnostics(context) + what_arg; + return parse_error(id_, pos.chars_read_total, w.c_str()); + } + + template + static parse_error create(int id_, std::size_t byte_, const std::string& what_arg, const BasicJsonType& context) + { + std::string w = exception::name("parse_error", id_) + "parse error" + + (byte_ != 0 ? (" at byte " + std::to_string(byte_)) : "") + + ": " + exception::diagnostics(context) + what_arg; + return parse_error(id_, byte_, w.c_str()); + } + + /*! + @brief byte index of the parse error + + The byte index of the last read character in the input file. + + @note For an input with n bytes, 1 is the index of the first character and + n+1 is the index of the terminating null byte or the end of file. + This also holds true when reading a byte vector (CBOR or MessagePack). + */ + const std::size_t byte; + + private: + parse_error(int id_, std::size_t byte_, const char* what_arg) + : exception(id_, what_arg), byte(byte_) {} + + static std::string position_string(const position_t& pos) + { + return " at line " + std::to_string(pos.lines_read + 1) + + ", column " + std::to_string(pos.chars_read_current_line); + } +}; + +/*! +@brief exception indicating errors with iterators + +This exception is thrown if iterators passed to a library function do not match +the expected semantics. + +Exceptions have ids 2xx. + +name / id | example message | description +----------------------------------- | --------------- | ------------------------- +json.exception.invalid_iterator.201 | iterators are not compatible | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. +json.exception.invalid_iterator.202 | iterator does not fit current value | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion. +json.exception.invalid_iterator.203 | iterators do not fit current value | Either iterator passed to function @ref erase(IteratorType first, IteratorType last) does not belong to the JSON value from which values shall be erased. It hence does not define a valid range to delete values from. +json.exception.invalid_iterator.204 | iterators out of range | When an iterator range for a primitive type (number, boolean, or string) is passed to a constructor or an erase function, this range has to be exactly (@ref begin(), @ref end()), because this is the only way the single stored value is expressed. All other ranges are invalid. +json.exception.invalid_iterator.205 | iterator out of range | When an iterator for a primitive type (number, boolean, or string) is passed to an erase function, the iterator has to be the @ref begin() iterator, because it is the only way to address the stored value. All other iterators are invalid. +json.exception.invalid_iterator.206 | cannot construct with iterators from null | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) belong to a JSON null value and hence to not define a valid range. +json.exception.invalid_iterator.207 | cannot use key() for non-object iterators | The key() member function can only be used on iterators belonging to a JSON object, because other types do not have a concept of a key. +json.exception.invalid_iterator.208 | cannot use operator[] for object iterators | The operator[] to specify a concrete offset cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. +json.exception.invalid_iterator.209 | cannot use offsets with object iterators | The offset operators (+, -, +=, -=) cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. +json.exception.invalid_iterator.210 | iterators do not fit | The iterator range passed to the insert function are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. +json.exception.invalid_iterator.211 | passed iterators may not belong to container | The iterator range passed to the insert function must not be a subrange of the container to insert to. +json.exception.invalid_iterator.212 | cannot compare iterators of different containers | When two iterators are compared, they must belong to the same container. +json.exception.invalid_iterator.213 | cannot compare order of object iterators | The order of object iterators cannot be compared, because JSON objects are unordered. +json.exception.invalid_iterator.214 | cannot get value | Cannot get value for iterator: Either the iterator belongs to a null value or it is an iterator to a primitive type (number, boolean, or string), but the iterator is different to @ref begin(). + +@liveexample{The following code shows how an `invalid_iterator` exception can be +caught.,invalid_iterator} + +@sa - @ref exception for the base class of the library exceptions +@sa - @ref parse_error for exceptions indicating a parse error +@sa - @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa - @ref out_of_range for exceptions indicating access out of the defined range +@sa - @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class invalid_iterator : public exception +{ + public: + template + static invalid_iterator create(int id_, const std::string& what_arg, const BasicJsonType& context) + { + std::string w = exception::name("invalid_iterator", id_) + exception::diagnostics(context) + what_arg; + return invalid_iterator(id_, w.c_str()); + } + + private: + JSON_HEDLEY_NON_NULL(3) + invalid_iterator(int id_, const char* what_arg) + : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating executing a member function with a wrong type + +This exception is thrown in case of a type error; that is, a library function is +executed on a JSON value whose type does not match the expected semantics. + +Exceptions have ids 3xx. + +name / id | example message | description +----------------------------- | --------------- | ------------------------- +json.exception.type_error.301 | cannot create object from initializer list | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead. +json.exception.type_error.302 | type must be object, but is array | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types. +json.exception.type_error.303 | incompatible ReferenceType for get_ref, actual type is object | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t &. +json.exception.type_error.304 | cannot use at() with string | The @ref at() member functions can only be executed for certain JSON types. +json.exception.type_error.305 | cannot use operator[] with string | The @ref operator[] member functions can only be executed for certain JSON types. +json.exception.type_error.306 | cannot use value() with string | The @ref value() member functions can only be executed for certain JSON types. +json.exception.type_error.307 | cannot use erase() with string | The @ref erase() member functions can only be executed for certain JSON types. +json.exception.type_error.308 | cannot use push_back() with string | The @ref push_back() and @ref operator+= member functions can only be executed for certain JSON types. +json.exception.type_error.309 | cannot use insert() with | The @ref insert() member functions can only be executed for certain JSON types. +json.exception.type_error.310 | cannot use swap() with number | The @ref swap() member functions can only be executed for certain JSON types. +json.exception.type_error.311 | cannot use emplace_back() with string | The @ref emplace_back() member function can only be executed for certain JSON types. +json.exception.type_error.312 | cannot use update() with string | The @ref update() member functions can only be executed for certain JSON types. +json.exception.type_error.313 | invalid value to unflatten | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined. +json.exception.type_error.314 | only objects can be unflattened | The @ref unflatten function only works for an object whose keys are JSON Pointers. +json.exception.type_error.315 | values in object must be primitive | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive. +json.exception.type_error.316 | invalid UTF-8 byte at index 10: 0x7E | The @ref dump function only works with UTF-8 encoded strings; that is, if you assign a `std::string` to a JSON value, make sure it is UTF-8 encoded. | +json.exception.type_error.317 | JSON value cannot be serialized to requested format | The dynamic type of the object cannot be represented in the requested serialization format (e.g. a raw `true` or `null` JSON object cannot be serialized to BSON) | + +@liveexample{The following code shows how a `type_error` exception can be +caught.,type_error} + +@sa - @ref exception for the base class of the library exceptions +@sa - @ref parse_error for exceptions indicating a parse error +@sa - @ref invalid_iterator for exceptions indicating errors with iterators +@sa - @ref out_of_range for exceptions indicating access out of the defined range +@sa - @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class type_error : public exception +{ + public: + template + static type_error create(int id_, const std::string& what_arg, const BasicJsonType& context) + { + std::string w = exception::name("type_error", id_) + exception::diagnostics(context) + what_arg; + return type_error(id_, w.c_str()); + } + + private: + JSON_HEDLEY_NON_NULL(3) + type_error(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating access out of the defined range + +This exception is thrown in case a library function is called on an input +parameter that exceeds the expected range, for instance in case of array +indices or nonexisting object keys. + +Exceptions have ids 4xx. + +name / id | example message | description +------------------------------- | --------------- | ------------------------- +json.exception.out_of_range.401 | array index 3 is out of range | The provided array index @a i is larger than @a size-1. +json.exception.out_of_range.402 | array index '-' (3) is out of range | The special array index `-` in a JSON Pointer never describes a valid element of the array, but the index past the end. That is, it can only be used to add elements at this position, but not to read it. +json.exception.out_of_range.403 | key 'foo' not found | The provided key was not found in the JSON object. +json.exception.out_of_range.404 | unresolved reference token 'foo' | A reference token in a JSON Pointer could not be resolved. +json.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value. +json.exception.out_of_range.406 | number overflow parsing '10E1000' | A parsed number could not be stored as without changing it to NaN or INF. +json.exception.out_of_range.407 | number overflow serializing '9223372036854775808' | UBJSON and BSON only support integer numbers up to 9223372036854775807. (until version 3.8.0) | +json.exception.out_of_range.408 | excessive array size: 8658170730974374167 | The size (following `#`) of an UBJSON array or object exceeds the maximal capacity. | +json.exception.out_of_range.409 | BSON key cannot contain code point U+0000 (at byte 2) | Key identifiers to be serialized to BSON cannot contain code point U+0000, since the key is stored as zero-terminated c-string | + +@liveexample{The following code shows how an `out_of_range` exception can be +caught.,out_of_range} + +@sa - @ref exception for the base class of the library exceptions +@sa - @ref parse_error for exceptions indicating a parse error +@sa - @ref invalid_iterator for exceptions indicating errors with iterators +@sa - @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa - @ref other_error for exceptions indicating other library errors + +@since version 3.0.0 +*/ +class out_of_range : public exception +{ + public: + template + static out_of_range create(int id_, const std::string& what_arg, const BasicJsonType& context) + { + std::string w = exception::name("out_of_range", id_) + exception::diagnostics(context) + what_arg; + return out_of_range(id_, w.c_str()); + } + + private: + JSON_HEDLEY_NON_NULL(3) + out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; + +/*! +@brief exception indicating other library errors + +This exception is thrown in case of errors that cannot be classified with the +other exception types. + +Exceptions have ids 5xx. + +name / id | example message | description +------------------------------ | --------------- | ------------------------- +json.exception.other_error.501 | unsuccessful: {"op":"test","path":"/baz", "value":"bar"} | A JSON Patch operation 'test' failed. The unsuccessful operation is also printed. + +@sa - @ref exception for the base class of the library exceptions +@sa - @ref parse_error for exceptions indicating a parse error +@sa - @ref invalid_iterator for exceptions indicating errors with iterators +@sa - @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa - @ref out_of_range for exceptions indicating access out of the defined range + +@liveexample{The following code shows how an `other_error` exception can be +caught.,other_error} + +@since version 3.0.0 +*/ +class other_error : public exception +{ + public: + template + static other_error create(int id_, const std::string& what_arg, const BasicJsonType& context) + { + std::string w = exception::name("other_error", id_) + exception::diagnostics(context) + what_arg; + return other_error(id_, w.c_str()); + } + + private: + JSON_HEDLEY_NON_NULL(3) + other_error(int id_, const char* what_arg) : exception(id_, what_arg) {} +}; +} // namespace detail +} // namespace nlohmann + +// #include + +// #include + + +#include // size_t +#include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type +#include // index_sequence, make_index_sequence, index_sequence_for + +// #include + + +namespace nlohmann +{ +namespace detail +{ + +template +using uncvref_t = typename std::remove_cv::type>::type; + +#ifdef JSON_HAS_CPP_14 + +// the following utilities are natively available in C++14 +using std::enable_if_t; +using std::index_sequence; +using std::make_index_sequence; +using std::index_sequence_for; + +#else + +// alias templates to reduce boilerplate +template +using enable_if_t = typename std::enable_if::type; + +// The following code is taken from https://github.com/abseil/abseil-cpp/blob/10cb35e459f5ecca5b2ff107635da0bfa41011b4/absl/utility/utility.h +// which is part of Google Abseil (https://github.com/abseil/abseil-cpp), licensed under the Apache License 2.0. + +//// START OF CODE FROM GOOGLE ABSEIL + +// integer_sequence +// +// Class template representing a compile-time integer sequence. An instantiation +// of `integer_sequence` has a sequence of integers encoded in its +// type through its template arguments (which is a common need when +// working with C++11 variadic templates). `absl::integer_sequence` is designed +// to be a drop-in replacement for C++14's `std::integer_sequence`. +// +// Example: +// +// template< class T, T... Ints > +// void user_function(integer_sequence); +// +// int main() +// { +// // user_function's `T` will be deduced to `int` and `Ints...` +// // will be deduced to `0, 1, 2, 3, 4`. +// user_function(make_integer_sequence()); +// } +template +struct integer_sequence +{ + using value_type = T; + static constexpr std::size_t size() noexcept + { + return sizeof...(Ints); + } +}; + +// index_sequence +// +// A helper template for an `integer_sequence` of `size_t`, +// `absl::index_sequence` is designed to be a drop-in replacement for C++14's +// `std::index_sequence`. +template +using index_sequence = integer_sequence; + +namespace utility_internal +{ + +template +struct Extend; + +// Note that SeqSize == sizeof...(Ints). It's passed explicitly for efficiency. +template +struct Extend, SeqSize, 0> +{ + using type = integer_sequence < T, Ints..., (Ints + SeqSize)... >; +}; + +template +struct Extend, SeqSize, 1> +{ + using type = integer_sequence < T, Ints..., (Ints + SeqSize)..., 2 * SeqSize >; +}; + +// Recursion helper for 'make_integer_sequence'. +// 'Gen::type' is an alias for 'integer_sequence'. +template +struct Gen +{ + using type = + typename Extend < typename Gen < T, N / 2 >::type, N / 2, N % 2 >::type; +}; + +template +struct Gen +{ + using type = integer_sequence; +}; + +} // namespace utility_internal + +// Compile-time sequences of integers + +// make_integer_sequence +// +// This template alias is equivalent to +// `integer_sequence`, and is designed to be a drop-in +// replacement for C++14's `std::make_integer_sequence`. +template +using make_integer_sequence = typename utility_internal::Gen::type; + +// make_index_sequence +// +// This template alias is equivalent to `index_sequence<0, 1, ..., N-1>`, +// and is designed to be a drop-in replacement for C++14's +// `std::make_index_sequence`. +template +using make_index_sequence = make_integer_sequence; + +// index_sequence_for +// +// Converts a typename pack into an index sequence of the same length, and +// is designed to be a drop-in replacement for C++14's +// `std::index_sequence_for()` +template +using index_sequence_for = make_index_sequence; + +//// END OF CODE FROM GOOGLE ABSEIL + +#endif + +// dispatch utility (taken from ranges-v3) +template struct priority_tag : priority_tag < N - 1 > {}; +template<> struct priority_tag<0> {}; + +// taken from ranges-v3 +template +struct static_const +{ + static constexpr T value{}; +}; + +template +constexpr T static_const::value; + +} // namespace detail +} // namespace nlohmann + +// #include + + +namespace nlohmann +{ +namespace detail +{ +// dispatching helper struct +template struct identity_tag {}; +} // namespace detail +} // namespace nlohmann + +// #include + + +#include // numeric_limits +#include // false_type, is_constructible, is_integral, is_same, true_type +#include // declval +#include // tuple + +// #include + + +// #include + + +#include // random_access_iterator_tag + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +template +struct iterator_types {}; + +template +struct iterator_types < + It, + void_t> +{ + using difference_type = typename It::difference_type; + using value_type = typename It::value_type; + using pointer = typename It::pointer; + using reference = typename It::reference; + using iterator_category = typename It::iterator_category; +}; + +// This is required as some compilers implement std::iterator_traits in a way that +// doesn't work with SFINAE. See https://github.com/nlohmann/json/issues/1341. +template +struct iterator_traits +{ +}; + +template +struct iterator_traits < T, enable_if_t < !std::is_pointer::value >> + : iterator_types +{ +}; + +template +struct iterator_traits::value>> +{ + using iterator_category = std::random_access_iterator_tag; + using value_type = T; + using difference_type = ptrdiff_t; + using pointer = T*; + using reference = T&; +}; +} // namespace detail +} // namespace nlohmann + +// #include + + +// #include + + +namespace nlohmann +{ +NLOHMANN_CAN_CALL_STD_FUNC_IMPL(begin); +} // namespace nlohmann + +// #include + + +// #include + + +namespace nlohmann +{ +NLOHMANN_CAN_CALL_STD_FUNC_IMPL(end); +} // namespace nlohmann + +// #include + +// #include + +// #include +#ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_ +#define INCLUDE_NLOHMANN_JSON_FWD_HPP_ + +#include // int64_t, uint64_t +#include // map +#include // allocator +#include // string +#include // vector + +/*! +@brief namespace for Niels Lohmann +@see https://github.com/nlohmann +@since version 1.0.0 +*/ +namespace nlohmann +{ +/*! +@brief default JSONSerializer template argument + +This serializer ignores the template arguments and uses ADL +([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl)) +for serialization. +*/ +template +struct adl_serializer; + +template class ObjectType = + std::map, + template class ArrayType = std::vector, + class StringType = std::string, class BooleanType = bool, + class NumberIntegerType = std::int64_t, + class NumberUnsignedType = std::uint64_t, + class NumberFloatType = double, + template class AllocatorType = std::allocator, + template class JSONSerializer = + adl_serializer, + class BinaryType = std::vector> +class basic_json; + +/*! +@brief JSON Pointer + +A JSON pointer defines a string syntax for identifying a specific value +within a JSON document. It can be used with functions `at` and +`operator[]`. Furthermore, JSON pointers are the base for JSON patches. + +@sa [RFC 6901](https://tools.ietf.org/html/rfc6901) + +@since version 2.0.0 +*/ +template +class json_pointer; + +/*! +@brief default JSON class + +This type is the default specialization of the @ref basic_json class which +uses the standard template types. + +@since version 1.0.0 +*/ +using json = basic_json<>; + +template +struct ordered_map; + +/*! +@brief ordered JSON class + +This type preserves the insertion order of object keys. + +@since version 3.9.0 +*/ +using ordered_json = basic_json; + +} // namespace nlohmann + +#endif // INCLUDE_NLOHMANN_JSON_FWD_HPP_ + + +namespace nlohmann +{ +/*! +@brief detail namespace with internal helper functions + +This namespace collects functions that should not be exposed, +implementations of some @ref basic_json methods, and meta-programming helpers. + +@since version 2.1.0 +*/ +namespace detail +{ +///////////// +// helpers // +///////////// + +// Note to maintainers: +// +// Every trait in this file expects a non CV-qualified type. +// The only exceptions are in the 'aliases for detected' section +// (i.e. those of the form: decltype(T::member_function(std::declval()))) +// +// In this case, T has to be properly CV-qualified to constraint the function arguments +// (e.g. to_json(BasicJsonType&, const T&)) + +template struct is_basic_json : std::false_type {}; + +NLOHMANN_BASIC_JSON_TPL_DECLARATION +struct is_basic_json : std::true_type {}; + +////////////////////// +// json_ref helpers // +////////////////////// + +template +class json_ref; + +template +struct is_json_ref : std::false_type {}; + +template +struct is_json_ref> : std::true_type {}; + +////////////////////////// +// aliases for detected // +////////////////////////// + +template +using mapped_type_t = typename T::mapped_type; + +template +using key_type_t = typename T::key_type; + +template +using value_type_t = typename T::value_type; + +template +using difference_type_t = typename T::difference_type; + +template +using pointer_t = typename T::pointer; + +template +using reference_t = typename T::reference; + +template +using iterator_category_t = typename T::iterator_category; + +template +using to_json_function = decltype(T::to_json(std::declval()...)); + +template +using from_json_function = decltype(T::from_json(std::declval()...)); + +template +using get_template_function = decltype(std::declval().template get()); + +// trait checking if JSONSerializer::from_json(json const&, udt&) exists +template +struct has_from_json : std::false_type {}; + +// trait checking if j.get is valid +// use this trait instead of std::is_constructible or std::is_convertible, +// both rely on, or make use of implicit conversions, and thus fail when T +// has several constructors/operator= (see https://github.com/nlohmann/json/issues/958) +template +struct is_getable +{ + static constexpr bool value = is_detected::value; +}; + +template +struct has_from_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >> +{ + using serializer = typename BasicJsonType::template json_serializer; + + static constexpr bool value = + is_detected_exact::value; +}; + +// This trait checks if JSONSerializer::from_json(json const&) exists +// this overload is used for non-default-constructible user-defined-types +template +struct has_non_default_from_json : std::false_type {}; + +template +struct has_non_default_from_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >> +{ + using serializer = typename BasicJsonType::template json_serializer; + + static constexpr bool value = + is_detected_exact::value; +}; + +// This trait checks if BasicJsonType::json_serializer::to_json exists +// Do not evaluate the trait when T is a basic_json type, to avoid template instantiation infinite recursion. +template +struct has_to_json : std::false_type {}; + +template +struct has_to_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >> +{ + using serializer = typename BasicJsonType::template json_serializer; + + static constexpr bool value = + is_detected_exact::value; +}; + + +/////////////////// +// is_ functions // +/////////////////// + +// https://en.cppreference.com/w/cpp/types/conjunction +template struct conjunction : std::true_type { }; +template struct conjunction : B1 { }; +template +struct conjunction +: std::conditional, B1>::type {}; + +// https://en.cppreference.com/w/cpp/types/negation +template struct negation : std::integral_constant < bool, !B::value > { }; + +// Reimplementation of is_constructible and is_default_constructible, due to them being broken for +// std::pair and std::tuple until LWG 2367 fix (see https://cplusplus.github.io/LWG/lwg-defects.html#2367). +// This causes compile errors in e.g. clang 3.5 or gcc 4.9. +template +struct is_default_constructible : std::is_default_constructible {}; + +template +struct is_default_constructible> + : conjunction, is_default_constructible> {}; + +template +struct is_default_constructible> + : conjunction, is_default_constructible> {}; + +template +struct is_default_constructible> + : conjunction...> {}; + +template +struct is_default_constructible> + : conjunction...> {}; + + +template +struct is_constructible : std::is_constructible {}; + +template +struct is_constructible> : is_default_constructible> {}; + +template +struct is_constructible> : is_default_constructible> {}; + +template +struct is_constructible> : is_default_constructible> {}; + +template +struct is_constructible> : is_default_constructible> {}; + + +template +struct is_iterator_traits : std::false_type {}; + +template +struct is_iterator_traits> +{ + private: + using traits = iterator_traits; + + public: + static constexpr auto value = + is_detected::value && + is_detected::value && + is_detected::value && + is_detected::value && + is_detected::value; +}; + +template +struct is_range +{ + private: + using t_ref = typename std::add_lvalue_reference::type; + + using iterator = detected_t; + using sentinel = detected_t; + + // to be 100% correct, it should use https://en.cppreference.com/w/cpp/iterator/input_or_output_iterator + // and https://en.cppreference.com/w/cpp/iterator/sentinel_for + // but reimplementing these would be too much work, as a lot of other concepts are used underneath + static constexpr auto is_iterator_begin = + is_iterator_traits>::value; + + public: + static constexpr bool value = !std::is_same::value && !std::is_same::value && is_iterator_begin; +}; + +template +using iterator_t = enable_if_t::value, result_of_begin())>>; + +template +using range_value_t = value_type_t>>; + +// The following implementation of is_complete_type is taken from +// https://blogs.msdn.microsoft.com/vcblog/2015/12/02/partial-support-for-expression-sfinae-in-vs-2015-update-1/ +// and is written by Xiang Fan who agreed to using it in this library. + +template +struct is_complete_type : std::false_type {}; + +template +struct is_complete_type : std::true_type {}; + +template +struct is_compatible_object_type_impl : std::false_type {}; + +template +struct is_compatible_object_type_impl < + BasicJsonType, CompatibleObjectType, + enable_if_t < is_detected::value&& + is_detected::value >> +{ + using object_t = typename BasicJsonType::object_t; + + // macOS's is_constructible does not play well with nonesuch... + static constexpr bool value = + is_constructible::value && + is_constructible::value; +}; + +template +struct is_compatible_object_type + : is_compatible_object_type_impl {}; + +template +struct is_constructible_object_type_impl : std::false_type {}; + +template +struct is_constructible_object_type_impl < + BasicJsonType, ConstructibleObjectType, + enable_if_t < is_detected::value&& + is_detected::value >> +{ + using object_t = typename BasicJsonType::object_t; + + static constexpr bool value = + (is_default_constructible::value && + (std::is_move_assignable::value || + std::is_copy_assignable::value) && + (is_constructible::value && + std::is_same < + typename object_t::mapped_type, + typename ConstructibleObjectType::mapped_type >::value)) || + (has_from_json::value || + has_non_default_from_json < + BasicJsonType, + typename ConstructibleObjectType::mapped_type >::value); +}; + +template +struct is_constructible_object_type + : is_constructible_object_type_impl {}; + +template +struct is_compatible_string_type +{ + static constexpr auto value = + is_constructible::value; +}; + +template +struct is_constructible_string_type +{ + static constexpr auto value = + is_constructible::value; +}; + +template +struct is_compatible_array_type_impl : std::false_type {}; + +template +struct is_compatible_array_type_impl < + BasicJsonType, CompatibleArrayType, + enable_if_t < + is_detected::value&& + is_iterator_traits>>::value&& +// special case for types like std::filesystem::path whose iterator's value_type are themselves +// c.f. https://github.com/nlohmann/json/pull/3073 + !std::is_same>::value >> +{ + static constexpr bool value = + is_constructible>::value; +}; + +template +struct is_compatible_array_type + : is_compatible_array_type_impl {}; + +template +struct is_constructible_array_type_impl : std::false_type {}; + +template +struct is_constructible_array_type_impl < + BasicJsonType, ConstructibleArrayType, + enable_if_t::value >> + : std::true_type {}; + +template +struct is_constructible_array_type_impl < + BasicJsonType, ConstructibleArrayType, + enable_if_t < !std::is_same::value&& + !is_compatible_string_type::value&& + is_default_constructible::value&& +(std::is_move_assignable::value || + std::is_copy_assignable::value)&& +is_detected::value&& +is_iterator_traits>>::value&& +is_detected::value&& +// special case for types like std::filesystem::path whose iterator's value_type are themselves +// c.f. https://github.com/nlohmann/json/pull/3073 +!std::is_same>::value&& + is_complete_type < + detected_t>::value >> +{ + using value_type = range_value_t; + + static constexpr bool value = + std::is_same::value || + has_from_json::value || + has_non_default_from_json < + BasicJsonType, + value_type >::value; +}; + +template +struct is_constructible_array_type + : is_constructible_array_type_impl {}; + +template +struct is_compatible_integer_type_impl : std::false_type {}; + +template +struct is_compatible_integer_type_impl < + RealIntegerType, CompatibleNumberIntegerType, + enable_if_t < std::is_integral::value&& + std::is_integral::value&& + !std::is_same::value >> +{ + // is there an assert somewhere on overflows? + using RealLimits = std::numeric_limits; + using CompatibleLimits = std::numeric_limits; + + static constexpr auto value = + is_constructible::value && + CompatibleLimits::is_integer && + RealLimits::is_signed == CompatibleLimits::is_signed; +}; + +template +struct is_compatible_integer_type + : is_compatible_integer_type_impl {}; + +template +struct is_compatible_type_impl: std::false_type {}; + +template +struct is_compatible_type_impl < + BasicJsonType, CompatibleType, + enable_if_t::value >> +{ + static constexpr bool value = + has_to_json::value; +}; + +template +struct is_compatible_type + : is_compatible_type_impl {}; + +template +struct is_constructible_tuple : std::false_type {}; + +template +struct is_constructible_tuple> : conjunction...> {}; + +// a naive helper to check if a type is an ordered_map (exploits the fact that +// ordered_map inherits capacity() from std::vector) +template +struct is_ordered_map +{ + using one = char; + + struct two + { + char x[2]; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) + }; + + template static one test( decltype(&C::capacity) ) ; + template static two test(...); + + enum { value = sizeof(test(nullptr)) == sizeof(char) }; // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) +}; + +// to avoid useless casts (see https://github.com/nlohmann/json/issues/2893#issuecomment-889152324) +template < typename T, typename U, enable_if_t < !std::is_same::value, int > = 0 > +T conditional_static_cast(U value) +{ + return static_cast(value); +} + +template::value, int> = 0> +T conditional_static_cast(U value) +{ + return value; +} + +} // namespace detail +} // namespace nlohmann + +// #include + + +#ifdef JSON_HAS_CPP_17 + #include +#endif + +namespace nlohmann +{ +namespace detail +{ +template +void from_json(const BasicJsonType& j, typename std::nullptr_t& n) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_null())) + { + JSON_THROW(type_error::create(302, "type must be null, but is " + std::string(j.type_name()), j)); + } + n = nullptr; +} + +// overloads for basic_json template parameters +template < typename BasicJsonType, typename ArithmeticType, + enable_if_t < std::is_arithmetic::value&& + !std::is_same::value, + int > = 0 > +void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val) +{ + switch (static_cast(j)) + { + case value_t::number_unsigned: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::number_integer: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::number_float: + { + val = static_cast(*j.template get_ptr()); + break; + } + + case value_t::null: + case value_t::object: + case value_t::array: + case value_t::string: + case value_t::boolean: + case value_t::binary: + case value_t::discarded: + default: + JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name()), j)); + } +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_boolean())) + { + JSON_THROW(type_error::create(302, "type must be boolean, but is " + std::string(j.type_name()), j)); + } + b = *j.template get_ptr(); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_string())) + { + JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()), j)); + } + s = *j.template get_ptr(); +} + +template < + typename BasicJsonType, typename ConstructibleStringType, + enable_if_t < + is_constructible_string_type::value&& + !std::is_same::value, + int > = 0 > +void from_json(const BasicJsonType& j, ConstructibleStringType& s) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_string())) + { + JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()), j)); + } + + s = *j.template get_ptr(); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val) +{ + get_arithmetic_value(j, val); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::number_unsigned_t& val) +{ + get_arithmetic_value(j, val); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::number_integer_t& val) +{ + get_arithmetic_value(j, val); +} + +template::value, int> = 0> +void from_json(const BasicJsonType& j, EnumType& e) +{ + typename std::underlying_type::type val; + get_arithmetic_value(j, val); + e = static_cast(val); +} + +// forward_list doesn't have an insert method +template::value, int> = 0> +void from_json(const BasicJsonType& j, std::forward_list& l) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()), j)); + } + l.clear(); + std::transform(j.rbegin(), j.rend(), + std::front_inserter(l), [](const BasicJsonType & i) + { + return i.template get(); + }); +} + +// valarray doesn't have an insert method +template::value, int> = 0> +void from_json(const BasicJsonType& j, std::valarray& l) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()), j)); + } + l.resize(j.size()); + std::transform(j.begin(), j.end(), std::begin(l), + [](const BasicJsonType & elem) + { + return elem.template get(); + }); +} + +template +auto from_json(const BasicJsonType& j, T (&arr)[N]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) +-> decltype(j.template get(), void()) +{ + for (std::size_t i = 0; i < N; ++i) + { + arr[i] = j.at(i).template get(); + } +} + +template +void from_json_array_impl(const BasicJsonType& j, typename BasicJsonType::array_t& arr, priority_tag<3> /*unused*/) +{ + arr = *j.template get_ptr(); +} + +template +auto from_json_array_impl(const BasicJsonType& j, std::array& arr, + priority_tag<2> /*unused*/) +-> decltype(j.template get(), void()) +{ + for (std::size_t i = 0; i < N; ++i) + { + arr[i] = j.at(i).template get(); + } +} + +template::value, + int> = 0> +auto from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, priority_tag<1> /*unused*/) +-> decltype( + arr.reserve(std::declval()), + j.template get(), + void()) +{ + using std::end; + + ConstructibleArrayType ret; + ret.reserve(j.size()); + std::transform(j.begin(), j.end(), + std::inserter(ret, end(ret)), [](const BasicJsonType & i) + { + // get() returns *this, this won't call a from_json + // method when value_type is BasicJsonType + return i.template get(); + }); + arr = std::move(ret); +} + +template::value, + int> = 0> +void from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, + priority_tag<0> /*unused*/) +{ + using std::end; + + ConstructibleArrayType ret; + std::transform( + j.begin(), j.end(), std::inserter(ret, end(ret)), + [](const BasicJsonType & i) + { + // get() returns *this, this won't call a from_json + // method when value_type is BasicJsonType + return i.template get(); + }); + arr = std::move(ret); +} + +template < typename BasicJsonType, typename ConstructibleArrayType, + enable_if_t < + is_constructible_array_type::value&& + !is_constructible_object_type::value&& + !is_constructible_string_type::value&& + !std::is_same::value&& + !is_basic_json::value, + int > = 0 > +auto from_json(const BasicJsonType& j, ConstructibleArrayType& arr) +-> decltype(from_json_array_impl(j, arr, priority_tag<3> {}), +j.template get(), +void()) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()), j)); + } + + from_json_array_impl(j, arr, priority_tag<3> {}); +} + +template < typename BasicJsonType, typename T, std::size_t... Idx > +std::array from_json_inplace_array_impl(BasicJsonType&& j, + identity_tag> /*unused*/, index_sequence /*unused*/) +{ + return { { std::forward(j).at(Idx).template get()... } }; +} + +template < typename BasicJsonType, typename T, std::size_t N > +auto from_json(BasicJsonType&& j, identity_tag> tag) +-> decltype(from_json_inplace_array_impl(std::forward(j), tag, make_index_sequence {})) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()), j)); + } + + return from_json_inplace_array_impl(std::forward(j), tag, make_index_sequence {}); +} + +template +void from_json(const BasicJsonType& j, typename BasicJsonType::binary_t& bin) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_binary())) + { + JSON_THROW(type_error::create(302, "type must be binary, but is " + std::string(j.type_name()), j)); + } + + bin = *j.template get_ptr(); +} + +template::value, int> = 0> +void from_json(const BasicJsonType& j, ConstructibleObjectType& obj) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_object())) + { + JSON_THROW(type_error::create(302, "type must be object, but is " + std::string(j.type_name()), j)); + } + + ConstructibleObjectType ret; + const auto* inner_object = j.template get_ptr(); + using value_type = typename ConstructibleObjectType::value_type; + std::transform( + inner_object->begin(), inner_object->end(), + std::inserter(ret, ret.begin()), + [](typename BasicJsonType::object_t::value_type const & p) + { + return value_type(p.first, p.second.template get()); + }); + obj = std::move(ret); +} + +// overload for arithmetic types, not chosen for basic_json template arguments +// (BooleanType, etc..); note: Is it really necessary to provide explicit +// overloads for boolean_t etc. in case of a custom BooleanType which is not +// an arithmetic type? +template < typename BasicJsonType, typename ArithmeticType, + enable_if_t < + std::is_arithmetic::value&& + !std::is_same::value&& + !std::is_same::value&& + !std::is_same::value&& + !std::is_same::value, + int > = 0 > +void from_json(const BasicJsonType& j, ArithmeticType& val) +{ + switch (static_cast(j)) + { + case value_t::number_unsigned: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::number_integer: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::number_float: + { + val = static_cast(*j.template get_ptr()); + break; + } + case value_t::boolean: + { + val = static_cast(*j.template get_ptr()); + break; + } + + case value_t::null: + case value_t::object: + case value_t::array: + case value_t::string: + case value_t::binary: + case value_t::discarded: + default: + JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name()), j)); + } +} + +template +std::tuple from_json_tuple_impl_base(BasicJsonType&& j, index_sequence /*unused*/) +{ + return std::make_tuple(std::forward(j).at(Idx).template get()...); +} + +template < typename BasicJsonType, class A1, class A2 > +std::pair from_json_tuple_impl(BasicJsonType&& j, identity_tag> /*unused*/, priority_tag<0> /*unused*/) +{ + return {std::forward(j).at(0).template get(), + std::forward(j).at(1).template get()}; +} + +template +void from_json_tuple_impl(BasicJsonType&& j, std::pair& p, priority_tag<1> /*unused*/) +{ + p = from_json_tuple_impl(std::forward(j), identity_tag> {}, priority_tag<0> {}); +} + +template +std::tuple from_json_tuple_impl(BasicJsonType&& j, identity_tag> /*unused*/, priority_tag<2> /*unused*/) +{ + return from_json_tuple_impl_base(std::forward(j), index_sequence_for {}); +} + +template +void from_json_tuple_impl(BasicJsonType&& j, std::tuple& t, priority_tag<3> /*unused*/) +{ + t = from_json_tuple_impl_base(std::forward(j), index_sequence_for {}); +} + +template +auto from_json(BasicJsonType&& j, TupleRelated&& t) +-> decltype(from_json_tuple_impl(std::forward(j), std::forward(t), priority_tag<3> {})) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()), j)); + } + + return from_json_tuple_impl(std::forward(j), std::forward(t), priority_tag<3> {}); +} + +template < typename BasicJsonType, typename Key, typename Value, typename Compare, typename Allocator, + typename = enable_if_t < !std::is_constructible < + typename BasicJsonType::string_t, Key >::value >> +void from_json(const BasicJsonType& j, std::map& m) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()), j)); + } + m.clear(); + for (const auto& p : j) + { + if (JSON_HEDLEY_UNLIKELY(!p.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(p.type_name()), j)); + } + m.emplace(p.at(0).template get(), p.at(1).template get()); + } +} + +template < typename BasicJsonType, typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator, + typename = enable_if_t < !std::is_constructible < + typename BasicJsonType::string_t, Key >::value >> +void from_json(const BasicJsonType& j, std::unordered_map& m) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()), j)); + } + m.clear(); + for (const auto& p : j) + { + if (JSON_HEDLEY_UNLIKELY(!p.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(p.type_name()), j)); + } + m.emplace(p.at(0).template get(), p.at(1).template get()); + } +} + +#ifdef JSON_HAS_CPP_17 +template +void from_json(const BasicJsonType& j, std::filesystem::path& p) +{ + if (JSON_HEDLEY_UNLIKELY(!j.is_string())) + { + JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()), j)); + } + p = *j.template get_ptr(); +} +#endif + +struct from_json_fn +{ + template + auto operator()(const BasicJsonType& j, T&& val) const + noexcept(noexcept(from_json(j, std::forward(val)))) + -> decltype(from_json(j, std::forward(val))) + { + return from_json(j, std::forward(val)); + } +}; +} // namespace detail + +/// namespace to hold default `from_json` function +/// to see why this is required: +/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html +namespace // NOLINT(cert-dcl59-cpp,fuchsia-header-anon-namespaces,google-build-namespaces) +{ +constexpr const auto& from_json = detail::static_const::value; // NOLINT(misc-definitions-in-headers) +} // namespace +} // namespace nlohmann + +// #include + + +#include // copy +#include // begin, end +#include // string +#include // tuple, get +#include // is_same, is_constructible, is_floating_point, is_enum, underlying_type +#include // move, forward, declval, pair +#include // valarray +#include // vector + +// #include + +// #include + + +#include // size_t +#include // input_iterator_tag +#include // string, to_string +#include // tuple_size, get, tuple_element +#include // move + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +template +void int_to_string( string_type& target, std::size_t value ) +{ + // For ADL + using std::to_string; + target = to_string(value); +} +template class iteration_proxy_value +{ + public: + using difference_type = std::ptrdiff_t; + using value_type = iteration_proxy_value; + using pointer = value_type * ; + using reference = value_type & ; + using iterator_category = std::input_iterator_tag; + using string_type = typename std::remove_cv< typename std::remove_reference().key() ) >::type >::type; + + private: + /// the iterator + IteratorType anchor; + /// an index for arrays (used to create key names) + std::size_t array_index = 0; + /// last stringified array index + mutable std::size_t array_index_last = 0; + /// a string representation of the array index + mutable string_type array_index_str = "0"; + /// an empty string (to return a reference for primitive values) + const string_type empty_str{}; + + public: + explicit iteration_proxy_value(IteratorType it) noexcept + : anchor(std::move(it)) + {} + + /// dereference operator (needed for range-based for) + iteration_proxy_value& operator*() + { + return *this; + } + + /// increment operator (needed for range-based for) + iteration_proxy_value& operator++() + { + ++anchor; + ++array_index; + + return *this; + } + + /// equality operator (needed for InputIterator) + bool operator==(const iteration_proxy_value& o) const + { + return anchor == o.anchor; + } + + /// inequality operator (needed for range-based for) + bool operator!=(const iteration_proxy_value& o) const + { + return anchor != o.anchor; + } + + /// return key of the iterator + const string_type& key() const + { + JSON_ASSERT(anchor.m_object != nullptr); + + switch (anchor.m_object->type()) + { + // use integer array index as key + case value_t::array: + { + if (array_index != array_index_last) + { + int_to_string( array_index_str, array_index ); + array_index_last = array_index; + } + return array_index_str; + } + + // use key from the object + case value_t::object: + return anchor.key(); + + // use an empty key for all primitive types + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + return empty_str; + } + } + + /// return value of the iterator + typename IteratorType::reference value() const + { + return anchor.value(); + } +}; + +/// proxy class for the items() function +template class iteration_proxy +{ + private: + /// the container to iterate + typename IteratorType::reference container; + + public: + /// construct iteration proxy from a container + explicit iteration_proxy(typename IteratorType::reference cont) noexcept + : container(cont) {} + + /// return iterator begin (needed for range-based for) + iteration_proxy_value begin() noexcept + { + return iteration_proxy_value(container.begin()); + } + + /// return iterator end (needed for range-based for) + iteration_proxy_value end() noexcept + { + return iteration_proxy_value(container.end()); + } +}; +// Structured Bindings Support +// For further reference see https://blog.tartanllama.xyz/structured-bindings/ +// And see https://github.com/nlohmann/json/pull/1391 +template = 0> +auto get(const nlohmann::detail::iteration_proxy_value& i) -> decltype(i.key()) +{ + return i.key(); +} +// Structured Bindings Support +// For further reference see https://blog.tartanllama.xyz/structured-bindings/ +// And see https://github.com/nlohmann/json/pull/1391 +template = 0> +auto get(const nlohmann::detail::iteration_proxy_value& i) -> decltype(i.value()) +{ + return i.value(); +} +} // namespace detail +} // namespace nlohmann + +// The Addition to the STD Namespace is required to add +// Structured Bindings Support to the iteration_proxy_value class +// For further reference see https://blog.tartanllama.xyz/structured-bindings/ +// And see https://github.com/nlohmann/json/pull/1391 +namespace std +{ +#if defined(__clang__) + // Fix: https://github.com/nlohmann/json/issues/1401 + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wmismatched-tags" +#endif +template +class tuple_size<::nlohmann::detail::iteration_proxy_value> + : public std::integral_constant {}; + +template +class tuple_element> +{ + public: + using type = decltype( + get(std::declval < + ::nlohmann::detail::iteration_proxy_value> ())); +}; +#if defined(__clang__) + #pragma clang diagnostic pop +#endif +} // namespace std + +// #include + +// #include + +// #include + + +#ifdef JSON_HAS_CPP_17 + #include +#endif + +namespace nlohmann +{ +namespace detail +{ +////////////////// +// constructors // +////////////////// + +/* + * Note all external_constructor<>::construct functions need to call + * j.m_value.destroy(j.m_type) to avoid a memory leak in case j contains an + * allocated value (e.g., a string). See bug issue + * https://github.com/nlohmann/json/issues/2865 for more information. + */ + +template struct external_constructor; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept + { + j.m_value.destroy(j.m_type); + j.m_type = value_t::boolean; + j.m_value = b; + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s) + { + j.m_value.destroy(j.m_type); + j.m_type = value_t::string; + j.m_value = s; + j.assert_invariant(); + } + + template + static void construct(BasicJsonType& j, typename BasicJsonType::string_t&& s) + { + j.m_value.destroy(j.m_type); + j.m_type = value_t::string; + j.m_value = std::move(s); + j.assert_invariant(); + } + + template < typename BasicJsonType, typename CompatibleStringType, + enable_if_t < !std::is_same::value, + int > = 0 > + static void construct(BasicJsonType& j, const CompatibleStringType& str) + { + j.m_value.destroy(j.m_type); + j.m_type = value_t::string; + j.m_value.string = j.template create(str); + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, const typename BasicJsonType::binary_t& b) + { + j.m_value.destroy(j.m_type); + j.m_type = value_t::binary; + j.m_value = typename BasicJsonType::binary_t(b); + j.assert_invariant(); + } + + template + static void construct(BasicJsonType& j, typename BasicJsonType::binary_t&& b) + { + j.m_value.destroy(j.m_type); + j.m_type = value_t::binary; + j.m_value = typename BasicJsonType::binary_t(std::move(b)); + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept + { + j.m_value.destroy(j.m_type); + j.m_type = value_t::number_float; + j.m_value = val; + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept + { + j.m_value.destroy(j.m_type); + j.m_type = value_t::number_unsigned; + j.m_value = val; + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept + { + j.m_value.destroy(j.m_type); + j.m_type = value_t::number_integer; + j.m_value = val; + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr) + { + j.m_value.destroy(j.m_type); + j.m_type = value_t::array; + j.m_value = arr; + j.set_parents(); + j.assert_invariant(); + } + + template + static void construct(BasicJsonType& j, typename BasicJsonType::array_t&& arr) + { + j.m_value.destroy(j.m_type); + j.m_type = value_t::array; + j.m_value = std::move(arr); + j.set_parents(); + j.assert_invariant(); + } + + template < typename BasicJsonType, typename CompatibleArrayType, + enable_if_t < !std::is_same::value, + int > = 0 > + static void construct(BasicJsonType& j, const CompatibleArrayType& arr) + { + using std::begin; + using std::end; + + j.m_value.destroy(j.m_type); + j.m_type = value_t::array; + j.m_value.array = j.template create(begin(arr), end(arr)); + j.set_parents(); + j.assert_invariant(); + } + + template + static void construct(BasicJsonType& j, const std::vector& arr) + { + j.m_value.destroy(j.m_type); + j.m_type = value_t::array; + j.m_value = value_t::array; + j.m_value.array->reserve(arr.size()); + for (const bool x : arr) + { + j.m_value.array->push_back(x); + j.set_parent(j.m_value.array->back()); + } + j.assert_invariant(); + } + + template::value, int> = 0> + static void construct(BasicJsonType& j, const std::valarray& arr) + { + j.m_value.destroy(j.m_type); + j.m_type = value_t::array; + j.m_value = value_t::array; + j.m_value.array->resize(arr.size()); + if (arr.size() > 0) + { + std::copy(std::begin(arr), std::end(arr), j.m_value.array->begin()); + } + j.set_parents(); + j.assert_invariant(); + } +}; + +template<> +struct external_constructor +{ + template + static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj) + { + j.m_value.destroy(j.m_type); + j.m_type = value_t::object; + j.m_value = obj; + j.set_parents(); + j.assert_invariant(); + } + + template + static void construct(BasicJsonType& j, typename BasicJsonType::object_t&& obj) + { + j.m_value.destroy(j.m_type); + j.m_type = value_t::object; + j.m_value = std::move(obj); + j.set_parents(); + j.assert_invariant(); + } + + template < typename BasicJsonType, typename CompatibleObjectType, + enable_if_t < !std::is_same::value, int > = 0 > + static void construct(BasicJsonType& j, const CompatibleObjectType& obj) + { + using std::begin; + using std::end; + + j.m_value.destroy(j.m_type); + j.m_type = value_t::object; + j.m_value.object = j.template create(begin(obj), end(obj)); + j.set_parents(); + j.assert_invariant(); + } +}; + +///////////// +// to_json // +///////////// + +template::value, int> = 0> +void to_json(BasicJsonType& j, T b) noexcept +{ + external_constructor::construct(j, b); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, const CompatibleString& s) +{ + external_constructor::construct(j, s); +} + +template +void to_json(BasicJsonType& j, typename BasicJsonType::string_t&& s) +{ + external_constructor::construct(j, std::move(s)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, FloatType val) noexcept +{ + external_constructor::construct(j, static_cast(val)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, CompatibleNumberUnsignedType val) noexcept +{ + external_constructor::construct(j, static_cast(val)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, CompatibleNumberIntegerType val) noexcept +{ + external_constructor::construct(j, static_cast(val)); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, EnumType e) noexcept +{ + using underlying_type = typename std::underlying_type::type; + external_constructor::construct(j, static_cast(e)); +} + +template +void to_json(BasicJsonType& j, const std::vector& e) +{ + external_constructor::construct(j, e); +} + +template < typename BasicJsonType, typename CompatibleArrayType, + enable_if_t < is_compatible_array_type::value&& + !is_compatible_object_type::value&& + !is_compatible_string_type::value&& + !std::is_same::value&& + !is_basic_json::value, + int > = 0 > +void to_json(BasicJsonType& j, const CompatibleArrayType& arr) +{ + external_constructor::construct(j, arr); +} + +template +void to_json(BasicJsonType& j, const typename BasicJsonType::binary_t& bin) +{ + external_constructor::construct(j, bin); +} + +template::value, int> = 0> +void to_json(BasicJsonType& j, const std::valarray& arr) +{ + external_constructor::construct(j, std::move(arr)); +} + +template +void to_json(BasicJsonType& j, typename BasicJsonType::array_t&& arr) +{ + external_constructor::construct(j, std::move(arr)); +} + +template < typename BasicJsonType, typename CompatibleObjectType, + enable_if_t < is_compatible_object_type::value&& !is_basic_json::value, int > = 0 > +void to_json(BasicJsonType& j, const CompatibleObjectType& obj) +{ + external_constructor::construct(j, obj); +} + +template +void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj) +{ + external_constructor::construct(j, std::move(obj)); +} + +template < + typename BasicJsonType, typename T, std::size_t N, + enable_if_t < !std::is_constructible::value, // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) + int > = 0 > +void to_json(BasicJsonType& j, const T(&arr)[N]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) +{ + external_constructor::construct(j, arr); +} + +template < typename BasicJsonType, typename T1, typename T2, enable_if_t < std::is_constructible::value&& std::is_constructible::value, int > = 0 > +void to_json(BasicJsonType& j, const std::pair& p) +{ + j = { p.first, p.second }; +} + +// for https://github.com/nlohmann/json/pull/1134 +template>::value, int> = 0> +void to_json(BasicJsonType& j, const T& b) +{ + j = { {b.key(), b.value()} }; +} + +template +void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence /*unused*/) +{ + j = { std::get(t)... }; +} + +template::value, int > = 0> +void to_json(BasicJsonType& j, const T& t) +{ + to_json_tuple_impl(j, t, make_index_sequence::value> {}); +} + +#ifdef JSON_HAS_CPP_17 +template +void to_json(BasicJsonType& j, const std::filesystem::path& p) +{ + j = p.string(); +} +#endif + +struct to_json_fn +{ + template + auto operator()(BasicJsonType& j, T&& val) const noexcept(noexcept(to_json(j, std::forward(val)))) + -> decltype(to_json(j, std::forward(val)), void()) + { + return to_json(j, std::forward(val)); + } +}; +} // namespace detail + +/// namespace to hold default `to_json` function +/// to see why this is required: +/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html +namespace // NOLINT(cert-dcl59-cpp,fuchsia-header-anon-namespaces,google-build-namespaces) +{ +constexpr const auto& to_json = detail::static_const::value; // NOLINT(misc-definitions-in-headers) +} // namespace +} // namespace nlohmann + +// #include + +// #include + + +namespace nlohmann +{ + +template +struct adl_serializer +{ + /*! + @brief convert a JSON value to any value type + + This function is usually called by the `get()` function of the + @ref basic_json class (either explicit or via conversion operators). + + @note This function is chosen for default-constructible value types. + + @param[in] j JSON value to read from + @param[in,out] val value to write to + */ + template + static auto from_json(BasicJsonType && j, TargetType& val) noexcept( + noexcept(::nlohmann::from_json(std::forward(j), val))) + -> decltype(::nlohmann::from_json(std::forward(j), val), void()) + { + ::nlohmann::from_json(std::forward(j), val); + } + + /*! + @brief convert a JSON value to any value type + + This function is usually called by the `get()` function of the + @ref basic_json class (either explicit or via conversion operators). + + @note This function is chosen for value types which are not default-constructible. + + @param[in] j JSON value to read from + + @return copy of the JSON value, converted to @a ValueType + */ + template + static auto from_json(BasicJsonType && j) noexcept( + noexcept(::nlohmann::from_json(std::forward(j), detail::identity_tag {}))) + -> decltype(::nlohmann::from_json(std::forward(j), detail::identity_tag {})) + { + return ::nlohmann::from_json(std::forward(j), detail::identity_tag {}); + } + + /*! + @brief convert any value type to a JSON value + + This function is usually called by the constructors of the @ref basic_json + class. + + @param[in,out] j JSON value to write to + @param[in] val value to read from + */ + template + static auto to_json(BasicJsonType& j, TargetType && val) noexcept( + noexcept(::nlohmann::to_json(j, std::forward(val)))) + -> decltype(::nlohmann::to_json(j, std::forward(val)), void()) + { + ::nlohmann::to_json(j, std::forward(val)); + } +}; +} // namespace nlohmann + +// #include + + +#include // uint8_t, uint64_t +#include // tie +#include // move + +namespace nlohmann +{ + +/*! +@brief an internal type for a backed binary type + +This type extends the template parameter @a BinaryType provided to `basic_json` +with a subtype used by BSON and MessagePack. This type exists so that the user +does not have to specify a type themselves with a specific naming scheme in +order to override the binary type. + +@tparam BinaryType container to store bytes (`std::vector` by + default) + +@since version 3.8.0; changed type of subtypes to std::uint64_t in 3.10.0. +*/ +template +class byte_container_with_subtype : public BinaryType +{ + public: + /// the type of the underlying container + using container_type = BinaryType; + /// the type of the subtype + using subtype_type = std::uint64_t; + + byte_container_with_subtype() noexcept(noexcept(container_type())) + : container_type() + {} + + byte_container_with_subtype(const container_type& b) noexcept(noexcept(container_type(b))) + : container_type(b) + {} + + byte_container_with_subtype(container_type&& b) noexcept(noexcept(container_type(std::move(b)))) + : container_type(std::move(b)) + {} + + byte_container_with_subtype(const container_type& b, subtype_type subtype_) noexcept(noexcept(container_type(b))) + : container_type(b) + , m_subtype(subtype_) + , m_has_subtype(true) + {} + + byte_container_with_subtype(container_type&& b, subtype_type subtype_) noexcept(noexcept(container_type(std::move(b)))) + : container_type(std::move(b)) + , m_subtype(subtype_) + , m_has_subtype(true) + {} + + bool operator==(const byte_container_with_subtype& rhs) const + { + return std::tie(static_cast(*this), m_subtype, m_has_subtype) == + std::tie(static_cast(rhs), rhs.m_subtype, rhs.m_has_subtype); + } + + bool operator!=(const byte_container_with_subtype& rhs) const + { + return !(rhs == *this); + } + + /*! + @brief sets the binary subtype + + Sets the binary subtype of the value, also flags a binary JSON value as + having a subtype, which has implications for serialization. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @sa see @ref subtype() -- return the binary subtype + @sa see @ref clear_subtype() -- clears the binary subtype + @sa see @ref has_subtype() -- returns whether or not the binary value has a + subtype + + @since version 3.8.0 + */ + void set_subtype(subtype_type subtype_) noexcept + { + m_subtype = subtype_; + m_has_subtype = true; + } + + /*! + @brief return the binary subtype + + Returns the numerical subtype of the value if it has a subtype. If it does + not have a subtype, this function will return subtype_type(-1) as a sentinel + value. + + @return the numerical subtype of the binary value + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @sa see @ref set_subtype() -- sets the binary subtype + @sa see @ref clear_subtype() -- clears the binary subtype + @sa see @ref has_subtype() -- returns whether or not the binary value has a + subtype + + @since version 3.8.0; fixed return value to properly return + subtype_type(-1) as documented in version 3.10.0 + */ + constexpr subtype_type subtype() const noexcept + { + return m_has_subtype ? m_subtype : subtype_type(-1); + } + + /*! + @brief return whether the value has a subtype + + @return whether the value has a subtype + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @sa see @ref subtype() -- return the binary subtype + @sa see @ref set_subtype() -- sets the binary subtype + @sa see @ref clear_subtype() -- clears the binary subtype + + @since version 3.8.0 + */ + constexpr bool has_subtype() const noexcept + { + return m_has_subtype; + } + + /*! + @brief clears the binary subtype + + Clears the binary subtype and flags the value as not having a subtype, which + has implications for serialization; for instance MessagePack will prefer the + bin family over the ext family. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @sa see @ref subtype() -- return the binary subtype + @sa see @ref set_subtype() -- sets the binary subtype + @sa see @ref has_subtype() -- returns whether or not the binary value has a + subtype + + @since version 3.8.0 + */ + void clear_subtype() noexcept + { + m_subtype = 0; + m_has_subtype = false; + } + + private: + subtype_type m_subtype = 0; + bool m_has_subtype = false; +}; + +} // namespace nlohmann + +// #include + +// #include + +// #include + +// #include + + +#include // uint8_t +#include // size_t +#include // hash + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ + +// boost::hash_combine +inline std::size_t combine(std::size_t seed, std::size_t h) noexcept +{ + seed ^= h + 0x9e3779b9 + (seed << 6U) + (seed >> 2U); + return seed; +} + +/*! +@brief hash a JSON value + +The hash function tries to rely on std::hash where possible. Furthermore, the +type of the JSON value is taken into account to have different hash values for +null, 0, 0U, and false, etc. + +@tparam BasicJsonType basic_json specialization +@param j JSON value to hash +@return hash value of j +*/ +template +std::size_t hash(const BasicJsonType& j) +{ + using string_t = typename BasicJsonType::string_t; + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + + const auto type = static_cast(j.type()); + switch (j.type()) + { + case BasicJsonType::value_t::null: + case BasicJsonType::value_t::discarded: + { + return combine(type, 0); + } + + case BasicJsonType::value_t::object: + { + auto seed = combine(type, j.size()); + for (const auto& element : j.items()) + { + const auto h = std::hash {}(element.key()); + seed = combine(seed, h); + seed = combine(seed, hash(element.value())); + } + return seed; + } + + case BasicJsonType::value_t::array: + { + auto seed = combine(type, j.size()); + for (const auto& element : j) + { + seed = combine(seed, hash(element)); + } + return seed; + } + + case BasicJsonType::value_t::string: + { + const auto h = std::hash {}(j.template get_ref()); + return combine(type, h); + } + + case BasicJsonType::value_t::boolean: + { + const auto h = std::hash {}(j.template get()); + return combine(type, h); + } + + case BasicJsonType::value_t::number_integer: + { + const auto h = std::hash {}(j.template get()); + return combine(type, h); + } + + case BasicJsonType::value_t::number_unsigned: + { + const auto h = std::hash {}(j.template get()); + return combine(type, h); + } + + case BasicJsonType::value_t::number_float: + { + const auto h = std::hash {}(j.template get()); + return combine(type, h); + } + + case BasicJsonType::value_t::binary: + { + auto seed = combine(type, j.get_binary().size()); + const auto h = std::hash {}(j.get_binary().has_subtype()); + seed = combine(seed, h); + seed = combine(seed, static_cast(j.get_binary().subtype())); + for (const auto byte : j.get_binary()) + { + seed = combine(seed, std::hash {}(byte)); + } + return seed; + } + + default: // LCOV_EXCL_LINE + JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE + return 0; // LCOV_EXCL_LINE + } +} + +} // namespace detail +} // namespace nlohmann + +// #include + + +#include // generate_n +#include // array +#include // ldexp +#include // size_t +#include // uint8_t, uint16_t, uint32_t, uint64_t +#include // snprintf +#include // memcpy +#include // back_inserter +#include // numeric_limits +#include // char_traits, string +#include // make_pair, move +#include // vector + +// #include + +// #include + + +#include // array +#include // size_t +#include // strlen +#include // begin, end, iterator_traits, random_access_iterator_tag, distance, next +#include // shared_ptr, make_shared, addressof +#include // accumulate +#include // string, char_traits +#include // enable_if, is_base_of, is_pointer, is_integral, remove_pointer +#include // pair, declval + +#ifndef JSON_NO_IO + #include // FILE * + #include // istream +#endif // JSON_NO_IO + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +/// the supported input formats +enum class input_format_t { json, cbor, msgpack, ubjson, bson }; + +//////////////////// +// input adapters // +//////////////////// + +#ifndef JSON_NO_IO +/*! +Input adapter for stdio file access. This adapter read only 1 byte and do not use any + buffer. This adapter is a very low level adapter. +*/ +class file_input_adapter +{ + public: + using char_type = char; + + JSON_HEDLEY_NON_NULL(2) + explicit file_input_adapter(std::FILE* f) noexcept + : m_file(f) + {} + + // make class move-only + file_input_adapter(const file_input_adapter&) = delete; + file_input_adapter(file_input_adapter&&) noexcept = default; + file_input_adapter& operator=(const file_input_adapter&) = delete; + file_input_adapter& operator=(file_input_adapter&&) = delete; + ~file_input_adapter() = default; + + std::char_traits::int_type get_character() noexcept + { + return std::fgetc(m_file); + } + + private: + /// the file pointer to read from + std::FILE* m_file; +}; + + +/*! +Input adapter for a (caching) istream. Ignores a UFT Byte Order Mark at +beginning of input. Does not support changing the underlying std::streambuf +in mid-input. Maintains underlying std::istream and std::streambuf to support +subsequent use of standard std::istream operations to process any input +characters following those used in parsing the JSON input. Clears the +std::istream flags; any input errors (e.g., EOF) will be detected by the first +subsequent call for input from the std::istream. +*/ +class input_stream_adapter +{ + public: + using char_type = char; + + ~input_stream_adapter() + { + // clear stream flags; we use underlying streambuf I/O, do not + // maintain ifstream flags, except eof + if (is != nullptr) + { + is->clear(is->rdstate() & std::ios::eofbit); + } + } + + explicit input_stream_adapter(std::istream& i) + : is(&i), sb(i.rdbuf()) + {} + + // delete because of pointer members + input_stream_adapter(const input_stream_adapter&) = delete; + input_stream_adapter& operator=(input_stream_adapter&) = delete; + input_stream_adapter& operator=(input_stream_adapter&&) = delete; + + input_stream_adapter(input_stream_adapter&& rhs) noexcept + : is(rhs.is), sb(rhs.sb) + { + rhs.is = nullptr; + rhs.sb = nullptr; + } + + // std::istream/std::streambuf use std::char_traits::to_int_type, to + // ensure that std::char_traits::eof() and the character 0xFF do not + // end up as the same value, eg. 0xFFFFFFFF. + std::char_traits::int_type get_character() + { + auto res = sb->sbumpc(); + // set eof manually, as we don't use the istream interface. + if (JSON_HEDLEY_UNLIKELY(res == std::char_traits::eof())) + { + is->clear(is->rdstate() | std::ios::eofbit); + } + return res; + } + + private: + /// the associated input stream + std::istream* is = nullptr; + std::streambuf* sb = nullptr; +}; +#endif // JSON_NO_IO + +// General-purpose iterator-based adapter. It might not be as fast as +// theoretically possible for some containers, but it is extremely versatile. +template +class iterator_input_adapter +{ + public: + using char_type = typename std::iterator_traits::value_type; + + iterator_input_adapter(IteratorType first, IteratorType last) + : current(std::move(first)), end(std::move(last)) + {} + + typename std::char_traits::int_type get_character() + { + if (JSON_HEDLEY_LIKELY(current != end)) + { + auto result = std::char_traits::to_int_type(*current); + std::advance(current, 1); + return result; + } + + return std::char_traits::eof(); + } + + private: + IteratorType current; + IteratorType end; + + template + friend struct wide_string_input_helper; + + bool empty() const + { + return current == end; + } +}; + + +template +struct wide_string_input_helper; + +template +struct wide_string_input_helper +{ + // UTF-32 + static void fill_buffer(BaseInputAdapter& input, + std::array::int_type, 4>& utf8_bytes, + size_t& utf8_bytes_index, + size_t& utf8_bytes_filled) + { + utf8_bytes_index = 0; + + if (JSON_HEDLEY_UNLIKELY(input.empty())) + { + utf8_bytes[0] = std::char_traits::eof(); + utf8_bytes_filled = 1; + } + else + { + // get the current character + const auto wc = input.get_character(); + + // UTF-32 to UTF-8 encoding + if (wc < 0x80) + { + utf8_bytes[0] = static_cast::int_type>(wc); + utf8_bytes_filled = 1; + } + else if (wc <= 0x7FF) + { + utf8_bytes[0] = static_cast::int_type>(0xC0u | ((static_cast(wc) >> 6u) & 0x1Fu)); + utf8_bytes[1] = static_cast::int_type>(0x80u | (static_cast(wc) & 0x3Fu)); + utf8_bytes_filled = 2; + } + else if (wc <= 0xFFFF) + { + utf8_bytes[0] = static_cast::int_type>(0xE0u | ((static_cast(wc) >> 12u) & 0x0Fu)); + utf8_bytes[1] = static_cast::int_type>(0x80u | ((static_cast(wc) >> 6u) & 0x3Fu)); + utf8_bytes[2] = static_cast::int_type>(0x80u | (static_cast(wc) & 0x3Fu)); + utf8_bytes_filled = 3; + } + else if (wc <= 0x10FFFF) + { + utf8_bytes[0] = static_cast::int_type>(0xF0u | ((static_cast(wc) >> 18u) & 0x07u)); + utf8_bytes[1] = static_cast::int_type>(0x80u | ((static_cast(wc) >> 12u) & 0x3Fu)); + utf8_bytes[2] = static_cast::int_type>(0x80u | ((static_cast(wc) >> 6u) & 0x3Fu)); + utf8_bytes[3] = static_cast::int_type>(0x80u | (static_cast(wc) & 0x3Fu)); + utf8_bytes_filled = 4; + } + else + { + // unknown character + utf8_bytes[0] = static_cast::int_type>(wc); + utf8_bytes_filled = 1; + } + } + } +}; + +template +struct wide_string_input_helper +{ + // UTF-16 + static void fill_buffer(BaseInputAdapter& input, + std::array::int_type, 4>& utf8_bytes, + size_t& utf8_bytes_index, + size_t& utf8_bytes_filled) + { + utf8_bytes_index = 0; + + if (JSON_HEDLEY_UNLIKELY(input.empty())) + { + utf8_bytes[0] = std::char_traits::eof(); + utf8_bytes_filled = 1; + } + else + { + // get the current character + const auto wc = input.get_character(); + + // UTF-16 to UTF-8 encoding + if (wc < 0x80) + { + utf8_bytes[0] = static_cast::int_type>(wc); + utf8_bytes_filled = 1; + } + else if (wc <= 0x7FF) + { + utf8_bytes[0] = static_cast::int_type>(0xC0u | ((static_cast(wc) >> 6u))); + utf8_bytes[1] = static_cast::int_type>(0x80u | (static_cast(wc) & 0x3Fu)); + utf8_bytes_filled = 2; + } + else if (0xD800 > wc || wc >= 0xE000) + { + utf8_bytes[0] = static_cast::int_type>(0xE0u | ((static_cast(wc) >> 12u))); + utf8_bytes[1] = static_cast::int_type>(0x80u | ((static_cast(wc) >> 6u) & 0x3Fu)); + utf8_bytes[2] = static_cast::int_type>(0x80u | (static_cast(wc) & 0x3Fu)); + utf8_bytes_filled = 3; + } + else + { + if (JSON_HEDLEY_UNLIKELY(!input.empty())) + { + const auto wc2 = static_cast(input.get_character()); + const auto charcode = 0x10000u + (((static_cast(wc) & 0x3FFu) << 10u) | (wc2 & 0x3FFu)); + utf8_bytes[0] = static_cast::int_type>(0xF0u | (charcode >> 18u)); + utf8_bytes[1] = static_cast::int_type>(0x80u | ((charcode >> 12u) & 0x3Fu)); + utf8_bytes[2] = static_cast::int_type>(0x80u | ((charcode >> 6u) & 0x3Fu)); + utf8_bytes[3] = static_cast::int_type>(0x80u | (charcode & 0x3Fu)); + utf8_bytes_filled = 4; + } + else + { + utf8_bytes[0] = static_cast::int_type>(wc); + utf8_bytes_filled = 1; + } + } + } + } +}; + +// Wraps another input apdater to convert wide character types into individual bytes. +template +class wide_string_input_adapter +{ + public: + using char_type = char; + + wide_string_input_adapter(BaseInputAdapter base) + : base_adapter(base) {} + + typename std::char_traits::int_type get_character() noexcept + { + // check if buffer needs to be filled + if (utf8_bytes_index == utf8_bytes_filled) + { + fill_buffer(); + + JSON_ASSERT(utf8_bytes_filled > 0); + JSON_ASSERT(utf8_bytes_index == 0); + } + + // use buffer + JSON_ASSERT(utf8_bytes_filled > 0); + JSON_ASSERT(utf8_bytes_index < utf8_bytes_filled); + return utf8_bytes[utf8_bytes_index++]; + } + + private: + BaseInputAdapter base_adapter; + + template + void fill_buffer() + { + wide_string_input_helper::fill_buffer(base_adapter, utf8_bytes, utf8_bytes_index, utf8_bytes_filled); + } + + /// a buffer for UTF-8 bytes + std::array::int_type, 4> utf8_bytes = {{0, 0, 0, 0}}; + + /// index to the utf8_codes array for the next valid byte + std::size_t utf8_bytes_index = 0; + /// number of valid bytes in the utf8_codes array + std::size_t utf8_bytes_filled = 0; +}; + + +template +struct iterator_input_adapter_factory +{ + using iterator_type = IteratorType; + using char_type = typename std::iterator_traits::value_type; + using adapter_type = iterator_input_adapter; + + static adapter_type create(IteratorType first, IteratorType last) + { + return adapter_type(std::move(first), std::move(last)); + } +}; + +template +struct is_iterator_of_multibyte +{ + using value_type = typename std::iterator_traits::value_type; + enum + { + value = sizeof(value_type) > 1 + }; +}; + +template +struct iterator_input_adapter_factory::value>> +{ + using iterator_type = IteratorType; + using char_type = typename std::iterator_traits::value_type; + using base_adapter_type = iterator_input_adapter; + using adapter_type = wide_string_input_adapter; + + static adapter_type create(IteratorType first, IteratorType last) + { + return adapter_type(base_adapter_type(std::move(first), std::move(last))); + } +}; + +// General purpose iterator-based input +template +typename iterator_input_adapter_factory::adapter_type input_adapter(IteratorType first, IteratorType last) +{ + using factory_type = iterator_input_adapter_factory; + return factory_type::create(first, last); +} + +// Convenience shorthand from container to iterator +// Enables ADL on begin(container) and end(container) +// Encloses the using declarations in namespace for not to leak them to outside scope + +namespace container_input_adapter_factory_impl +{ + +using std::begin; +using std::end; + +template +struct container_input_adapter_factory {}; + +template +struct container_input_adapter_factory< ContainerType, + void_t()), end(std::declval()))>> + { + using adapter_type = decltype(input_adapter(begin(std::declval()), end(std::declval()))); + + static adapter_type create(const ContainerType& container) +{ + return input_adapter(begin(container), end(container)); +} + }; + +} // namespace container_input_adapter_factory_impl + +template +typename container_input_adapter_factory_impl::container_input_adapter_factory::adapter_type input_adapter(const ContainerType& container) +{ + return container_input_adapter_factory_impl::container_input_adapter_factory::create(container); +} + +#ifndef JSON_NO_IO +// Special cases with fast paths +inline file_input_adapter input_adapter(std::FILE* file) +{ + return file_input_adapter(file); +} + +inline input_stream_adapter input_adapter(std::istream& stream) +{ + return input_stream_adapter(stream); +} + +inline input_stream_adapter input_adapter(std::istream&& stream) +{ + return input_stream_adapter(stream); +} +#endif // JSON_NO_IO + +using contiguous_bytes_input_adapter = decltype(input_adapter(std::declval(), std::declval())); + +// Null-delimited strings, and the like. +template < typename CharT, + typename std::enable_if < + std::is_pointer::value&& + !std::is_array::value&& + std::is_integral::type>::value&& + sizeof(typename std::remove_pointer::type) == 1, + int >::type = 0 > +contiguous_bytes_input_adapter input_adapter(CharT b) +{ + auto length = std::strlen(reinterpret_cast(b)); + const auto* ptr = reinterpret_cast(b); + return input_adapter(ptr, ptr + length); +} + +template +auto input_adapter(T (&array)[N]) -> decltype(input_adapter(array, array + N)) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) +{ + return input_adapter(array, array + N); +} + +// This class only handles inputs of input_buffer_adapter type. +// It's required so that expressions like {ptr, len} can be implicitely casted +// to the correct adapter. +class span_input_adapter +{ + public: + template < typename CharT, + typename std::enable_if < + std::is_pointer::value&& + std::is_integral::type>::value&& + sizeof(typename std::remove_pointer::type) == 1, + int >::type = 0 > + span_input_adapter(CharT b, std::size_t l) + : ia(reinterpret_cast(b), reinterpret_cast(b) + l) {} + + template::iterator_category, std::random_access_iterator_tag>::value, + int>::type = 0> + span_input_adapter(IteratorType first, IteratorType last) + : ia(input_adapter(first, last)) {} + + contiguous_bytes_input_adapter&& get() + { + return std::move(ia); // NOLINT(hicpp-move-const-arg,performance-move-const-arg) + } + + private: + contiguous_bytes_input_adapter ia; +}; +} // namespace detail +} // namespace nlohmann + +// #include + + +#include +#include // string +#include // move +#include // vector + +// #include + +// #include + + +namespace nlohmann +{ + +/*! +@brief SAX interface + +This class describes the SAX interface used by @ref nlohmann::json::sax_parse. +Each function is called in different situations while the input is parsed. The +boolean return value informs the parser whether to continue processing the +input. +*/ +template +struct json_sax +{ + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + using binary_t = typename BasicJsonType::binary_t; + + /*! + @brief a null value was read + @return whether parsing should proceed + */ + virtual bool null() = 0; + + /*! + @brief a boolean value was read + @param[in] val boolean value + @return whether parsing should proceed + */ + virtual bool boolean(bool val) = 0; + + /*! + @brief an integer number was read + @param[in] val integer value + @return whether parsing should proceed + */ + virtual bool number_integer(number_integer_t val) = 0; + + /*! + @brief an unsigned integer number was read + @param[in] val unsigned integer value + @return whether parsing should proceed + */ + virtual bool number_unsigned(number_unsigned_t val) = 0; + + /*! + @brief an floating-point number was read + @param[in] val floating-point value + @param[in] s raw token value + @return whether parsing should proceed + */ + virtual bool number_float(number_float_t val, const string_t& s) = 0; + + /*! + @brief a string was read + @param[in] val string value + @return whether parsing should proceed + @note It is safe to move the passed string. + */ + virtual bool string(string_t& val) = 0; + + /*! + @brief a binary string was read + @param[in] val binary value + @return whether parsing should proceed + @note It is safe to move the passed binary. + */ + virtual bool binary(binary_t& val) = 0; + + /*! + @brief the beginning of an object was read + @param[in] elements number of object elements or -1 if unknown + @return whether parsing should proceed + @note binary formats may report the number of elements + */ + virtual bool start_object(std::size_t elements) = 0; + + /*! + @brief an object key was read + @param[in] val object key + @return whether parsing should proceed + @note It is safe to move the passed string. + */ + virtual bool key(string_t& val) = 0; + + /*! + @brief the end of an object was read + @return whether parsing should proceed + */ + virtual bool end_object() = 0; + + /*! + @brief the beginning of an array was read + @param[in] elements number of array elements or -1 if unknown + @return whether parsing should proceed + @note binary formats may report the number of elements + */ + virtual bool start_array(std::size_t elements) = 0; + + /*! + @brief the end of an array was read + @return whether parsing should proceed + */ + virtual bool end_array() = 0; + + /*! + @brief a parse error occurred + @param[in] position the position in the input where the error occurs + @param[in] last_token the last read token + @param[in] ex an exception object describing the error + @return whether parsing should proceed (must return false) + */ + virtual bool parse_error(std::size_t position, + const std::string& last_token, + const detail::exception& ex) = 0; + + json_sax() = default; + json_sax(const json_sax&) = default; + json_sax(json_sax&&) noexcept = default; + json_sax& operator=(const json_sax&) = default; + json_sax& operator=(json_sax&&) noexcept = default; + virtual ~json_sax() = default; +}; + + +namespace detail +{ +/*! +@brief SAX implementation to create a JSON value from SAX events + +This class implements the @ref json_sax interface and processes the SAX events +to create a JSON value which makes it basically a DOM parser. The structure or +hierarchy of the JSON value is managed by the stack `ref_stack` which contains +a pointer to the respective array or object for each recursion depth. + +After successful parsing, the value that is passed by reference to the +constructor contains the parsed value. + +@tparam BasicJsonType the JSON type +*/ +template +class json_sax_dom_parser +{ + public: + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + using binary_t = typename BasicJsonType::binary_t; + + /*! + @param[in,out] r reference to a JSON value that is manipulated while + parsing + @param[in] allow_exceptions_ whether parse errors yield exceptions + */ + explicit json_sax_dom_parser(BasicJsonType& r, const bool allow_exceptions_ = true) + : root(r), allow_exceptions(allow_exceptions_) + {} + + // make class move-only + json_sax_dom_parser(const json_sax_dom_parser&) = delete; + json_sax_dom_parser(json_sax_dom_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) + json_sax_dom_parser& operator=(const json_sax_dom_parser&) = delete; + json_sax_dom_parser& operator=(json_sax_dom_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) + ~json_sax_dom_parser() = default; + + bool null() + { + handle_value(nullptr); + return true; + } + + bool boolean(bool val) + { + handle_value(val); + return true; + } + + bool number_integer(number_integer_t val) + { + handle_value(val); + return true; + } + + bool number_unsigned(number_unsigned_t val) + { + handle_value(val); + return true; + } + + bool number_float(number_float_t val, const string_t& /*unused*/) + { + handle_value(val); + return true; + } + + bool string(string_t& val) + { + handle_value(val); + return true; + } + + bool binary(binary_t& val) + { + handle_value(std::move(val)); + return true; + } + + bool start_object(std::size_t len) + { + ref_stack.push_back(handle_value(BasicJsonType::value_t::object)); + + if (JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size())) + { + JSON_THROW(out_of_range::create(408, "excessive object size: " + std::to_string(len), *ref_stack.back())); + } + + return true; + } + + bool key(string_t& val) + { + // add null at given key and store the reference for later + object_element = &(ref_stack.back()->m_value.object->operator[](val)); + return true; + } + + bool end_object() + { + ref_stack.back()->set_parents(); + ref_stack.pop_back(); + return true; + } + + bool start_array(std::size_t len) + { + ref_stack.push_back(handle_value(BasicJsonType::value_t::array)); + + if (JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size())) + { + JSON_THROW(out_of_range::create(408, "excessive array size: " + std::to_string(len), *ref_stack.back())); + } + + return true; + } + + bool end_array() + { + ref_stack.back()->set_parents(); + ref_stack.pop_back(); + return true; + } + + template + bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, + const Exception& ex) + { + errored = true; + static_cast(ex); + if (allow_exceptions) + { + JSON_THROW(ex); + } + return false; + } + + constexpr bool is_errored() const + { + return errored; + } + + private: + /*! + @invariant If the ref stack is empty, then the passed value will be the new + root. + @invariant If the ref stack contains a value, then it is an array or an + object to which we can add elements + */ + template + JSON_HEDLEY_RETURNS_NON_NULL + BasicJsonType* handle_value(Value&& v) + { + if (ref_stack.empty()) + { + root = BasicJsonType(std::forward(v)); + return &root; + } + + JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object()); + + if (ref_stack.back()->is_array()) + { + ref_stack.back()->m_value.array->emplace_back(std::forward(v)); + return &(ref_stack.back()->m_value.array->back()); + } + + JSON_ASSERT(ref_stack.back()->is_object()); + JSON_ASSERT(object_element); + *object_element = BasicJsonType(std::forward(v)); + return object_element; + } + + /// the parsed JSON value + BasicJsonType& root; + /// stack to model hierarchy of values + std::vector ref_stack {}; + /// helper to hold the reference for the next object element + BasicJsonType* object_element = nullptr; + /// whether a syntax error occurred + bool errored = false; + /// whether to throw exceptions in case of errors + const bool allow_exceptions = true; +}; + +template +class json_sax_dom_callback_parser +{ + public: + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + using binary_t = typename BasicJsonType::binary_t; + using parser_callback_t = typename BasicJsonType::parser_callback_t; + using parse_event_t = typename BasicJsonType::parse_event_t; + + json_sax_dom_callback_parser(BasicJsonType& r, + const parser_callback_t cb, + const bool allow_exceptions_ = true) + : root(r), callback(cb), allow_exceptions(allow_exceptions_) + { + keep_stack.push_back(true); + } + + // make class move-only + json_sax_dom_callback_parser(const json_sax_dom_callback_parser&) = delete; + json_sax_dom_callback_parser(json_sax_dom_callback_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) + json_sax_dom_callback_parser& operator=(const json_sax_dom_callback_parser&) = delete; + json_sax_dom_callback_parser& operator=(json_sax_dom_callback_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) + ~json_sax_dom_callback_parser() = default; + + bool null() + { + handle_value(nullptr); + return true; + } + + bool boolean(bool val) + { + handle_value(val); + return true; + } + + bool number_integer(number_integer_t val) + { + handle_value(val); + return true; + } + + bool number_unsigned(number_unsigned_t val) + { + handle_value(val); + return true; + } + + bool number_float(number_float_t val, const string_t& /*unused*/) + { + handle_value(val); + return true; + } + + bool string(string_t& val) + { + handle_value(val); + return true; + } + + bool binary(binary_t& val) + { + handle_value(std::move(val)); + return true; + } + + bool start_object(std::size_t len) + { + // check callback for object start + const bool keep = callback(static_cast(ref_stack.size()), parse_event_t::object_start, discarded); + keep_stack.push_back(keep); + + auto val = handle_value(BasicJsonType::value_t::object, true); + ref_stack.push_back(val.second); + + // check object limit + if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size())) + { + JSON_THROW(out_of_range::create(408, "excessive object size: " + std::to_string(len), *ref_stack.back())); + } + + return true; + } + + bool key(string_t& val) + { + BasicJsonType k = BasicJsonType(val); + + // check callback for key + const bool keep = callback(static_cast(ref_stack.size()), parse_event_t::key, k); + key_keep_stack.push_back(keep); + + // add discarded value at given key and store the reference for later + if (keep && ref_stack.back()) + { + object_element = &(ref_stack.back()->m_value.object->operator[](val) = discarded); + } + + return true; + } + + bool end_object() + { + if (ref_stack.back()) + { + if (!callback(static_cast(ref_stack.size()) - 1, parse_event_t::object_end, *ref_stack.back())) + { + // discard object + *ref_stack.back() = discarded; + } + else + { + ref_stack.back()->set_parents(); + } + } + + JSON_ASSERT(!ref_stack.empty()); + JSON_ASSERT(!keep_stack.empty()); + ref_stack.pop_back(); + keep_stack.pop_back(); + + if (!ref_stack.empty() && ref_stack.back() && ref_stack.back()->is_structured()) + { + // remove discarded value + for (auto it = ref_stack.back()->begin(); it != ref_stack.back()->end(); ++it) + { + if (it->is_discarded()) + { + ref_stack.back()->erase(it); + break; + } + } + } + + return true; + } + + bool start_array(std::size_t len) + { + const bool keep = callback(static_cast(ref_stack.size()), parse_event_t::array_start, discarded); + keep_stack.push_back(keep); + + auto val = handle_value(BasicJsonType::value_t::array, true); + ref_stack.push_back(val.second); + + // check array limit + if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != std::size_t(-1) && len > ref_stack.back()->max_size())) + { + JSON_THROW(out_of_range::create(408, "excessive array size: " + std::to_string(len), *ref_stack.back())); + } + + return true; + } + + bool end_array() + { + bool keep = true; + + if (ref_stack.back()) + { + keep = callback(static_cast(ref_stack.size()) - 1, parse_event_t::array_end, *ref_stack.back()); + if (keep) + { + ref_stack.back()->set_parents(); + } + else + { + // discard array + *ref_stack.back() = discarded; + } + } + + JSON_ASSERT(!ref_stack.empty()); + JSON_ASSERT(!keep_stack.empty()); + ref_stack.pop_back(); + keep_stack.pop_back(); + + // remove discarded value + if (!keep && !ref_stack.empty() && ref_stack.back()->is_array()) + { + ref_stack.back()->m_value.array->pop_back(); + } + + return true; + } + + template + bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, + const Exception& ex) + { + errored = true; + static_cast(ex); + if (allow_exceptions) + { + JSON_THROW(ex); + } + return false; + } + + constexpr bool is_errored() const + { + return errored; + } + + private: + /*! + @param[in] v value to add to the JSON value we build during parsing + @param[in] skip_callback whether we should skip calling the callback + function; this is required after start_array() and + start_object() SAX events, because otherwise we would call the + callback function with an empty array or object, respectively. + + @invariant If the ref stack is empty, then the passed value will be the new + root. + @invariant If the ref stack contains a value, then it is an array or an + object to which we can add elements + + @return pair of boolean (whether value should be kept) and pointer (to the + passed value in the ref_stack hierarchy; nullptr if not kept) + */ + template + std::pair handle_value(Value&& v, const bool skip_callback = false) + { + JSON_ASSERT(!keep_stack.empty()); + + // do not handle this value if we know it would be added to a discarded + // container + if (!keep_stack.back()) + { + return {false, nullptr}; + } + + // create value + auto value = BasicJsonType(std::forward(v)); + + // check callback + const bool keep = skip_callback || callback(static_cast(ref_stack.size()), parse_event_t::value, value); + + // do not handle this value if we just learnt it shall be discarded + if (!keep) + { + return {false, nullptr}; + } + + if (ref_stack.empty()) + { + root = std::move(value); + return {true, &root}; + } + + // skip this value if we already decided to skip the parent + // (https://github.com/nlohmann/json/issues/971#issuecomment-413678360) + if (!ref_stack.back()) + { + return {false, nullptr}; + } + + // we now only expect arrays and objects + JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object()); + + // array + if (ref_stack.back()->is_array()) + { + ref_stack.back()->m_value.array->emplace_back(std::move(value)); + return {true, &(ref_stack.back()->m_value.array->back())}; + } + + // object + JSON_ASSERT(ref_stack.back()->is_object()); + // check if we should store an element for the current key + JSON_ASSERT(!key_keep_stack.empty()); + const bool store_element = key_keep_stack.back(); + key_keep_stack.pop_back(); + + if (!store_element) + { + return {false, nullptr}; + } + + JSON_ASSERT(object_element); + *object_element = std::move(value); + return {true, object_element}; + } + + /// the parsed JSON value + BasicJsonType& root; + /// stack to model hierarchy of values + std::vector ref_stack {}; + /// stack to manage which values to keep + std::vector keep_stack {}; + /// stack to manage which object keys to keep + std::vector key_keep_stack {}; + /// helper to hold the reference for the next object element + BasicJsonType* object_element = nullptr; + /// whether a syntax error occurred + bool errored = false; + /// callback function + const parser_callback_t callback = nullptr; + /// whether to throw exceptions in case of errors + const bool allow_exceptions = true; + /// a discarded value for the callback + BasicJsonType discarded = BasicJsonType::value_t::discarded; +}; + +template +class json_sax_acceptor +{ + public: + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + using binary_t = typename BasicJsonType::binary_t; + + bool null() + { + return true; + } + + bool boolean(bool /*unused*/) + { + return true; + } + + bool number_integer(number_integer_t /*unused*/) + { + return true; + } + + bool number_unsigned(number_unsigned_t /*unused*/) + { + return true; + } + + bool number_float(number_float_t /*unused*/, const string_t& /*unused*/) + { + return true; + } + + bool string(string_t& /*unused*/) + { + return true; + } + + bool binary(binary_t& /*unused*/) + { + return true; + } + + bool start_object(std::size_t /*unused*/ = std::size_t(-1)) + { + return true; + } + + bool key(string_t& /*unused*/) + { + return true; + } + + bool end_object() + { + return true; + } + + bool start_array(std::size_t /*unused*/ = std::size_t(-1)) + { + return true; + } + + bool end_array() + { + return true; + } + + bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const detail::exception& /*unused*/) + { + return false; + } +}; +} // namespace detail + +} // namespace nlohmann + +// #include + + +#include // array +#include // localeconv +#include // size_t +#include // snprintf +#include // strtof, strtod, strtold, strtoll, strtoull +#include // initializer_list +#include // char_traits, string +#include // move +#include // vector + +// #include + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +/////////// +// lexer // +/////////// + +template +class lexer_base +{ + public: + /// token types for the parser + enum class token_type + { + uninitialized, ///< indicating the scanner is uninitialized + literal_true, ///< the `true` literal + literal_false, ///< the `false` literal + literal_null, ///< the `null` literal + value_string, ///< a string -- use get_string() for actual value + value_unsigned, ///< an unsigned integer -- use get_number_unsigned() for actual value + value_integer, ///< a signed integer -- use get_number_integer() for actual value + value_float, ///< an floating point number -- use get_number_float() for actual value + begin_array, ///< the character for array begin `[` + begin_object, ///< the character for object begin `{` + end_array, ///< the character for array end `]` + end_object, ///< the character for object end `}` + name_separator, ///< the name separator `:` + value_separator, ///< the value separator `,` + parse_error, ///< indicating a parse error + end_of_input, ///< indicating the end of the input buffer + literal_or_value ///< a literal or the begin of a value (only for diagnostics) + }; + + /// return name of values of type token_type (only used for errors) + JSON_HEDLEY_RETURNS_NON_NULL + JSON_HEDLEY_CONST + static const char* token_type_name(const token_type t) noexcept + { + switch (t) + { + case token_type::uninitialized: + return ""; + case token_type::literal_true: + return "true literal"; + case token_type::literal_false: + return "false literal"; + case token_type::literal_null: + return "null literal"; + case token_type::value_string: + return "string literal"; + case token_type::value_unsigned: + case token_type::value_integer: + case token_type::value_float: + return "number literal"; + case token_type::begin_array: + return "'['"; + case token_type::begin_object: + return "'{'"; + case token_type::end_array: + return "']'"; + case token_type::end_object: + return "'}'"; + case token_type::name_separator: + return "':'"; + case token_type::value_separator: + return "','"; + case token_type::parse_error: + return ""; + case token_type::end_of_input: + return "end of input"; + case token_type::literal_or_value: + return "'[', '{', or a literal"; + // LCOV_EXCL_START + default: // catch non-enum values + return "unknown token"; + // LCOV_EXCL_STOP + } + } +}; +/*! +@brief lexical analysis + +This class organizes the lexical analysis during JSON deserialization. +*/ +template +class lexer : public lexer_base +{ + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + using char_type = typename InputAdapterType::char_type; + using char_int_type = typename std::char_traits::int_type; + + public: + using token_type = typename lexer_base::token_type; + + explicit lexer(InputAdapterType&& adapter, bool ignore_comments_ = false) noexcept + : ia(std::move(adapter)) + , ignore_comments(ignore_comments_) + , decimal_point_char(static_cast(get_decimal_point())) + {} + + // delete because of pointer members + lexer(const lexer&) = delete; + lexer(lexer&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) + lexer& operator=(lexer&) = delete; + lexer& operator=(lexer&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) + ~lexer() = default; + + private: + ///////////////////// + // locales + ///////////////////// + + /// return the locale-dependent decimal point + JSON_HEDLEY_PURE + static char get_decimal_point() noexcept + { + const auto* loc = localeconv(); + JSON_ASSERT(loc != nullptr); + return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point); + } + + ///////////////////// + // scan functions + ///////////////////// + + /*! + @brief get codepoint from 4 hex characters following `\u` + + For input "\u c1 c2 c3 c4" the codepoint is: + (c1 * 0x1000) + (c2 * 0x0100) + (c3 * 0x0010) + c4 + = (c1 << 12) + (c2 << 8) + (c3 << 4) + (c4 << 0) + + Furthermore, the possible characters '0'..'9', 'A'..'F', and 'a'..'f' + must be converted to the integers 0x0..0x9, 0xA..0xF, 0xA..0xF, resp. The + conversion is done by subtracting the offset (0x30, 0x37, and 0x57) + between the ASCII value of the character and the desired integer value. + + @return codepoint (0x0000..0xFFFF) or -1 in case of an error (e.g. EOF or + non-hex character) + */ + int get_codepoint() + { + // this function only makes sense after reading `\u` + JSON_ASSERT(current == 'u'); + int codepoint = 0; + + const auto factors = { 12u, 8u, 4u, 0u }; + for (const auto factor : factors) + { + get(); + + if (current >= '0' && current <= '9') + { + codepoint += static_cast((static_cast(current) - 0x30u) << factor); + } + else if (current >= 'A' && current <= 'F') + { + codepoint += static_cast((static_cast(current) - 0x37u) << factor); + } + else if (current >= 'a' && current <= 'f') + { + codepoint += static_cast((static_cast(current) - 0x57u) << factor); + } + else + { + return -1; + } + } + + JSON_ASSERT(0x0000 <= codepoint && codepoint <= 0xFFFF); + return codepoint; + } + + /*! + @brief check if the next byte(s) are inside a given range + + Adds the current byte and, for each passed range, reads a new byte and + checks if it is inside the range. If a violation was detected, set up an + error message and return false. Otherwise, return true. + + @param[in] ranges list of integers; interpreted as list of pairs of + inclusive lower and upper bound, respectively + + @pre The passed list @a ranges must have 2, 4, or 6 elements; that is, + 1, 2, or 3 pairs. This precondition is enforced by an assertion. + + @return true if and only if no range violation was detected + */ + bool next_byte_in_range(std::initializer_list ranges) + { + JSON_ASSERT(ranges.size() == 2 || ranges.size() == 4 || ranges.size() == 6); + add(current); + + for (auto range = ranges.begin(); range != ranges.end(); ++range) + { + get(); + if (JSON_HEDLEY_LIKELY(*range <= current && current <= *(++range))) + { + add(current); + } + else + { + error_message = "invalid string: ill-formed UTF-8 byte"; + return false; + } + } + + return true; + } + + /*! + @brief scan a string literal + + This function scans a string according to Sect. 7 of RFC 8259. While + scanning, bytes are escaped and copied into buffer token_buffer. Then the + function returns successfully, token_buffer is *not* null-terminated (as it + may contain \0 bytes), and token_buffer.size() is the number of bytes in the + string. + + @return token_type::value_string if string could be successfully scanned, + token_type::parse_error otherwise + + @note In case of errors, variable error_message contains a textual + description. + */ + token_type scan_string() + { + // reset token_buffer (ignore opening quote) + reset(); + + // we entered the function by reading an open quote + JSON_ASSERT(current == '\"'); + + while (true) + { + // get next character + switch (get()) + { + // end of file while parsing string + case std::char_traits::eof(): + { + error_message = "invalid string: missing closing quote"; + return token_type::parse_error; + } + + // closing quote + case '\"': + { + return token_type::value_string; + } + + // escapes + case '\\': + { + switch (get()) + { + // quotation mark + case '\"': + add('\"'); + break; + // reverse solidus + case '\\': + add('\\'); + break; + // solidus + case '/': + add('/'); + break; + // backspace + case 'b': + add('\b'); + break; + // form feed + case 'f': + add('\f'); + break; + // line feed + case 'n': + add('\n'); + break; + // carriage return + case 'r': + add('\r'); + break; + // tab + case 't': + add('\t'); + break; + + // unicode escapes + case 'u': + { + const int codepoint1 = get_codepoint(); + int codepoint = codepoint1; // start with codepoint1 + + if (JSON_HEDLEY_UNLIKELY(codepoint1 == -1)) + { + error_message = "invalid string: '\\u' must be followed by 4 hex digits"; + return token_type::parse_error; + } + + // check if code point is a high surrogate + if (0xD800 <= codepoint1 && codepoint1 <= 0xDBFF) + { + // expect next \uxxxx entry + if (JSON_HEDLEY_LIKELY(get() == '\\' && get() == 'u')) + { + const int codepoint2 = get_codepoint(); + + if (JSON_HEDLEY_UNLIKELY(codepoint2 == -1)) + { + error_message = "invalid string: '\\u' must be followed by 4 hex digits"; + return token_type::parse_error; + } + + // check if codepoint2 is a low surrogate + if (JSON_HEDLEY_LIKELY(0xDC00 <= codepoint2 && codepoint2 <= 0xDFFF)) + { + // overwrite codepoint + codepoint = static_cast( + // high surrogate occupies the most significant 22 bits + (static_cast(codepoint1) << 10u) + // low surrogate occupies the least significant 15 bits + + static_cast(codepoint2) + // there is still the 0xD800, 0xDC00 and 0x10000 noise + // in the result so we have to subtract with: + // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00 + - 0x35FDC00u); + } + else + { + error_message = "invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF"; + return token_type::parse_error; + } + } + else + { + error_message = "invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF"; + return token_type::parse_error; + } + } + else + { + if (JSON_HEDLEY_UNLIKELY(0xDC00 <= codepoint1 && codepoint1 <= 0xDFFF)) + { + error_message = "invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF"; + return token_type::parse_error; + } + } + + // result of the above calculation yields a proper codepoint + JSON_ASSERT(0x00 <= codepoint && codepoint <= 0x10FFFF); + + // translate codepoint into bytes + if (codepoint < 0x80) + { + // 1-byte characters: 0xxxxxxx (ASCII) + add(static_cast(codepoint)); + } + else if (codepoint <= 0x7FF) + { + // 2-byte characters: 110xxxxx 10xxxxxx + add(static_cast(0xC0u | (static_cast(codepoint) >> 6u))); + add(static_cast(0x80u | (static_cast(codepoint) & 0x3Fu))); + } + else if (codepoint <= 0xFFFF) + { + // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx + add(static_cast(0xE0u | (static_cast(codepoint) >> 12u))); + add(static_cast(0x80u | ((static_cast(codepoint) >> 6u) & 0x3Fu))); + add(static_cast(0x80u | (static_cast(codepoint) & 0x3Fu))); + } + else + { + // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + add(static_cast(0xF0u | (static_cast(codepoint) >> 18u))); + add(static_cast(0x80u | ((static_cast(codepoint) >> 12u) & 0x3Fu))); + add(static_cast(0x80u | ((static_cast(codepoint) >> 6u) & 0x3Fu))); + add(static_cast(0x80u | (static_cast(codepoint) & 0x3Fu))); + } + + break; + } + + // other characters after escape + default: + error_message = "invalid string: forbidden character after backslash"; + return token_type::parse_error; + } + + break; + } + + // invalid control characters + case 0x00: + { + error_message = "invalid string: control character U+0000 (NUL) must be escaped to \\u0000"; + return token_type::parse_error; + } + + case 0x01: + { + error_message = "invalid string: control character U+0001 (SOH) must be escaped to \\u0001"; + return token_type::parse_error; + } + + case 0x02: + { + error_message = "invalid string: control character U+0002 (STX) must be escaped to \\u0002"; + return token_type::parse_error; + } + + case 0x03: + { + error_message = "invalid string: control character U+0003 (ETX) must be escaped to \\u0003"; + return token_type::parse_error; + } + + case 0x04: + { + error_message = "invalid string: control character U+0004 (EOT) must be escaped to \\u0004"; + return token_type::parse_error; + } + + case 0x05: + { + error_message = "invalid string: control character U+0005 (ENQ) must be escaped to \\u0005"; + return token_type::parse_error; + } + + case 0x06: + { + error_message = "invalid string: control character U+0006 (ACK) must be escaped to \\u0006"; + return token_type::parse_error; + } + + case 0x07: + { + error_message = "invalid string: control character U+0007 (BEL) must be escaped to \\u0007"; + return token_type::parse_error; + } + + case 0x08: + { + error_message = "invalid string: control character U+0008 (BS) must be escaped to \\u0008 or \\b"; + return token_type::parse_error; + } + + case 0x09: + { + error_message = "invalid string: control character U+0009 (HT) must be escaped to \\u0009 or \\t"; + return token_type::parse_error; + } + + case 0x0A: + { + error_message = "invalid string: control character U+000A (LF) must be escaped to \\u000A or \\n"; + return token_type::parse_error; + } + + case 0x0B: + { + error_message = "invalid string: control character U+000B (VT) must be escaped to \\u000B"; + return token_type::parse_error; + } + + case 0x0C: + { + error_message = "invalid string: control character U+000C (FF) must be escaped to \\u000C or \\f"; + return token_type::parse_error; + } + + case 0x0D: + { + error_message = "invalid string: control character U+000D (CR) must be escaped to \\u000D or \\r"; + return token_type::parse_error; + } + + case 0x0E: + { + error_message = "invalid string: control character U+000E (SO) must be escaped to \\u000E"; + return token_type::parse_error; + } + + case 0x0F: + { + error_message = "invalid string: control character U+000F (SI) must be escaped to \\u000F"; + return token_type::parse_error; + } + + case 0x10: + { + error_message = "invalid string: control character U+0010 (DLE) must be escaped to \\u0010"; + return token_type::parse_error; + } + + case 0x11: + { + error_message = "invalid string: control character U+0011 (DC1) must be escaped to \\u0011"; + return token_type::parse_error; + } + + case 0x12: + { + error_message = "invalid string: control character U+0012 (DC2) must be escaped to \\u0012"; + return token_type::parse_error; + } + + case 0x13: + { + error_message = "invalid string: control character U+0013 (DC3) must be escaped to \\u0013"; + return token_type::parse_error; + } + + case 0x14: + { + error_message = "invalid string: control character U+0014 (DC4) must be escaped to \\u0014"; + return token_type::parse_error; + } + + case 0x15: + { + error_message = "invalid string: control character U+0015 (NAK) must be escaped to \\u0015"; + return token_type::parse_error; + } + + case 0x16: + { + error_message = "invalid string: control character U+0016 (SYN) must be escaped to \\u0016"; + return token_type::parse_error; + } + + case 0x17: + { + error_message = "invalid string: control character U+0017 (ETB) must be escaped to \\u0017"; + return token_type::parse_error; + } + + case 0x18: + { + error_message = "invalid string: control character U+0018 (CAN) must be escaped to \\u0018"; + return token_type::parse_error; + } + + case 0x19: + { + error_message = "invalid string: control character U+0019 (EM) must be escaped to \\u0019"; + return token_type::parse_error; + } + + case 0x1A: + { + error_message = "invalid string: control character U+001A (SUB) must be escaped to \\u001A"; + return token_type::parse_error; + } + + case 0x1B: + { + error_message = "invalid string: control character U+001B (ESC) must be escaped to \\u001B"; + return token_type::parse_error; + } + + case 0x1C: + { + error_message = "invalid string: control character U+001C (FS) must be escaped to \\u001C"; + return token_type::parse_error; + } + + case 0x1D: + { + error_message = "invalid string: control character U+001D (GS) must be escaped to \\u001D"; + return token_type::parse_error; + } + + case 0x1E: + { + error_message = "invalid string: control character U+001E (RS) must be escaped to \\u001E"; + return token_type::parse_error; + } + + case 0x1F: + { + error_message = "invalid string: control character U+001F (US) must be escaped to \\u001F"; + return token_type::parse_error; + } + + // U+0020..U+007F (except U+0022 (quote) and U+005C (backspace)) + case 0x20: + case 0x21: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + case 0x29: + case 0x2A: + case 0x2B: + case 0x2C: + case 0x2D: + case 0x2E: + case 0x2F: + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + case 0x38: + case 0x39: + case 0x3A: + case 0x3B: + case 0x3C: + case 0x3D: + case 0x3E: + case 0x3F: + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4A: + case 0x4B: + case 0x4C: + case 0x4D: + case 0x4E: + case 0x4F: + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + case 0x58: + case 0x59: + case 0x5A: + case 0x5B: + case 0x5D: + case 0x5E: + case 0x5F: + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + case 0x78: + case 0x79: + case 0x7A: + case 0x7B: + case 0x7C: + case 0x7D: + case 0x7E: + case 0x7F: + { + add(current); + break; + } + + // U+0080..U+07FF: bytes C2..DF 80..BF + case 0xC2: + case 0xC3: + case 0xC4: + case 0xC5: + case 0xC6: + case 0xC7: + case 0xC8: + case 0xC9: + case 0xCA: + case 0xCB: + case 0xCC: + case 0xCD: + case 0xCE: + case 0xCF: + case 0xD0: + case 0xD1: + case 0xD2: + case 0xD3: + case 0xD4: + case 0xD5: + case 0xD6: + case 0xD7: + case 0xD8: + case 0xD9: + case 0xDA: + case 0xDB: + case 0xDC: + case 0xDD: + case 0xDE: + case 0xDF: + { + if (JSON_HEDLEY_UNLIKELY(!next_byte_in_range({0x80, 0xBF}))) + { + return token_type::parse_error; + } + break; + } + + // U+0800..U+0FFF: bytes E0 A0..BF 80..BF + case 0xE0: + { + if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0xA0, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+1000..U+CFFF: bytes E1..EC 80..BF 80..BF + // U+E000..U+FFFF: bytes EE..EF 80..BF 80..BF + case 0xE1: + case 0xE2: + case 0xE3: + case 0xE4: + case 0xE5: + case 0xE6: + case 0xE7: + case 0xE8: + case 0xE9: + case 0xEA: + case 0xEB: + case 0xEC: + case 0xEE: + case 0xEF: + { + if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+D000..U+D7FF: bytes ED 80..9F 80..BF + case 0xED: + { + if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0x9F, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+10000..U+3FFFF F0 90..BF 80..BF 80..BF + case 0xF0: + { + if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF + case 0xF1: + case 0xF2: + case 0xF3: + { + if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // U+100000..U+10FFFF F4 80..8F 80..BF 80..BF + case 0xF4: + { + if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF})))) + { + return token_type::parse_error; + } + break; + } + + // remaining bytes (80..C1 and F5..FF) are ill-formed + default: + { + error_message = "invalid string: ill-formed UTF-8 byte"; + return token_type::parse_error; + } + } + } + } + + /*! + * @brief scan a comment + * @return whether comment could be scanned successfully + */ + bool scan_comment() + { + switch (get()) + { + // single-line comments skip input until a newline or EOF is read + case '/': + { + while (true) + { + switch (get()) + { + case '\n': + case '\r': + case std::char_traits::eof(): + case '\0': + return true; + + default: + break; + } + } + } + + // multi-line comments skip input until */ is read + case '*': + { + while (true) + { + switch (get()) + { + case std::char_traits::eof(): + case '\0': + { + error_message = "invalid comment; missing closing '*/'"; + return false; + } + + case '*': + { + switch (get()) + { + case '/': + return true; + + default: + { + unget(); + continue; + } + } + } + + default: + continue; + } + } + } + + // unexpected character after reading '/' + default: + { + error_message = "invalid comment; expecting '/' or '*' after '/'"; + return false; + } + } + } + + JSON_HEDLEY_NON_NULL(2) + static void strtof(float& f, const char* str, char** endptr) noexcept + { + f = std::strtof(str, endptr); + } + + JSON_HEDLEY_NON_NULL(2) + static void strtof(double& f, const char* str, char** endptr) noexcept + { + f = std::strtod(str, endptr); + } + + JSON_HEDLEY_NON_NULL(2) + static void strtof(long double& f, const char* str, char** endptr) noexcept + { + f = std::strtold(str, endptr); + } + + /*! + @brief scan a number literal + + This function scans a string according to Sect. 6 of RFC 8259. + + The function is realized with a deterministic finite state machine derived + from the grammar described in RFC 8259. Starting in state "init", the + input is read and used to determined the next state. Only state "done" + accepts the number. State "error" is a trap state to model errors. In the + table below, "anything" means any character but the ones listed before. + + state | 0 | 1-9 | e E | + | - | . | anything + ---------|----------|----------|----------|---------|---------|----------|----------- + init | zero | any1 | [error] | [error] | minus | [error] | [error] + minus | zero | any1 | [error] | [error] | [error] | [error] | [error] + zero | done | done | exponent | done | done | decimal1 | done + any1 | any1 | any1 | exponent | done | done | decimal1 | done + decimal1 | decimal2 | decimal2 | [error] | [error] | [error] | [error] | [error] + decimal2 | decimal2 | decimal2 | exponent | done | done | done | done + exponent | any2 | any2 | [error] | sign | sign | [error] | [error] + sign | any2 | any2 | [error] | [error] | [error] | [error] | [error] + any2 | any2 | any2 | done | done | done | done | done + + The state machine is realized with one label per state (prefixed with + "scan_number_") and `goto` statements between them. The state machine + contains cycles, but any cycle can be left when EOF is read. Therefore, + the function is guaranteed to terminate. + + During scanning, the read bytes are stored in token_buffer. This string is + then converted to a signed integer, an unsigned integer, or a + floating-point number. + + @return token_type::value_unsigned, token_type::value_integer, or + token_type::value_float if number could be successfully scanned, + token_type::parse_error otherwise + + @note The scanner is independent of the current locale. Internally, the + locale's decimal point is used instead of `.` to work with the + locale-dependent converters. + */ + token_type scan_number() // lgtm [cpp/use-of-goto] + { + // reset token_buffer to store the number's bytes + reset(); + + // the type of the parsed number; initially set to unsigned; will be + // changed if minus sign, decimal point or exponent is read + token_type number_type = token_type::value_unsigned; + + // state (init): we just found out we need to scan a number + switch (current) + { + case '-': + { + add(current); + goto scan_number_minus; + } + + case '0': + { + add(current); + goto scan_number_zero; + } + + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any1; + } + + // all other characters are rejected outside scan_number() + default: // LCOV_EXCL_LINE + JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE + } + +scan_number_minus: + // state: we just parsed a leading minus sign + number_type = token_type::value_integer; + switch (get()) + { + case '0': + { + add(current); + goto scan_number_zero; + } + + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any1; + } + + default: + { + error_message = "invalid number; expected digit after '-'"; + return token_type::parse_error; + } + } + +scan_number_zero: + // state: we just parse a zero (maybe with a leading minus sign) + switch (get()) + { + case '.': + { + add(decimal_point_char); + goto scan_number_decimal1; + } + + case 'e': + case 'E': + { + add(current); + goto scan_number_exponent; + } + + default: + goto scan_number_done; + } + +scan_number_any1: + // state: we just parsed a number 0-9 (maybe with a leading minus sign) + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any1; + } + + case '.': + { + add(decimal_point_char); + goto scan_number_decimal1; + } + + case 'e': + case 'E': + { + add(current); + goto scan_number_exponent; + } + + default: + goto scan_number_done; + } + +scan_number_decimal1: + // state: we just parsed a decimal point + number_type = token_type::value_float; + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_decimal2; + } + + default: + { + error_message = "invalid number; expected digit after '.'"; + return token_type::parse_error; + } + } + +scan_number_decimal2: + // we just parsed at least one number after a decimal point + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_decimal2; + } + + case 'e': + case 'E': + { + add(current); + goto scan_number_exponent; + } + + default: + goto scan_number_done; + } + +scan_number_exponent: + // we just parsed an exponent + number_type = token_type::value_float; + switch (get()) + { + case '+': + case '-': + { + add(current); + goto scan_number_sign; + } + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any2; + } + + default: + { + error_message = + "invalid number; expected '+', '-', or digit after exponent"; + return token_type::parse_error; + } + } + +scan_number_sign: + // we just parsed an exponent sign + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any2; + } + + default: + { + error_message = "invalid number; expected digit after exponent sign"; + return token_type::parse_error; + } + } + +scan_number_any2: + // we just parsed a number after the exponent or exponent sign + switch (get()) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + add(current); + goto scan_number_any2; + } + + default: + goto scan_number_done; + } + +scan_number_done: + // unget the character after the number (we only read it to know that + // we are done scanning a number) + unget(); + + char* endptr = nullptr; // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) + errno = 0; + + // try to parse integers first and fall back to floats + if (number_type == token_type::value_unsigned) + { + const auto x = std::strtoull(token_buffer.data(), &endptr, 10); + + // we checked the number format before + JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size()); + + if (errno == 0) + { + value_unsigned = static_cast(x); + if (value_unsigned == x) + { + return token_type::value_unsigned; + } + } + } + else if (number_type == token_type::value_integer) + { + const auto x = std::strtoll(token_buffer.data(), &endptr, 10); + + // we checked the number format before + JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size()); + + if (errno == 0) + { + value_integer = static_cast(x); + if (value_integer == x) + { + return token_type::value_integer; + } + } + } + + // this code is reached if we parse a floating-point number or if an + // integer conversion above failed + strtof(value_float, token_buffer.data(), &endptr); + + // we checked the number format before + JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size()); + + return token_type::value_float; + } + + /*! + @param[in] literal_text the literal text to expect + @param[in] length the length of the passed literal text + @param[in] return_type the token type to return on success + */ + JSON_HEDLEY_NON_NULL(2) + token_type scan_literal(const char_type* literal_text, const std::size_t length, + token_type return_type) + { + JSON_ASSERT(std::char_traits::to_char_type(current) == literal_text[0]); + for (std::size_t i = 1; i < length; ++i) + { + if (JSON_HEDLEY_UNLIKELY(std::char_traits::to_char_type(get()) != literal_text[i])) + { + error_message = "invalid literal"; + return token_type::parse_error; + } + } + return return_type; + } + + ///////////////////// + // input management + ///////////////////// + + /// reset token_buffer; current character is beginning of token + void reset() noexcept + { + token_buffer.clear(); + token_string.clear(); + token_string.push_back(std::char_traits::to_char_type(current)); + } + + /* + @brief get next character from the input + + This function provides the interface to the used input adapter. It does + not throw in case the input reached EOF, but returns a + `std::char_traits::eof()` in that case. Stores the scanned characters + for use in error messages. + + @return character read from the input + */ + char_int_type get() + { + ++position.chars_read_total; + ++position.chars_read_current_line; + + if (next_unget) + { + // just reset the next_unget variable and work with current + next_unget = false; + } + else + { + current = ia.get_character(); + } + + if (JSON_HEDLEY_LIKELY(current != std::char_traits::eof())) + { + token_string.push_back(std::char_traits::to_char_type(current)); + } + + if (current == '\n') + { + ++position.lines_read; + position.chars_read_current_line = 0; + } + + return current; + } + + /*! + @brief unget current character (read it again on next get) + + We implement unget by setting variable next_unget to true. The input is not + changed - we just simulate ungetting by modifying chars_read_total, + chars_read_current_line, and token_string. The next call to get() will + behave as if the unget character is read again. + */ + void unget() + { + next_unget = true; + + --position.chars_read_total; + + // in case we "unget" a newline, we have to also decrement the lines_read + if (position.chars_read_current_line == 0) + { + if (position.lines_read > 0) + { + --position.lines_read; + } + } + else + { + --position.chars_read_current_line; + } + + if (JSON_HEDLEY_LIKELY(current != std::char_traits::eof())) + { + JSON_ASSERT(!token_string.empty()); + token_string.pop_back(); + } + } + + /// add a character to token_buffer + void add(char_int_type c) + { + token_buffer.push_back(static_cast(c)); + } + + public: + ///////////////////// + // value getters + ///////////////////// + + /// return integer value + constexpr number_integer_t get_number_integer() const noexcept + { + return value_integer; + } + + /// return unsigned integer value + constexpr number_unsigned_t get_number_unsigned() const noexcept + { + return value_unsigned; + } + + /// return floating-point value + constexpr number_float_t get_number_float() const noexcept + { + return value_float; + } + + /// return current string value (implicitly resets the token; useful only once) + string_t& get_string() + { + return token_buffer; + } + + ///////////////////// + // diagnostics + ///////////////////// + + /// return position of last read token + constexpr position_t get_position() const noexcept + { + return position; + } + + /// return the last read token (for errors only). Will never contain EOF + /// (an arbitrary value that is not a valid char value, often -1), because + /// 255 may legitimately occur. May contain NUL, which should be escaped. + std::string get_token_string() const + { + // escape control characters + std::string result; + for (const auto c : token_string) + { + if (static_cast(c) <= '\x1F') + { + // escape control characters + std::array cs{{}}; + (std::snprintf)(cs.data(), cs.size(), "", static_cast(c)); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) + result += cs.data(); + } + else + { + // add character as is + result.push_back(static_cast(c)); + } + } + + return result; + } + + /// return syntax error message + JSON_HEDLEY_RETURNS_NON_NULL + constexpr const char* get_error_message() const noexcept + { + return error_message; + } + + ///////////////////// + // actual scanner + ///////////////////// + + /*! + @brief skip the UTF-8 byte order mark + @return true iff there is no BOM or the correct BOM has been skipped + */ + bool skip_bom() + { + if (get() == 0xEF) + { + // check if we completely parse the BOM + return get() == 0xBB && get() == 0xBF; + } + + // the first character is not the beginning of the BOM; unget it to + // process is later + unget(); + return true; + } + + void skip_whitespace() + { + do + { + get(); + } + while (current == ' ' || current == '\t' || current == '\n' || current == '\r'); + } + + token_type scan() + { + // initially, skip the BOM + if (position.chars_read_total == 0 && !skip_bom()) + { + error_message = "invalid BOM; must be 0xEF 0xBB 0xBF if given"; + return token_type::parse_error; + } + + // read next character and ignore whitespace + skip_whitespace(); + + // ignore comments + while (ignore_comments && current == '/') + { + if (!scan_comment()) + { + return token_type::parse_error; + } + + // skip following whitespace + skip_whitespace(); + } + + switch (current) + { + // structural characters + case '[': + return token_type::begin_array; + case ']': + return token_type::end_array; + case '{': + return token_type::begin_object; + case '}': + return token_type::end_object; + case ':': + return token_type::name_separator; + case ',': + return token_type::value_separator; + + // literals + case 't': + { + std::array true_literal = {{char_type('t'), char_type('r'), char_type('u'), char_type('e')}}; + return scan_literal(true_literal.data(), true_literal.size(), token_type::literal_true); + } + case 'f': + { + std::array false_literal = {{char_type('f'), char_type('a'), char_type('l'), char_type('s'), char_type('e')}}; + return scan_literal(false_literal.data(), false_literal.size(), token_type::literal_false); + } + case 'n': + { + std::array null_literal = {{char_type('n'), char_type('u'), char_type('l'), char_type('l')}}; + return scan_literal(null_literal.data(), null_literal.size(), token_type::literal_null); + } + + // string + case '\"': + return scan_string(); + + // number + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return scan_number(); + + // end of input (the null byte is needed when parsing from + // string literals) + case '\0': + case std::char_traits::eof(): + return token_type::end_of_input; + + // error + default: + error_message = "invalid literal"; + return token_type::parse_error; + } + } + + private: + /// input adapter + InputAdapterType ia; + + /// whether comments should be ignored (true) or signaled as errors (false) + const bool ignore_comments = false; + + /// the current character + char_int_type current = std::char_traits::eof(); + + /// whether the next get() call should just return current + bool next_unget = false; + + /// the start position of the current token + position_t position {}; + + /// raw input token string (for error messages) + std::vector token_string {}; + + /// buffer for variable-length tokens (numbers, strings) + string_t token_buffer {}; + + /// a description of occurred lexer errors + const char* error_message = ""; + + // number values + number_integer_t value_integer = 0; + number_unsigned_t value_unsigned = 0; + number_float_t value_float = 0; + + /// the decimal point + const char_int_type decimal_point_char = '.'; +}; +} // namespace detail +} // namespace nlohmann + +// #include + +// #include + + +#include // size_t +#include // declval +#include // string + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +template +using null_function_t = decltype(std::declval().null()); + +template +using boolean_function_t = + decltype(std::declval().boolean(std::declval())); + +template +using number_integer_function_t = + decltype(std::declval().number_integer(std::declval())); + +template +using number_unsigned_function_t = + decltype(std::declval().number_unsigned(std::declval())); + +template +using number_float_function_t = decltype(std::declval().number_float( + std::declval(), std::declval())); + +template +using string_function_t = + decltype(std::declval().string(std::declval())); + +template +using binary_function_t = + decltype(std::declval().binary(std::declval())); + +template +using start_object_function_t = + decltype(std::declval().start_object(std::declval())); + +template +using key_function_t = + decltype(std::declval().key(std::declval())); + +template +using end_object_function_t = decltype(std::declval().end_object()); + +template +using start_array_function_t = + decltype(std::declval().start_array(std::declval())); + +template +using end_array_function_t = decltype(std::declval().end_array()); + +template +using parse_error_function_t = decltype(std::declval().parse_error( + std::declval(), std::declval(), + std::declval())); + +template +struct is_sax +{ + private: + static_assert(is_basic_json::value, + "BasicJsonType must be of type basic_json<...>"); + + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + using binary_t = typename BasicJsonType::binary_t; + using exception_t = typename BasicJsonType::exception; + + public: + static constexpr bool value = + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value && + is_detected_exact::value; +}; + +template +struct is_sax_static_asserts +{ + private: + static_assert(is_basic_json::value, + "BasicJsonType must be of type basic_json<...>"); + + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + using binary_t = typename BasicJsonType::binary_t; + using exception_t = typename BasicJsonType::exception; + + public: + static_assert(is_detected_exact::value, + "Missing/invalid function: bool null()"); + static_assert(is_detected_exact::value, + "Missing/invalid function: bool boolean(bool)"); + static_assert(is_detected_exact::value, + "Missing/invalid function: bool boolean(bool)"); + static_assert( + is_detected_exact::value, + "Missing/invalid function: bool number_integer(number_integer_t)"); + static_assert( + is_detected_exact::value, + "Missing/invalid function: bool number_unsigned(number_unsigned_t)"); + static_assert(is_detected_exact::value, + "Missing/invalid function: bool number_float(number_float_t, const string_t&)"); + static_assert( + is_detected_exact::value, + "Missing/invalid function: bool string(string_t&)"); + static_assert( + is_detected_exact::value, + "Missing/invalid function: bool binary(binary_t&)"); + static_assert(is_detected_exact::value, + "Missing/invalid function: bool start_object(std::size_t)"); + static_assert(is_detected_exact::value, + "Missing/invalid function: bool key(string_t&)"); + static_assert(is_detected_exact::value, + "Missing/invalid function: bool end_object()"); + static_assert(is_detected_exact::value, + "Missing/invalid function: bool start_array(std::size_t)"); + static_assert(is_detected_exact::value, + "Missing/invalid function: bool end_array()"); + static_assert( + is_detected_exact::value, + "Missing/invalid function: bool parse_error(std::size_t, const " + "std::string&, const exception&)"); +}; +} // namespace detail +} // namespace nlohmann + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ + +/// how to treat CBOR tags +enum class cbor_tag_handler_t +{ + error, ///< throw a parse_error exception in case of a tag + ignore, ///< ignore tags + store ///< store tags as binary type +}; + +/*! +@brief determine system byte order + +@return true if and only if system's byte order is little endian + +@note from https://stackoverflow.com/a/1001328/266378 +*/ +static inline bool little_endianess(int num = 1) noexcept +{ + return *reinterpret_cast(&num) == 1; +} + + +/////////////////// +// binary reader // +/////////////////// + +/*! +@brief deserialization of CBOR, MessagePack, and UBJSON values +*/ +template> +class binary_reader +{ + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + using binary_t = typename BasicJsonType::binary_t; + using json_sax_t = SAX; + using char_type = typename InputAdapterType::char_type; + using char_int_type = typename std::char_traits::int_type; + + public: + /*! + @brief create a binary reader + + @param[in] adapter input adapter to read from + */ + explicit binary_reader(InputAdapterType&& adapter) noexcept : ia(std::move(adapter)) + { + (void)detail::is_sax_static_asserts {}; + } + + // make class move-only + binary_reader(const binary_reader&) = delete; + binary_reader(binary_reader&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) + binary_reader& operator=(const binary_reader&) = delete; + binary_reader& operator=(binary_reader&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) + ~binary_reader() = default; + + /*! + @param[in] format the binary format to parse + @param[in] sax_ a SAX event processor + @param[in] strict whether to expect the input to be consumed completed + @param[in] tag_handler how to treat CBOR tags + + @return whether parsing was successful + */ + JSON_HEDLEY_NON_NULL(3) + bool sax_parse(const input_format_t format, + json_sax_t* sax_, + const bool strict = true, + const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) + { + sax = sax_; + bool result = false; + + switch (format) + { + case input_format_t::bson: + result = parse_bson_internal(); + break; + + case input_format_t::cbor: + result = parse_cbor_internal(true, tag_handler); + break; + + case input_format_t::msgpack: + result = parse_msgpack_internal(); + break; + + case input_format_t::ubjson: + result = parse_ubjson_internal(); + break; + + case input_format_t::json: // LCOV_EXCL_LINE + default: // LCOV_EXCL_LINE + JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE + } + + // strict mode: next byte must be EOF + if (result && strict) + { + if (format == input_format_t::ubjson) + { + get_ignore_noop(); + } + else + { + get(); + } + + if (JSON_HEDLEY_UNLIKELY(current != std::char_traits::eof())) + { + return sax->parse_error(chars_read, get_token_string(), + parse_error::create(110, chars_read, exception_message(format, "expected end of input; last byte: 0x" + get_token_string(), "value"), BasicJsonType())); + } + } + + return result; + } + + private: + ////////// + // BSON // + ////////// + + /*! + @brief Reads in a BSON-object and passes it to the SAX-parser. + @return whether a valid BSON-value was passed to the SAX parser + */ + bool parse_bson_internal() + { + std::int32_t document_size{}; + get_number(input_format_t::bson, document_size); + + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(std::size_t(-1)))) + { + return false; + } + + if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_list(/*is_array*/false))) + { + return false; + } + + return sax->end_object(); + } + + /*! + @brief Parses a C-style string from the BSON input. + @param[in,out] result A reference to the string variable where the read + string is to be stored. + @return `true` if the \x00-byte indicating the end of the string was + encountered before the EOF; false` indicates an unexpected EOF. + */ + bool get_bson_cstr(string_t& result) + { + auto out = std::back_inserter(result); + while (true) + { + get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::bson, "cstring"))) + { + return false; + } + if (current == 0x00) + { + return true; + } + *out++ = static_cast(current); + } + } + + /*! + @brief Parses a zero-terminated string of length @a len from the BSON + input. + @param[in] len The length (including the zero-byte at the end) of the + string to be read. + @param[in,out] result A reference to the string variable where the read + string is to be stored. + @tparam NumberType The type of the length @a len + @pre len >= 1 + @return `true` if the string was successfully parsed + */ + template + bool get_bson_string(const NumberType len, string_t& result) + { + if (JSON_HEDLEY_UNLIKELY(len < 1)) + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::bson, "string length must be at least 1, is " + std::to_string(len), "string"), BasicJsonType())); + } + + return get_string(input_format_t::bson, len - static_cast(1), result) && get() != std::char_traits::eof(); + } + + /*! + @brief Parses a byte array input of length @a len from the BSON input. + @param[in] len The length of the byte array to be read. + @param[in,out] result A reference to the binary variable where the read + array is to be stored. + @tparam NumberType The type of the length @a len + @pre len >= 0 + @return `true` if the byte array was successfully parsed + */ + template + bool get_bson_binary(const NumberType len, binary_t& result) + { + if (JSON_HEDLEY_UNLIKELY(len < 0)) + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::bson, "byte array length cannot be negative, is " + std::to_string(len), "binary"), BasicJsonType())); + } + + // All BSON binary values have a subtype + std::uint8_t subtype{}; + get_number(input_format_t::bson, subtype); + result.set_subtype(subtype); + + return get_binary(input_format_t::bson, len, result); + } + + /*! + @brief Read a BSON document element of the given @a element_type. + @param[in] element_type The BSON element type, c.f. http://bsonspec.org/spec.html + @param[in] element_type_parse_position The position in the input stream, + where the `element_type` was read. + @warning Not all BSON element types are supported yet. An unsupported + @a element_type will give rise to a parse_error.114: + Unsupported BSON record type 0x... + @return whether a valid BSON-object/array was passed to the SAX parser + */ + bool parse_bson_element_internal(const char_int_type element_type, + const std::size_t element_type_parse_position) + { + switch (element_type) + { + case 0x01: // double + { + double number{}; + return get_number(input_format_t::bson, number) && sax->number_float(static_cast(number), ""); + } + + case 0x02: // string + { + std::int32_t len{}; + string_t value; + return get_number(input_format_t::bson, len) && get_bson_string(len, value) && sax->string(value); + } + + case 0x03: // object + { + return parse_bson_internal(); + } + + case 0x04: // array + { + return parse_bson_array(); + } + + case 0x05: // binary + { + std::int32_t len{}; + binary_t value; + return get_number(input_format_t::bson, len) && get_bson_binary(len, value) && sax->binary(value); + } + + case 0x08: // boolean + { + return sax->boolean(get() != 0); + } + + case 0x0A: // null + { + return sax->null(); + } + + case 0x10: // int32 + { + std::int32_t value{}; + return get_number(input_format_t::bson, value) && sax->number_integer(value); + } + + case 0x12: // int64 + { + std::int64_t value{}; + return get_number(input_format_t::bson, value) && sax->number_integer(value); + } + + default: // anything else not supported (yet) + { + std::array cr{{}}; + (std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast(element_type)); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) + return sax->parse_error(element_type_parse_position, std::string(cr.data()), parse_error::create(114, element_type_parse_position, "Unsupported BSON record type 0x" + std::string(cr.data()), BasicJsonType())); + } + } + } + + /*! + @brief Read a BSON element list (as specified in the BSON-spec) + + The same binary layout is used for objects and arrays, hence it must be + indicated with the argument @a is_array which one is expected + (true --> array, false --> object). + + @param[in] is_array Determines if the element list being read is to be + treated as an object (@a is_array == false), or as an + array (@a is_array == true). + @return whether a valid BSON-object/array was passed to the SAX parser + */ + bool parse_bson_element_list(const bool is_array) + { + string_t key; + + while (auto element_type = get()) + { + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::bson, "element list"))) + { + return false; + } + + const std::size_t element_type_parse_position = chars_read; + if (JSON_HEDLEY_UNLIKELY(!get_bson_cstr(key))) + { + return false; + } + + if (!is_array && !sax->key(key)) + { + return false; + } + + if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_internal(element_type, element_type_parse_position))) + { + return false; + } + + // get_bson_cstr only appends + key.clear(); + } + + return true; + } + + /*! + @brief Reads an array from the BSON input and passes it to the SAX-parser. + @return whether a valid BSON-array was passed to the SAX parser + */ + bool parse_bson_array() + { + std::int32_t document_size{}; + get_number(input_format_t::bson, document_size); + + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(std::size_t(-1)))) + { + return false; + } + + if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_list(/*is_array*/true))) + { + return false; + } + + return sax->end_array(); + } + + ////////// + // CBOR // + ////////// + + /*! + @param[in] get_char whether a new character should be retrieved from the + input (true) or whether the last read character should + be considered instead (false) + @param[in] tag_handler how CBOR tags should be treated + + @return whether a valid CBOR value was passed to the SAX parser + */ + bool parse_cbor_internal(const bool get_char, + const cbor_tag_handler_t tag_handler) + { + switch (get_char ? get() : current) + { + // EOF + case std::char_traits::eof(): + return unexpect_eof(input_format_t::cbor, "value"); + + // Integer 0x00..0x17 (0..23) + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0A: + case 0x0B: + case 0x0C: + case 0x0D: + case 0x0E: + case 0x0F: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + return sax->number_unsigned(static_cast(current)); + + case 0x18: // Unsigned integer (one-byte uint8_t follows) + { + std::uint8_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_unsigned(number); + } + + case 0x19: // Unsigned integer (two-byte uint16_t follows) + { + std::uint16_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_unsigned(number); + } + + case 0x1A: // Unsigned integer (four-byte uint32_t follows) + { + std::uint32_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_unsigned(number); + } + + case 0x1B: // Unsigned integer (eight-byte uint64_t follows) + { + std::uint64_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_unsigned(number); + } + + // Negative integer -1-0x00..-1-0x17 (-1..-24) + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + case 0x29: + case 0x2A: + case 0x2B: + case 0x2C: + case 0x2D: + case 0x2E: + case 0x2F: + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + return sax->number_integer(static_cast(0x20 - 1 - current)); + + case 0x38: // Negative integer (one-byte uint8_t follows) + { + std::uint8_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast(-1) - number); + } + + case 0x39: // Negative integer -1-n (two-byte uint16_t follows) + { + std::uint16_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast(-1) - number); + } + + case 0x3A: // Negative integer -1-n (four-byte uint32_t follows) + { + std::uint32_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast(-1) - number); + } + + case 0x3B: // Negative integer -1-n (eight-byte uint64_t follows) + { + std::uint64_t number{}; + return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast(-1) + - static_cast(number)); + } + + // Binary data (0x00..0x17 bytes follow) + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4A: + case 0x4B: + case 0x4C: + case 0x4D: + case 0x4E: + case 0x4F: + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + case 0x58: // Binary data (one-byte uint8_t for n follows) + case 0x59: // Binary data (two-byte uint16_t for n follow) + case 0x5A: // Binary data (four-byte uint32_t for n follow) + case 0x5B: // Binary data (eight-byte uint64_t for n follow) + case 0x5F: // Binary data (indefinite length) + { + binary_t b; + return get_cbor_binary(b) && sax->binary(b); + } + + // UTF-8 string (0x00..0x17 bytes follow) + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + case 0x78: // UTF-8 string (one-byte uint8_t for n follows) + case 0x79: // UTF-8 string (two-byte uint16_t for n follow) + case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) + case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) + case 0x7F: // UTF-8 string (indefinite length) + { + string_t s; + return get_cbor_string(s) && sax->string(s); + } + + // array (0x00..0x17 data items follow) + case 0x80: + case 0x81: + case 0x82: + case 0x83: + case 0x84: + case 0x85: + case 0x86: + case 0x87: + case 0x88: + case 0x89: + case 0x8A: + case 0x8B: + case 0x8C: + case 0x8D: + case 0x8E: + case 0x8F: + case 0x90: + case 0x91: + case 0x92: + case 0x93: + case 0x94: + case 0x95: + case 0x96: + case 0x97: + return get_cbor_array(static_cast(static_cast(current) & 0x1Fu), tag_handler); + + case 0x98: // array (one-byte uint8_t for n follows) + { + std::uint8_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast(len), tag_handler); + } + + case 0x99: // array (two-byte uint16_t for n follow) + { + std::uint16_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast(len), tag_handler); + } + + case 0x9A: // array (four-byte uint32_t for n follow) + { + std::uint32_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast(len), tag_handler); + } + + case 0x9B: // array (eight-byte uint64_t for n follow) + { + std::uint64_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_array(detail::conditional_static_cast(len), tag_handler); + } + + case 0x9F: // array (indefinite length) + return get_cbor_array(std::size_t(-1), tag_handler); + + // map (0x00..0x17 pairs of data items follow) + case 0xA0: + case 0xA1: + case 0xA2: + case 0xA3: + case 0xA4: + case 0xA5: + case 0xA6: + case 0xA7: + case 0xA8: + case 0xA9: + case 0xAA: + case 0xAB: + case 0xAC: + case 0xAD: + case 0xAE: + case 0xAF: + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: + case 0xB4: + case 0xB5: + case 0xB6: + case 0xB7: + return get_cbor_object(static_cast(static_cast(current) & 0x1Fu), tag_handler); + + case 0xB8: // map (one-byte uint8_t for n follows) + { + std::uint8_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast(len), tag_handler); + } + + case 0xB9: // map (two-byte uint16_t for n follow) + { + std::uint16_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast(len), tag_handler); + } + + case 0xBA: // map (four-byte uint32_t for n follow) + { + std::uint32_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast(len), tag_handler); + } + + case 0xBB: // map (eight-byte uint64_t for n follow) + { + std::uint64_t len{}; + return get_number(input_format_t::cbor, len) && get_cbor_object(detail::conditional_static_cast(len), tag_handler); + } + + case 0xBF: // map (indefinite length) + return get_cbor_object(std::size_t(-1), tag_handler); + + case 0xC6: // tagged item + case 0xC7: + case 0xC8: + case 0xC9: + case 0xCA: + case 0xCB: + case 0xCC: + case 0xCD: + case 0xCE: + case 0xCF: + case 0xD0: + case 0xD1: + case 0xD2: + case 0xD3: + case 0xD4: + case 0xD8: // tagged item (1 bytes follow) + case 0xD9: // tagged item (2 bytes follow) + case 0xDA: // tagged item (4 bytes follow) + case 0xDB: // tagged item (8 bytes follow) + { + switch (tag_handler) + { + case cbor_tag_handler_t::error: + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::cbor, "invalid byte: 0x" + last_token, "value"), BasicJsonType())); + } + + case cbor_tag_handler_t::ignore: + { + // ignore binary subtype + switch (current) + { + case 0xD8: + { + std::uint8_t subtype_to_ignore{}; + get_number(input_format_t::cbor, subtype_to_ignore); + break; + } + case 0xD9: + { + std::uint16_t subtype_to_ignore{}; + get_number(input_format_t::cbor, subtype_to_ignore); + break; + } + case 0xDA: + { + std::uint32_t subtype_to_ignore{}; + get_number(input_format_t::cbor, subtype_to_ignore); + break; + } + case 0xDB: + { + std::uint64_t subtype_to_ignore{}; + get_number(input_format_t::cbor, subtype_to_ignore); + break; + } + default: + break; + } + return parse_cbor_internal(true, tag_handler); + } + + case cbor_tag_handler_t::store: + { + binary_t b; + // use binary subtype and store in binary container + switch (current) + { + case 0xD8: + { + std::uint8_t subtype{}; + get_number(input_format_t::cbor, subtype); + b.set_subtype(detail::conditional_static_cast(subtype)); + break; + } + case 0xD9: + { + std::uint16_t subtype{}; + get_number(input_format_t::cbor, subtype); + b.set_subtype(detail::conditional_static_cast(subtype)); + break; + } + case 0xDA: + { + std::uint32_t subtype{}; + get_number(input_format_t::cbor, subtype); + b.set_subtype(detail::conditional_static_cast(subtype)); + break; + } + case 0xDB: + { + std::uint64_t subtype{}; + get_number(input_format_t::cbor, subtype); + b.set_subtype(detail::conditional_static_cast(subtype)); + break; + } + default: + return parse_cbor_internal(true, tag_handler); + } + get(); + return get_cbor_binary(b) && sax->binary(b); + } + + default: // LCOV_EXCL_LINE + JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE + return false; // LCOV_EXCL_LINE + } + } + + case 0xF4: // false + return sax->boolean(false); + + case 0xF5: // true + return sax->boolean(true); + + case 0xF6: // null + return sax->null(); + + case 0xF9: // Half-Precision Float (two-byte IEEE 754) + { + const auto byte1_raw = get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "number"))) + { + return false; + } + const auto byte2_raw = get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "number"))) + { + return false; + } + + const auto byte1 = static_cast(byte1_raw); + const auto byte2 = static_cast(byte2_raw); + + // code from RFC 7049, Appendix D, Figure 3: + // As half-precision floating-point numbers were only added + // to IEEE 754 in 2008, today's programming platforms often + // still only have limited support for them. It is very + // easy to include at least decoding support for them even + // without such support. An example of a small decoder for + // half-precision floating-point numbers in the C language + // is shown in Fig. 3. + const auto half = static_cast((byte1 << 8u) + byte2); + const double val = [&half] + { + const int exp = (half >> 10u) & 0x1Fu; + const unsigned int mant = half & 0x3FFu; + JSON_ASSERT(0 <= exp&& exp <= 32); + JSON_ASSERT(mant <= 1024); + switch (exp) + { + case 0: + return std::ldexp(mant, -24); + case 31: + return (mant == 0) + ? std::numeric_limits::infinity() + : std::numeric_limits::quiet_NaN(); + default: + return std::ldexp(mant + 1024, exp - 25); + } + }(); + return sax->number_float((half & 0x8000u) != 0 + ? static_cast(-val) + : static_cast(val), ""); + } + + case 0xFA: // Single-Precision Float (four-byte IEEE 754) + { + float number{}; + return get_number(input_format_t::cbor, number) && sax->number_float(static_cast(number), ""); + } + + case 0xFB: // Double-Precision Float (eight-byte IEEE 754) + { + double number{}; + return get_number(input_format_t::cbor, number) && sax->number_float(static_cast(number), ""); + } + + default: // anything else (0xFF is handled inside the other types) + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::cbor, "invalid byte: 0x" + last_token, "value"), BasicJsonType())); + } + } + } + + /*! + @brief reads a CBOR string + + This function first reads starting bytes to determine the expected + string length and then copies this number of bytes into a string. + Additionally, CBOR's strings with indefinite lengths are supported. + + @param[out] result created string + + @return whether string creation completed + */ + bool get_cbor_string(string_t& result) + { + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "string"))) + { + return false; + } + + switch (current) + { + // UTF-8 string (0x00..0x17 bytes follow) + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + { + return get_string(input_format_t::cbor, static_cast(current) & 0x1Fu, result); + } + + case 0x78: // UTF-8 string (one-byte uint8_t for n follows) + { + std::uint8_t len{}; + return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result); + } + + case 0x79: // UTF-8 string (two-byte uint16_t for n follow) + { + std::uint16_t len{}; + return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result); + } + + case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) + { + std::uint32_t len{}; + return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result); + } + + case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) + { + std::uint64_t len{}; + return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result); + } + + case 0x7F: // UTF-8 string (indefinite length) + { + while (get() != 0xFF) + { + string_t chunk; + if (!get_cbor_string(chunk)) + { + return false; + } + result.append(chunk); + } + return true; + } + + default: + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::cbor, "expected length specification (0x60-0x7B) or indefinite string type (0x7F); last byte: 0x" + last_token, "string"), BasicJsonType())); + } + } + } + + /*! + @brief reads a CBOR byte array + + This function first reads starting bytes to determine the expected + byte array length and then copies this number of bytes into the byte array. + Additionally, CBOR's byte arrays with indefinite lengths are supported. + + @param[out] result created byte array + + @return whether byte array creation completed + */ + bool get_cbor_binary(binary_t& result) + { + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "binary"))) + { + return false; + } + + switch (current) + { + // Binary data (0x00..0x17 bytes follow) + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4A: + case 0x4B: + case 0x4C: + case 0x4D: + case 0x4E: + case 0x4F: + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + { + return get_binary(input_format_t::cbor, static_cast(current) & 0x1Fu, result); + } + + case 0x58: // Binary data (one-byte uint8_t for n follows) + { + std::uint8_t len{}; + return get_number(input_format_t::cbor, len) && + get_binary(input_format_t::cbor, len, result); + } + + case 0x59: // Binary data (two-byte uint16_t for n follow) + { + std::uint16_t len{}; + return get_number(input_format_t::cbor, len) && + get_binary(input_format_t::cbor, len, result); + } + + case 0x5A: // Binary data (four-byte uint32_t for n follow) + { + std::uint32_t len{}; + return get_number(input_format_t::cbor, len) && + get_binary(input_format_t::cbor, len, result); + } + + case 0x5B: // Binary data (eight-byte uint64_t for n follow) + { + std::uint64_t len{}; + return get_number(input_format_t::cbor, len) && + get_binary(input_format_t::cbor, len, result); + } + + case 0x5F: // Binary data (indefinite length) + { + while (get() != 0xFF) + { + binary_t chunk; + if (!get_cbor_binary(chunk)) + { + return false; + } + result.insert(result.end(), chunk.begin(), chunk.end()); + } + return true; + } + + default: + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::cbor, "expected length specification (0x40-0x5B) or indefinite binary array type (0x5F); last byte: 0x" + last_token, "binary"), BasicJsonType())); + } + } + } + + /*! + @param[in] len the length of the array or std::size_t(-1) for an + array of indefinite size + @param[in] tag_handler how CBOR tags should be treated + @return whether array creation completed + */ + bool get_cbor_array(const std::size_t len, + const cbor_tag_handler_t tag_handler) + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(len))) + { + return false; + } + + if (len != std::size_t(-1)) + { + for (std::size_t i = 0; i < len; ++i) + { + if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler))) + { + return false; + } + } + } + else + { + while (get() != 0xFF) + { + if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(false, tag_handler))) + { + return false; + } + } + } + + return sax->end_array(); + } + + /*! + @param[in] len the length of the object or std::size_t(-1) for an + object of indefinite size + @param[in] tag_handler how CBOR tags should be treated + @return whether object creation completed + */ + bool get_cbor_object(const std::size_t len, + const cbor_tag_handler_t tag_handler) + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(len))) + { + return false; + } + + if (len != 0) + { + string_t key; + if (len != std::size_t(-1)) + { + for (std::size_t i = 0; i < len; ++i) + { + get(); + if (JSON_HEDLEY_UNLIKELY(!get_cbor_string(key) || !sax->key(key))) + { + return false; + } + + if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler))) + { + return false; + } + key.clear(); + } + } + else + { + while (get() != 0xFF) + { + if (JSON_HEDLEY_UNLIKELY(!get_cbor_string(key) || !sax->key(key))) + { + return false; + } + + if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler))) + { + return false; + } + key.clear(); + } + } + } + + return sax->end_object(); + } + + ///////////// + // MsgPack // + ///////////// + + /*! + @return whether a valid MessagePack value was passed to the SAX parser + */ + bool parse_msgpack_internal() + { + switch (get()) + { + // EOF + case std::char_traits::eof(): + return unexpect_eof(input_format_t::msgpack, "value"); + + // positive fixint + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0A: + case 0x0B: + case 0x0C: + case 0x0D: + case 0x0E: + case 0x0F: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1A: + case 0x1B: + case 0x1C: + case 0x1D: + case 0x1E: + case 0x1F: + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + case 0x29: + case 0x2A: + case 0x2B: + case 0x2C: + case 0x2D: + case 0x2E: + case 0x2F: + case 0x30: + case 0x31: + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + case 0x38: + case 0x39: + case 0x3A: + case 0x3B: + case 0x3C: + case 0x3D: + case 0x3E: + case 0x3F: + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4A: + case 0x4B: + case 0x4C: + case 0x4D: + case 0x4E: + case 0x4F: + case 0x50: + case 0x51: + case 0x52: + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + case 0x58: + case 0x59: + case 0x5A: + case 0x5B: + case 0x5C: + case 0x5D: + case 0x5E: + case 0x5F: + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + case 0x78: + case 0x79: + case 0x7A: + case 0x7B: + case 0x7C: + case 0x7D: + case 0x7E: + case 0x7F: + return sax->number_unsigned(static_cast(current)); + + // fixmap + case 0x80: + case 0x81: + case 0x82: + case 0x83: + case 0x84: + case 0x85: + case 0x86: + case 0x87: + case 0x88: + case 0x89: + case 0x8A: + case 0x8B: + case 0x8C: + case 0x8D: + case 0x8E: + case 0x8F: + return get_msgpack_object(static_cast(static_cast(current) & 0x0Fu)); + + // fixarray + case 0x90: + case 0x91: + case 0x92: + case 0x93: + case 0x94: + case 0x95: + case 0x96: + case 0x97: + case 0x98: + case 0x99: + case 0x9A: + case 0x9B: + case 0x9C: + case 0x9D: + case 0x9E: + case 0x9F: + return get_msgpack_array(static_cast(static_cast(current) & 0x0Fu)); + + // fixstr + case 0xA0: + case 0xA1: + case 0xA2: + case 0xA3: + case 0xA4: + case 0xA5: + case 0xA6: + case 0xA7: + case 0xA8: + case 0xA9: + case 0xAA: + case 0xAB: + case 0xAC: + case 0xAD: + case 0xAE: + case 0xAF: + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: + case 0xB4: + case 0xB5: + case 0xB6: + case 0xB7: + case 0xB8: + case 0xB9: + case 0xBA: + case 0xBB: + case 0xBC: + case 0xBD: + case 0xBE: + case 0xBF: + case 0xD9: // str 8 + case 0xDA: // str 16 + case 0xDB: // str 32 + { + string_t s; + return get_msgpack_string(s) && sax->string(s); + } + + case 0xC0: // nil + return sax->null(); + + case 0xC2: // false + return sax->boolean(false); + + case 0xC3: // true + return sax->boolean(true); + + case 0xC4: // bin 8 + case 0xC5: // bin 16 + case 0xC6: // bin 32 + case 0xC7: // ext 8 + case 0xC8: // ext 16 + case 0xC9: // ext 32 + case 0xD4: // fixext 1 + case 0xD5: // fixext 2 + case 0xD6: // fixext 4 + case 0xD7: // fixext 8 + case 0xD8: // fixext 16 + { + binary_t b; + return get_msgpack_binary(b) && sax->binary(b); + } + + case 0xCA: // float 32 + { + float number{}; + return get_number(input_format_t::msgpack, number) && sax->number_float(static_cast(number), ""); + } + + case 0xCB: // float 64 + { + double number{}; + return get_number(input_format_t::msgpack, number) && sax->number_float(static_cast(number), ""); + } + + case 0xCC: // uint 8 + { + std::uint8_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number); + } + + case 0xCD: // uint 16 + { + std::uint16_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number); + } + + case 0xCE: // uint 32 + { + std::uint32_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number); + } + + case 0xCF: // uint 64 + { + std::uint64_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number); + } + + case 0xD0: // int 8 + { + std::int8_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_integer(number); + } + + case 0xD1: // int 16 + { + std::int16_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_integer(number); + } + + case 0xD2: // int 32 + { + std::int32_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_integer(number); + } + + case 0xD3: // int 64 + { + std::int64_t number{}; + return get_number(input_format_t::msgpack, number) && sax->number_integer(number); + } + + case 0xDC: // array 16 + { + std::uint16_t len{}; + return get_number(input_format_t::msgpack, len) && get_msgpack_array(static_cast(len)); + } + + case 0xDD: // array 32 + { + std::uint32_t len{}; + return get_number(input_format_t::msgpack, len) && get_msgpack_array(static_cast(len)); + } + + case 0xDE: // map 16 + { + std::uint16_t len{}; + return get_number(input_format_t::msgpack, len) && get_msgpack_object(static_cast(len)); + } + + case 0xDF: // map 32 + { + std::uint32_t len{}; + return get_number(input_format_t::msgpack, len) && get_msgpack_object(static_cast(len)); + } + + // negative fixint + case 0xE0: + case 0xE1: + case 0xE2: + case 0xE3: + case 0xE4: + case 0xE5: + case 0xE6: + case 0xE7: + case 0xE8: + case 0xE9: + case 0xEA: + case 0xEB: + case 0xEC: + case 0xED: + case 0xEE: + case 0xEF: + case 0xF0: + case 0xF1: + case 0xF2: + case 0xF3: + case 0xF4: + case 0xF5: + case 0xF6: + case 0xF7: + case 0xF8: + case 0xF9: + case 0xFA: + case 0xFB: + case 0xFC: + case 0xFD: + case 0xFE: + case 0xFF: + return sax->number_integer(static_cast(current)); + + default: // anything else + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::msgpack, "invalid byte: 0x" + last_token, "value"), BasicJsonType())); + } + } + } + + /*! + @brief reads a MessagePack string + + This function first reads starting bytes to determine the expected + string length and then copies this number of bytes into a string. + + @param[out] result created string + + @return whether string creation completed + */ + bool get_msgpack_string(string_t& result) + { + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::msgpack, "string"))) + { + return false; + } + + switch (current) + { + // fixstr + case 0xA0: + case 0xA1: + case 0xA2: + case 0xA3: + case 0xA4: + case 0xA5: + case 0xA6: + case 0xA7: + case 0xA8: + case 0xA9: + case 0xAA: + case 0xAB: + case 0xAC: + case 0xAD: + case 0xAE: + case 0xAF: + case 0xB0: + case 0xB1: + case 0xB2: + case 0xB3: + case 0xB4: + case 0xB5: + case 0xB6: + case 0xB7: + case 0xB8: + case 0xB9: + case 0xBA: + case 0xBB: + case 0xBC: + case 0xBD: + case 0xBE: + case 0xBF: + { + return get_string(input_format_t::msgpack, static_cast(current) & 0x1Fu, result); + } + + case 0xD9: // str 8 + { + std::uint8_t len{}; + return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result); + } + + case 0xDA: // str 16 + { + std::uint16_t len{}; + return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result); + } + + case 0xDB: // str 32 + { + std::uint32_t len{}; + return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result); + } + + default: + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::msgpack, "expected length specification (0xA0-0xBF, 0xD9-0xDB); last byte: 0x" + last_token, "string"), BasicJsonType())); + } + } + } + + /*! + @brief reads a MessagePack byte array + + This function first reads starting bytes to determine the expected + byte array length and then copies this number of bytes into a byte array. + + @param[out] result created byte array + + @return whether byte array creation completed + */ + bool get_msgpack_binary(binary_t& result) + { + // helper function to set the subtype + auto assign_and_return_true = [&result](std::int8_t subtype) + { + result.set_subtype(static_cast(subtype)); + return true; + }; + + switch (current) + { + case 0xC4: // bin 8 + { + std::uint8_t len{}; + return get_number(input_format_t::msgpack, len) && + get_binary(input_format_t::msgpack, len, result); + } + + case 0xC5: // bin 16 + { + std::uint16_t len{}; + return get_number(input_format_t::msgpack, len) && + get_binary(input_format_t::msgpack, len, result); + } + + case 0xC6: // bin 32 + { + std::uint32_t len{}; + return get_number(input_format_t::msgpack, len) && + get_binary(input_format_t::msgpack, len, result); + } + + case 0xC7: // ext 8 + { + std::uint8_t len{}; + std::int8_t subtype{}; + return get_number(input_format_t::msgpack, len) && + get_number(input_format_t::msgpack, subtype) && + get_binary(input_format_t::msgpack, len, result) && + assign_and_return_true(subtype); + } + + case 0xC8: // ext 16 + { + std::uint16_t len{}; + std::int8_t subtype{}; + return get_number(input_format_t::msgpack, len) && + get_number(input_format_t::msgpack, subtype) && + get_binary(input_format_t::msgpack, len, result) && + assign_and_return_true(subtype); + } + + case 0xC9: // ext 32 + { + std::uint32_t len{}; + std::int8_t subtype{}; + return get_number(input_format_t::msgpack, len) && + get_number(input_format_t::msgpack, subtype) && + get_binary(input_format_t::msgpack, len, result) && + assign_and_return_true(subtype); + } + + case 0xD4: // fixext 1 + { + std::int8_t subtype{}; + return get_number(input_format_t::msgpack, subtype) && + get_binary(input_format_t::msgpack, 1, result) && + assign_and_return_true(subtype); + } + + case 0xD5: // fixext 2 + { + std::int8_t subtype{}; + return get_number(input_format_t::msgpack, subtype) && + get_binary(input_format_t::msgpack, 2, result) && + assign_and_return_true(subtype); + } + + case 0xD6: // fixext 4 + { + std::int8_t subtype{}; + return get_number(input_format_t::msgpack, subtype) && + get_binary(input_format_t::msgpack, 4, result) && + assign_and_return_true(subtype); + } + + case 0xD7: // fixext 8 + { + std::int8_t subtype{}; + return get_number(input_format_t::msgpack, subtype) && + get_binary(input_format_t::msgpack, 8, result) && + assign_and_return_true(subtype); + } + + case 0xD8: // fixext 16 + { + std::int8_t subtype{}; + return get_number(input_format_t::msgpack, subtype) && + get_binary(input_format_t::msgpack, 16, result) && + assign_and_return_true(subtype); + } + + default: // LCOV_EXCL_LINE + return false; // LCOV_EXCL_LINE + } + } + + /*! + @param[in] len the length of the array + @return whether array creation completed + */ + bool get_msgpack_array(const std::size_t len) + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(len))) + { + return false; + } + + for (std::size_t i = 0; i < len; ++i) + { + if (JSON_HEDLEY_UNLIKELY(!parse_msgpack_internal())) + { + return false; + } + } + + return sax->end_array(); + } + + /*! + @param[in] len the length of the object + @return whether object creation completed + */ + bool get_msgpack_object(const std::size_t len) + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(len))) + { + return false; + } + + string_t key; + for (std::size_t i = 0; i < len; ++i) + { + get(); + if (JSON_HEDLEY_UNLIKELY(!get_msgpack_string(key) || !sax->key(key))) + { + return false; + } + + if (JSON_HEDLEY_UNLIKELY(!parse_msgpack_internal())) + { + return false; + } + key.clear(); + } + + return sax->end_object(); + } + + //////////// + // UBJSON // + //////////// + + /*! + @param[in] get_char whether a new character should be retrieved from the + input (true, default) or whether the last read + character should be considered instead + + @return whether a valid UBJSON value was passed to the SAX parser + */ + bool parse_ubjson_internal(const bool get_char = true) + { + return get_ubjson_value(get_char ? get_ignore_noop() : current); + } + + /*! + @brief reads a UBJSON string + + This function is either called after reading the 'S' byte explicitly + indicating a string, or in case of an object key where the 'S' byte can be + left out. + + @param[out] result created string + @param[in] get_char whether a new character should be retrieved from the + input (true, default) or whether the last read + character should be considered instead + + @return whether string creation completed + */ + bool get_ubjson_string(string_t& result, const bool get_char = true) + { + if (get_char) + { + get(); // TODO(niels): may we ignore N here? + } + + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::ubjson, "value"))) + { + return false; + } + + switch (current) + { + case 'U': + { + std::uint8_t len{}; + return get_number(input_format_t::ubjson, len) && get_string(input_format_t::ubjson, len, result); + } + + case 'i': + { + std::int8_t len{}; + return get_number(input_format_t::ubjson, len) && get_string(input_format_t::ubjson, len, result); + } + + case 'I': + { + std::int16_t len{}; + return get_number(input_format_t::ubjson, len) && get_string(input_format_t::ubjson, len, result); + } + + case 'l': + { + std::int32_t len{}; + return get_number(input_format_t::ubjson, len) && get_string(input_format_t::ubjson, len, result); + } + + case 'L': + { + std::int64_t len{}; + return get_number(input_format_t::ubjson, len) && get_string(input_format_t::ubjson, len, result); + } + + default: + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, "expected length type specification (U, i, I, l, L); last byte: 0x" + last_token, "string"), BasicJsonType())); + } + } + + /*! + @param[out] result determined size + @return whether size determination completed + */ + bool get_ubjson_size_value(std::size_t& result) + { + switch (get_ignore_noop()) + { + case 'U': + { + std::uint8_t number{}; + if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::ubjson, number))) + { + return false; + } + result = static_cast(number); + return true; + } + + case 'i': + { + std::int8_t number{}; + if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::ubjson, number))) + { + return false; + } + result = static_cast(number); // NOLINT(bugprone-signed-char-misuse,cert-str34-c): number is not a char + return true; + } + + case 'I': + { + std::int16_t number{}; + if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::ubjson, number))) + { + return false; + } + result = static_cast(number); + return true; + } + + case 'l': + { + std::int32_t number{}; + if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::ubjson, number))) + { + return false; + } + result = static_cast(number); + return true; + } + + case 'L': + { + std::int64_t number{}; + if (JSON_HEDLEY_UNLIKELY(!get_number(input_format_t::ubjson, number))) + { + return false; + } + result = static_cast(number); + return true; + } + + default: + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, "expected length type specification (U, i, I, l, L) after '#'; last byte: 0x" + last_token, "size"), BasicJsonType())); + } + } + } + + /*! + @brief determine the type and size for a container + + In the optimized UBJSON format, a type and a size can be provided to allow + for a more compact representation. + + @param[out] result pair of the size and the type + + @return whether pair creation completed + */ + bool get_ubjson_size_type(std::pair& result) + { + result.first = string_t::npos; // size + result.second = 0; // type + + get_ignore_noop(); + + if (current == '$') + { + result.second = get(); // must not ignore 'N', because 'N' maybe the type + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::ubjson, "type"))) + { + return false; + } + + get_ignore_noop(); + if (JSON_HEDLEY_UNLIKELY(current != '#')) + { + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::ubjson, "value"))) + { + return false; + } + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::ubjson, "expected '#' after type information; last byte: 0x" + last_token, "size"), BasicJsonType())); + } + + return get_ubjson_size_value(result.first); + } + + if (current == '#') + { + return get_ubjson_size_value(result.first); + } + + return true; + } + + /*! + @param prefix the previously read or set type prefix + @return whether value creation completed + */ + bool get_ubjson_value(const char_int_type prefix) + { + switch (prefix) + { + case std::char_traits::eof(): // EOF + return unexpect_eof(input_format_t::ubjson, "value"); + + case 'T': // true + return sax->boolean(true); + case 'F': // false + return sax->boolean(false); + + case 'Z': // null + return sax->null(); + + case 'U': + { + std::uint8_t number{}; + return get_number(input_format_t::ubjson, number) && sax->number_unsigned(number); + } + + case 'i': + { + std::int8_t number{}; + return get_number(input_format_t::ubjson, number) && sax->number_integer(number); + } + + case 'I': + { + std::int16_t number{}; + return get_number(input_format_t::ubjson, number) && sax->number_integer(number); + } + + case 'l': + { + std::int32_t number{}; + return get_number(input_format_t::ubjson, number) && sax->number_integer(number); + } + + case 'L': + { + std::int64_t number{}; + return get_number(input_format_t::ubjson, number) && sax->number_integer(number); + } + + case 'd': + { + float number{}; + return get_number(input_format_t::ubjson, number) && sax->number_float(static_cast(number), ""); + } + + case 'D': + { + double number{}; + return get_number(input_format_t::ubjson, number) && sax->number_float(static_cast(number), ""); + } + + case 'H': + { + return get_ubjson_high_precision_number(); + } + + case 'C': // char + { + get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::ubjson, "char"))) + { + return false; + } + if (JSON_HEDLEY_UNLIKELY(current > 127)) + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, "byte after 'C' must be in range 0x00..0x7F; last byte: 0x" + last_token, "char"), BasicJsonType())); + } + string_t s(1, static_cast(current)); + return sax->string(s); + } + + case 'S': // string + { + string_t s; + return get_ubjson_string(s) && sax->string(s); + } + + case '[': // array + return get_ubjson_array(); + + case '{': // object + return get_ubjson_object(); + + default: // anything else + { + auto last_token = get_token_string(); + return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::ubjson, "invalid byte: 0x" + last_token, "value"), BasicJsonType())); + } + } + } + + /*! + @return whether array creation completed + */ + bool get_ubjson_array() + { + std::pair size_and_type; + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type))) + { + return false; + } + + if (size_and_type.first != string_t::npos) + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(size_and_type.first))) + { + return false; + } + + if (size_and_type.second != 0) + { + if (size_and_type.second != 'N') + { + for (std::size_t i = 0; i < size_and_type.first; ++i) + { + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second))) + { + return false; + } + } + } + } + else + { + for (std::size_t i = 0; i < size_and_type.first; ++i) + { + if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal())) + { + return false; + } + } + } + } + else + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(std::size_t(-1)))) + { + return false; + } + + while (current != ']') + { + if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal(false))) + { + return false; + } + get_ignore_noop(); + } + } + + return sax->end_array(); + } + + /*! + @return whether object creation completed + */ + bool get_ubjson_object() + { + std::pair size_and_type; + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type))) + { + return false; + } + + string_t key; + if (size_and_type.first != string_t::npos) + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(size_and_type.first))) + { + return false; + } + + if (size_and_type.second != 0) + { + for (std::size_t i = 0; i < size_and_type.first; ++i) + { + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key) || !sax->key(key))) + { + return false; + } + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second))) + { + return false; + } + key.clear(); + } + } + else + { + for (std::size_t i = 0; i < size_and_type.first; ++i) + { + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key) || !sax->key(key))) + { + return false; + } + if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal())) + { + return false; + } + key.clear(); + } + } + } + else + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(std::size_t(-1)))) + { + return false; + } + + while (current != '}') + { + if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key, false) || !sax->key(key))) + { + return false; + } + if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal())) + { + return false; + } + get_ignore_noop(); + key.clear(); + } + } + + return sax->end_object(); + } + + // Note, no reader for UBJSON binary types is implemented because they do + // not exist + + bool get_ubjson_high_precision_number() + { + // get size of following number string + std::size_t size{}; + auto res = get_ubjson_size_value(size); + if (JSON_HEDLEY_UNLIKELY(!res)) + { + return res; + } + + // get number string + std::vector number_vector; + for (std::size_t i = 0; i < size; ++i) + { + get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::ubjson, "number"))) + { + return false; + } + number_vector.push_back(static_cast(current)); + } + + // parse number string + using ia_type = decltype(detail::input_adapter(number_vector)); + auto number_lexer = detail::lexer(detail::input_adapter(number_vector), false); + const auto result_number = number_lexer.scan(); + const auto number_string = number_lexer.get_token_string(); + const auto result_remainder = number_lexer.scan(); + + using token_type = typename detail::lexer_base::token_type; + + if (JSON_HEDLEY_UNLIKELY(result_remainder != token_type::end_of_input)) + { + return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read, exception_message(input_format_t::ubjson, "invalid number text: " + number_lexer.get_token_string(), "high-precision number"), BasicJsonType())); + } + + switch (result_number) + { + case token_type::value_integer: + return sax->number_integer(number_lexer.get_number_integer()); + case token_type::value_unsigned: + return sax->number_unsigned(number_lexer.get_number_unsigned()); + case token_type::value_float: + return sax->number_float(number_lexer.get_number_float(), std::move(number_string)); + case token_type::uninitialized: + case token_type::literal_true: + case token_type::literal_false: + case token_type::literal_null: + case token_type::value_string: + case token_type::begin_array: + case token_type::begin_object: + case token_type::end_array: + case token_type::end_object: + case token_type::name_separator: + case token_type::value_separator: + case token_type::parse_error: + case token_type::end_of_input: + case token_type::literal_or_value: + default: + return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read, exception_message(input_format_t::ubjson, "invalid number text: " + number_lexer.get_token_string(), "high-precision number"), BasicJsonType())); + } + } + + /////////////////////// + // Utility functions // + /////////////////////// + + /*! + @brief get next character from the input + + This function provides the interface to the used input adapter. It does + not throw in case the input reached EOF, but returns a -'ve valued + `std::char_traits::eof()` in that case. + + @return character read from the input + */ + char_int_type get() + { + ++chars_read; + return current = ia.get_character(); + } + + /*! + @return character read from the input after ignoring all 'N' entries + */ + char_int_type get_ignore_noop() + { + do + { + get(); + } + while (current == 'N'); + + return current; + } + + /* + @brief read a number from the input + + @tparam NumberType the type of the number + @param[in] format the current format (for diagnostics) + @param[out] result number of type @a NumberType + + @return whether conversion completed + + @note This function needs to respect the system's endianess, because + bytes in CBOR, MessagePack, and UBJSON are stored in network order + (big endian) and therefore need reordering on little endian systems. + */ + template + bool get_number(const input_format_t format, NumberType& result) + { + // step 1: read input into array with system's byte order + std::array vec{}; + for (std::size_t i = 0; i < sizeof(NumberType); ++i) + { + get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "number"))) + { + return false; + } + + // reverse byte order prior to conversion if necessary + if (is_little_endian != InputIsLittleEndian) + { + vec[sizeof(NumberType) - i - 1] = static_cast(current); + } + else + { + vec[i] = static_cast(current); // LCOV_EXCL_LINE + } + } + + // step 2: convert array into number of type T and return + std::memcpy(&result, vec.data(), sizeof(NumberType)); + return true; + } + + /*! + @brief create a string by reading characters from the input + + @tparam NumberType the type of the number + @param[in] format the current format (for diagnostics) + @param[in] len number of characters to read + @param[out] result string created by reading @a len bytes + + @return whether string creation completed + + @note We can not reserve @a len bytes for the result, because @a len + may be too large. Usually, @ref unexpect_eof() detects the end of + the input before we run out of string memory. + */ + template + bool get_string(const input_format_t format, + const NumberType len, + string_t& result) + { + bool success = true; + for (NumberType i = 0; i < len; i++) + { + get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "string"))) + { + success = false; + break; + } + result.push_back(static_cast(current)); + } + return success; + } + + /*! + @brief create a byte array by reading bytes from the input + + @tparam NumberType the type of the number + @param[in] format the current format (for diagnostics) + @param[in] len number of bytes to read + @param[out] result byte array created by reading @a len bytes + + @return whether byte array creation completed + + @note We can not reserve @a len bytes for the result, because @a len + may be too large. Usually, @ref unexpect_eof() detects the end of + the input before we run out of memory. + */ + template + bool get_binary(const input_format_t format, + const NumberType len, + binary_t& result) + { + bool success = true; + for (NumberType i = 0; i < len; i++) + { + get(); + if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "binary"))) + { + success = false; + break; + } + result.push_back(static_cast(current)); + } + return success; + } + + /*! + @param[in] format the current format (for diagnostics) + @param[in] context further context information (for diagnostics) + @return whether the last read character is not EOF + */ + JSON_HEDLEY_NON_NULL(3) + bool unexpect_eof(const input_format_t format, const char* context) const + { + if (JSON_HEDLEY_UNLIKELY(current == std::char_traits::eof())) + { + return sax->parse_error(chars_read, "", + parse_error::create(110, chars_read, exception_message(format, "unexpected end of input", context), BasicJsonType())); + } + return true; + } + + /*! + @return a string representation of the last read byte + */ + std::string get_token_string() const + { + std::array cr{{}}; + (std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast(current)); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) + return std::string{cr.data()}; + } + + /*! + @param[in] format the current format + @param[in] detail a detailed error message + @param[in] context further context information + @return a message string to use in the parse_error exceptions + */ + std::string exception_message(const input_format_t format, + const std::string& detail, + const std::string& context) const + { + std::string error_msg = "syntax error while parsing "; + + switch (format) + { + case input_format_t::cbor: + error_msg += "CBOR"; + break; + + case input_format_t::msgpack: + error_msg += "MessagePack"; + break; + + case input_format_t::ubjson: + error_msg += "UBJSON"; + break; + + case input_format_t::bson: + error_msg += "BSON"; + break; + + case input_format_t::json: // LCOV_EXCL_LINE + default: // LCOV_EXCL_LINE + JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE + } + + return error_msg + " " + context + ": " + detail; + } + + private: + /// input adapter + InputAdapterType ia; + + /// the current character + char_int_type current = std::char_traits::eof(); + + /// the number of characters read + std::size_t chars_read = 0; + + /// whether we can assume little endianess + const bool is_little_endian = little_endianess(); + + /// the SAX parser + json_sax_t* sax = nullptr; +}; +} // namespace detail +} // namespace nlohmann + +// #include + +// #include + +// #include + + +#include // isfinite +#include // uint8_t +#include // function +#include // string +#include // move +#include // vector + +// #include + +// #include + +// #include + +// #include + +// #include + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +//////////// +// parser // +//////////// + +enum class parse_event_t : std::uint8_t +{ + /// the parser read `{` and started to process a JSON object + object_start, + /// the parser read `}` and finished processing a JSON object + object_end, + /// the parser read `[` and started to process a JSON array + array_start, + /// the parser read `]` and finished processing a JSON array + array_end, + /// the parser read a key of a value in an object + key, + /// the parser finished reading a JSON value + value +}; + +template +using parser_callback_t = + std::function; + +/*! +@brief syntax analysis + +This class implements a recursive descent parser. +*/ +template +class parser +{ + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; + using string_t = typename BasicJsonType::string_t; + using lexer_t = lexer; + using token_type = typename lexer_t::token_type; + + public: + /// a parser reading from an input adapter + explicit parser(InputAdapterType&& adapter, + const parser_callback_t cb = nullptr, + const bool allow_exceptions_ = true, + const bool skip_comments = false) + : callback(cb) + , m_lexer(std::move(adapter), skip_comments) + , allow_exceptions(allow_exceptions_) + { + // read first token + get_token(); + } + + /*! + @brief public parser interface + + @param[in] strict whether to expect the last token to be EOF + @param[in,out] result parsed JSON value + + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + */ + void parse(const bool strict, BasicJsonType& result) + { + if (callback) + { + json_sax_dom_callback_parser sdp(result, callback, allow_exceptions); + sax_parse_internal(&sdp); + + // in strict mode, input must be completely read + if (strict && (get_token() != token_type::end_of_input)) + { + sdp.parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), + exception_message(token_type::end_of_input, "value"), BasicJsonType())); + } + + // in case of an error, return discarded value + if (sdp.is_errored()) + { + result = value_t::discarded; + return; + } + + // set top-level value to null if it was discarded by the callback + // function + if (result.is_discarded()) + { + result = nullptr; + } + } + else + { + json_sax_dom_parser sdp(result, allow_exceptions); + sax_parse_internal(&sdp); + + // in strict mode, input must be completely read + if (strict && (get_token() != token_type::end_of_input)) + { + sdp.parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input, "value"), BasicJsonType())); + } + + // in case of an error, return discarded value + if (sdp.is_errored()) + { + result = value_t::discarded; + return; + } + } + + result.assert_invariant(); + } + + /*! + @brief public accept interface + + @param[in] strict whether to expect the last token to be EOF + @return whether the input is a proper JSON text + */ + bool accept(const bool strict = true) + { + json_sax_acceptor sax_acceptor; + return sax_parse(&sax_acceptor, strict); + } + + template + JSON_HEDLEY_NON_NULL(2) + bool sax_parse(SAX* sax, const bool strict = true) + { + (void)detail::is_sax_static_asserts {}; + const bool result = sax_parse_internal(sax); + + // strict mode: next byte must be EOF + if (result && strict && (get_token() != token_type::end_of_input)) + { + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input, "value"), BasicJsonType())); + } + + return result; + } + + private: + template + JSON_HEDLEY_NON_NULL(2) + bool sax_parse_internal(SAX* sax) + { + // stack to remember the hierarchy of structured values we are parsing + // true = array; false = object + std::vector states; + // value to avoid a goto (see comment where set to true) + bool skip_to_state_evaluation = false; + + while (true) + { + if (!skip_to_state_evaluation) + { + // invariant: get_token() was called before each iteration + switch (last_token) + { + case token_type::begin_object: + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_object(std::size_t(-1)))) + { + return false; + } + + // closing } -> we are done + if (get_token() == token_type::end_object) + { + if (JSON_HEDLEY_UNLIKELY(!sax->end_object())) + { + return false; + } + break; + } + + // parse key + if (JSON_HEDLEY_UNLIKELY(last_token != token_type::value_string)) + { + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string, "object key"), BasicJsonType())); + } + if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string()))) + { + return false; + } + + // parse separator (:) + if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator)) + { + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator, "object separator"), BasicJsonType())); + } + + // remember we are now inside an object + states.push_back(false); + + // parse values + get_token(); + continue; + } + + case token_type::begin_array: + { + if (JSON_HEDLEY_UNLIKELY(!sax->start_array(std::size_t(-1)))) + { + return false; + } + + // closing ] -> we are done + if (get_token() == token_type::end_array) + { + if (JSON_HEDLEY_UNLIKELY(!sax->end_array())) + { + return false; + } + break; + } + + // remember we are now inside an array + states.push_back(true); + + // parse values (no need to call get_token) + continue; + } + + case token_type::value_float: + { + const auto res = m_lexer.get_number_float(); + + if (JSON_HEDLEY_UNLIKELY(!std::isfinite(res))) + { + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + out_of_range::create(406, "number overflow parsing '" + m_lexer.get_token_string() + "'", BasicJsonType())); + } + + if (JSON_HEDLEY_UNLIKELY(!sax->number_float(res, m_lexer.get_string()))) + { + return false; + } + + break; + } + + case token_type::literal_false: + { + if (JSON_HEDLEY_UNLIKELY(!sax->boolean(false))) + { + return false; + } + break; + } + + case token_type::literal_null: + { + if (JSON_HEDLEY_UNLIKELY(!sax->null())) + { + return false; + } + break; + } + + case token_type::literal_true: + { + if (JSON_HEDLEY_UNLIKELY(!sax->boolean(true))) + { + return false; + } + break; + } + + case token_type::value_integer: + { + if (JSON_HEDLEY_UNLIKELY(!sax->number_integer(m_lexer.get_number_integer()))) + { + return false; + } + break; + } + + case token_type::value_string: + { + if (JSON_HEDLEY_UNLIKELY(!sax->string(m_lexer.get_string()))) + { + return false; + } + break; + } + + case token_type::value_unsigned: + { + if (JSON_HEDLEY_UNLIKELY(!sax->number_unsigned(m_lexer.get_number_unsigned()))) + { + return false; + } + break; + } + + case token_type::parse_error: + { + // using "uninitialized" to avoid "expected" message + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), exception_message(token_type::uninitialized, "value"), BasicJsonType())); + } + + case token_type::uninitialized: + case token_type::end_array: + case token_type::end_object: + case token_type::name_separator: + case token_type::value_separator: + case token_type::end_of_input: + case token_type::literal_or_value: + default: // the last token was unexpected + { + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), exception_message(token_type::literal_or_value, "value"), BasicJsonType())); + } + } + } + else + { + skip_to_state_evaluation = false; + } + + // we reached this line after we successfully parsed a value + if (states.empty()) + { + // empty stack: we reached the end of the hierarchy: done + return true; + } + + if (states.back()) // array + { + // comma -> next value + if (get_token() == token_type::value_separator) + { + // parse a new value + get_token(); + continue; + } + + // closing ] + if (JSON_HEDLEY_LIKELY(last_token == token_type::end_array)) + { + if (JSON_HEDLEY_UNLIKELY(!sax->end_array())) + { + return false; + } + + // We are done with this array. Before we can parse a + // new value, we need to evaluate the new state first. + // By setting skip_to_state_evaluation to false, we + // are effectively jumping to the beginning of this if. + JSON_ASSERT(!states.empty()); + states.pop_back(); + skip_to_state_evaluation = true; + continue; + } + + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_array, "array"), BasicJsonType())); + } + + // states.back() is false -> object + + // comma -> next value + if (get_token() == token_type::value_separator) + { + // parse key + if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::value_string)) + { + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string, "object key"), BasicJsonType())); + } + + if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string()))) + { + return false; + } + + // parse separator (:) + if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator)) + { + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator, "object separator"), BasicJsonType())); + } + + // parse values + get_token(); + continue; + } + + // closing } + if (JSON_HEDLEY_LIKELY(last_token == token_type::end_object)) + { + if (JSON_HEDLEY_UNLIKELY(!sax->end_object())) + { + return false; + } + + // We are done with this object. Before we can parse a + // new value, we need to evaluate the new state first. + // By setting skip_to_state_evaluation to false, we + // are effectively jumping to the beginning of this if. + JSON_ASSERT(!states.empty()); + states.pop_back(); + skip_to_state_evaluation = true; + continue; + } + + return sax->parse_error(m_lexer.get_position(), + m_lexer.get_token_string(), + parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_object, "object"), BasicJsonType())); + } + } + + /// get next token from lexer + token_type get_token() + { + return last_token = m_lexer.scan(); + } + + std::string exception_message(const token_type expected, const std::string& context) + { + std::string error_msg = "syntax error "; + + if (!context.empty()) + { + error_msg += "while parsing " + context + " "; + } + + error_msg += "- "; + + if (last_token == token_type::parse_error) + { + error_msg += std::string(m_lexer.get_error_message()) + "; last read: '" + + m_lexer.get_token_string() + "'"; + } + else + { + error_msg += "unexpected " + std::string(lexer_t::token_type_name(last_token)); + } + + if (expected != token_type::uninitialized) + { + error_msg += "; expected " + std::string(lexer_t::token_type_name(expected)); + } + + return error_msg; + } + + private: + /// callback function + const parser_callback_t callback = nullptr; + /// the type of the last read token + token_type last_token = token_type::uninitialized; + /// the lexer + lexer_t m_lexer; + /// whether to throw exceptions in case of errors + const bool allow_exceptions = true; +}; + +} // namespace detail +} // namespace nlohmann + +// #include + + +// #include + + +#include // ptrdiff_t +#include // numeric_limits + +// #include + + +namespace nlohmann +{ +namespace detail +{ +/* +@brief an iterator for primitive JSON types + +This class models an iterator for primitive JSON types (boolean, number, +string). It's only purpose is to allow the iterator/const_iterator classes +to "iterate" over primitive values. Internally, the iterator is modeled by +a `difference_type` variable. Value begin_value (`0`) models the begin, +end_value (`1`) models past the end. +*/ +class primitive_iterator_t +{ + private: + using difference_type = std::ptrdiff_t; + static constexpr difference_type begin_value = 0; + static constexpr difference_type end_value = begin_value + 1; + + JSON_PRIVATE_UNLESS_TESTED: + /// iterator as signed integer type + difference_type m_it = (std::numeric_limits::min)(); + + public: + constexpr difference_type get_value() const noexcept + { + return m_it; + } + + /// set iterator to a defined beginning + void set_begin() noexcept + { + m_it = begin_value; + } + + /// set iterator to a defined past the end + void set_end() noexcept + { + m_it = end_value; + } + + /// return whether the iterator can be dereferenced + constexpr bool is_begin() const noexcept + { + return m_it == begin_value; + } + + /// return whether the iterator is at end + constexpr bool is_end() const noexcept + { + return m_it == end_value; + } + + friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept + { + return lhs.m_it == rhs.m_it; + } + + friend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept + { + return lhs.m_it < rhs.m_it; + } + + primitive_iterator_t operator+(difference_type n) noexcept + { + auto result = *this; + result += n; + return result; + } + + friend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept + { + return lhs.m_it - rhs.m_it; + } + + primitive_iterator_t& operator++() noexcept + { + ++m_it; + return *this; + } + + primitive_iterator_t const operator++(int) noexcept // NOLINT(readability-const-return-type) + { + auto result = *this; + ++m_it; + return result; + } + + primitive_iterator_t& operator--() noexcept + { + --m_it; + return *this; + } + + primitive_iterator_t const operator--(int) noexcept // NOLINT(readability-const-return-type) + { + auto result = *this; + --m_it; + return result; + } + + primitive_iterator_t& operator+=(difference_type n) noexcept + { + m_it += n; + return *this; + } + + primitive_iterator_t& operator-=(difference_type n) noexcept + { + m_it -= n; + return *this; + } +}; +} // namespace detail +} // namespace nlohmann + + +namespace nlohmann +{ +namespace detail +{ +/*! +@brief an iterator value + +@note This structure could easily be a union, but MSVC currently does not allow +unions members with complex constructors, see https://github.com/nlohmann/json/pull/105. +*/ +template struct internal_iterator +{ + /// iterator for JSON objects + typename BasicJsonType::object_t::iterator object_iterator {}; + /// iterator for JSON arrays + typename BasicJsonType::array_t::iterator array_iterator {}; + /// generic iterator for all other types + primitive_iterator_t primitive_iterator {}; +}; +} // namespace detail +} // namespace nlohmann + +// #include + + +#include // iterator, random_access_iterator_tag, bidirectional_iterator_tag, advance, next +#include // conditional, is_const, remove_const + +// #include + +// #include + +// #include + +// #include + +// #include + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +// forward declare, to be able to friend it later on +template class iteration_proxy; +template class iteration_proxy_value; + +/*! +@brief a template for a bidirectional iterator for the @ref basic_json class +This class implements a both iterators (iterator and const_iterator) for the +@ref basic_json class. +@note An iterator is called *initialized* when a pointer to a JSON value has + been set (e.g., by a constructor or a copy assignment). If the iterator is + default-constructed, it is *uninitialized* and most methods are undefined. + **The library uses assertions to detect calls on uninitialized iterators.** +@requirement The class satisfies the following concept requirements: +- +[BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator): + The iterator that can be moved can be moved in both directions (i.e. + incremented and decremented). +@since version 1.0.0, simplified in version 2.0.9, change to bidirectional + iterators in version 3.0.0 (see https://github.com/nlohmann/json/issues/593) +*/ +template +class iter_impl +{ + /// the iterator with BasicJsonType of different const-ness + using other_iter_impl = iter_impl::value, typename std::remove_const::type, const BasicJsonType>::type>; + /// allow basic_json to access private members + friend other_iter_impl; + friend BasicJsonType; + friend iteration_proxy; + friend iteration_proxy_value; + + using object_t = typename BasicJsonType::object_t; + using array_t = typename BasicJsonType::array_t; + // make sure BasicJsonType is basic_json or const basic_json + static_assert(is_basic_json::type>::value, + "iter_impl only accepts (const) basic_json"); + + public: + + /// The std::iterator class template (used as a base class to provide typedefs) is deprecated in C++17. + /// The C++ Standard has never required user-defined iterators to derive from std::iterator. + /// A user-defined iterator should provide publicly accessible typedefs named + /// iterator_category, value_type, difference_type, pointer, and reference. + /// Note that value_type is required to be non-const, even for constant iterators. + using iterator_category = std::bidirectional_iterator_tag; + + /// the type of the values when the iterator is dereferenced + using value_type = typename BasicJsonType::value_type; + /// a type to represent differences between iterators + using difference_type = typename BasicJsonType::difference_type; + /// defines a pointer to the type iterated over (value_type) + using pointer = typename std::conditional::value, + typename BasicJsonType::const_pointer, + typename BasicJsonType::pointer>::type; + /// defines a reference to the type iterated over (value_type) + using reference = + typename std::conditional::value, + typename BasicJsonType::const_reference, + typename BasicJsonType::reference>::type; + + iter_impl() = default; + ~iter_impl() = default; + iter_impl(iter_impl&&) noexcept = default; + iter_impl& operator=(iter_impl&&) noexcept = default; + + /*! + @brief constructor for a given JSON instance + @param[in] object pointer to a JSON object for this iterator + @pre object != nullptr + @post The iterator is initialized; i.e. `m_object != nullptr`. + */ + explicit iter_impl(pointer object) noexcept : m_object(object) + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + m_it.object_iterator = typename object_t::iterator(); + break; + } + + case value_t::array: + { + m_it.array_iterator = typename array_t::iterator(); + break; + } + + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + { + m_it.primitive_iterator = primitive_iterator_t(); + break; + } + } + } + + /*! + @note The conventional copy constructor and copy assignment are implicitly + defined. Combined with the following converting constructor and + assignment, they support: (1) copy from iterator to iterator, (2) + copy from const iterator to const iterator, and (3) conversion from + iterator to const iterator. However conversion from const iterator + to iterator is not defined. + */ + + /*! + @brief const copy constructor + @param[in] other const iterator to copy from + @note This copy constructor had to be defined explicitly to circumvent a bug + occurring on msvc v19.0 compiler (VS 2015) debug build. For more + information refer to: https://github.com/nlohmann/json/issues/1608 + */ + iter_impl(const iter_impl& other) noexcept + : m_object(other.m_object), m_it(other.m_it) + {} + + /*! + @brief converting assignment + @param[in] other const iterator to copy from + @return const/non-const iterator + @note It is not checked whether @a other is initialized. + */ + iter_impl& operator=(const iter_impl& other) noexcept + { + if (&other != this) + { + m_object = other.m_object; + m_it = other.m_it; + } + return *this; + } + + /*! + @brief converting constructor + @param[in] other non-const iterator to copy from + @note It is not checked whether @a other is initialized. + */ + iter_impl(const iter_impl::type>& other) noexcept + : m_object(other.m_object), m_it(other.m_it) + {} + + /*! + @brief converting assignment + @param[in] other non-const iterator to copy from + @return const/non-const iterator + @note It is not checked whether @a other is initialized. + */ + iter_impl& operator=(const iter_impl::type>& other) noexcept // NOLINT(cert-oop54-cpp) + { + m_object = other.m_object; + m_it = other.m_it; + return *this; + } + + JSON_PRIVATE_UNLESS_TESTED: + /*! + @brief set the iterator to the first value + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + void set_begin() noexcept + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + m_it.object_iterator = m_object->m_value.object->begin(); + break; + } + + case value_t::array: + { + m_it.array_iterator = m_object->m_value.array->begin(); + break; + } + + case value_t::null: + { + // set to end so begin()==end() is true: null is empty + m_it.primitive_iterator.set_end(); + break; + } + + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + { + m_it.primitive_iterator.set_begin(); + break; + } + } + } + + /*! + @brief set the iterator past the last value + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + void set_end() noexcept + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + m_it.object_iterator = m_object->m_value.object->end(); + break; + } + + case value_t::array: + { + m_it.array_iterator = m_object->m_value.array->end(); + break; + } + + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + { + m_it.primitive_iterator.set_end(); + break; + } + } + } + + public: + /*! + @brief return a reference to the value pointed to by the iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + reference operator*() const + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + JSON_ASSERT(m_it.object_iterator != m_object->m_value.object->end()); + return m_it.object_iterator->second; + } + + case value_t::array: + { + JSON_ASSERT(m_it.array_iterator != m_object->m_value.array->end()); + return *m_it.array_iterator; + } + + case value_t::null: + JSON_THROW(invalid_iterator::create(214, "cannot get value", *m_object)); + + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + { + if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin())) + { + return *m_object; + } + + JSON_THROW(invalid_iterator::create(214, "cannot get value", *m_object)); + } + } + } + + /*! + @brief dereference the iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + pointer operator->() const + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + JSON_ASSERT(m_it.object_iterator != m_object->m_value.object->end()); + return &(m_it.object_iterator->second); + } + + case value_t::array: + { + JSON_ASSERT(m_it.array_iterator != m_object->m_value.array->end()); + return &*m_it.array_iterator; + } + + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + { + if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin())) + { + return m_object; + } + + JSON_THROW(invalid_iterator::create(214, "cannot get value", *m_object)); + } + } + } + + /*! + @brief post-increment (it++) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl const operator++(int) // NOLINT(readability-const-return-type) + { + auto result = *this; + ++(*this); + return result; + } + + /*! + @brief pre-increment (++it) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl& operator++() + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + std::advance(m_it.object_iterator, 1); + break; + } + + case value_t::array: + { + std::advance(m_it.array_iterator, 1); + break; + } + + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + { + ++m_it.primitive_iterator; + break; + } + } + + return *this; + } + + /*! + @brief post-decrement (it--) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl const operator--(int) // NOLINT(readability-const-return-type) + { + auto result = *this; + --(*this); + return result; + } + + /*! + @brief pre-decrement (--it) + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl& operator--() + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + { + std::advance(m_it.object_iterator, -1); + break; + } + + case value_t::array: + { + std::advance(m_it.array_iterator, -1); + break; + } + + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + { + --m_it.primitive_iterator; + break; + } + } + + return *this; + } + + /*! + @brief comparison: equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + template < typename IterImpl, detail::enable_if_t < (std::is_same::value || std::is_same::value), std::nullptr_t > = nullptr > + bool operator==(const IterImpl& other) const + { + // if objects are not the same, the comparison is undefined + if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object)) + { + JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", *m_object)); + } + + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + return (m_it.object_iterator == other.m_it.object_iterator); + + case value_t::array: + return (m_it.array_iterator == other.m_it.array_iterator); + + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + return (m_it.primitive_iterator == other.m_it.primitive_iterator); + } + } + + /*! + @brief comparison: not equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + template < typename IterImpl, detail::enable_if_t < (std::is_same::value || std::is_same::value), std::nullptr_t > = nullptr > + bool operator!=(const IterImpl& other) const + { + return !operator==(other); + } + + /*! + @brief comparison: smaller + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator<(const iter_impl& other) const + { + // if objects are not the same, the comparison is undefined + if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object)) + { + JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", *m_object)); + } + + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + JSON_THROW(invalid_iterator::create(213, "cannot compare order of object iterators", *m_object)); + + case value_t::array: + return (m_it.array_iterator < other.m_it.array_iterator); + + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + return (m_it.primitive_iterator < other.m_it.primitive_iterator); + } + } + + /*! + @brief comparison: less than or equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator<=(const iter_impl& other) const + { + return !other.operator < (*this); + } + + /*! + @brief comparison: greater than + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator>(const iter_impl& other) const + { + return !operator<=(other); + } + + /*! + @brief comparison: greater than or equal + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + bool operator>=(const iter_impl& other) const + { + return !operator<(other); + } + + /*! + @brief add to iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl& operator+=(difference_type i) + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators", *m_object)); + + case value_t::array: + { + std::advance(m_it.array_iterator, i); + break; + } + + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + { + m_it.primitive_iterator += i; + break; + } + } + + return *this; + } + + /*! + @brief subtract from iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl& operator-=(difference_type i) + { + return operator+=(-i); + } + + /*! + @brief add to iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl operator+(difference_type i) const + { + auto result = *this; + result += i; + return result; + } + + /*! + @brief addition of distance and iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + friend iter_impl operator+(difference_type i, const iter_impl& it) + { + auto result = it; + result += i; + return result; + } + + /*! + @brief subtract from iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + iter_impl operator-(difference_type i) const + { + auto result = *this; + result -= i; + return result; + } + + /*! + @brief return difference + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + difference_type operator-(const iter_impl& other) const + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators", *m_object)); + + case value_t::array: + return m_it.array_iterator - other.m_it.array_iterator; + + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + return m_it.primitive_iterator - other.m_it.primitive_iterator; + } + } + + /*! + @brief access to successor + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + reference operator[](difference_type n) const + { + JSON_ASSERT(m_object != nullptr); + + switch (m_object->m_type) + { + case value_t::object: + JSON_THROW(invalid_iterator::create(208, "cannot use operator[] for object iterators", *m_object)); + + case value_t::array: + return *std::next(m_it.array_iterator, n); + + case value_t::null: + JSON_THROW(invalid_iterator::create(214, "cannot get value", *m_object)); + + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + { + if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.get_value() == -n)) + { + return *m_object; + } + + JSON_THROW(invalid_iterator::create(214, "cannot get value", *m_object)); + } + } + } + + /*! + @brief return the key of an object iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + const typename object_t::key_type& key() const + { + JSON_ASSERT(m_object != nullptr); + + if (JSON_HEDLEY_LIKELY(m_object->is_object())) + { + return m_it.object_iterator->first; + } + + JSON_THROW(invalid_iterator::create(207, "cannot use key() for non-object iterators", *m_object)); + } + + /*! + @brief return the value of an iterator + @pre The iterator is initialized; i.e. `m_object != nullptr`. + */ + reference value() const + { + return operator*(); + } + + JSON_PRIVATE_UNLESS_TESTED: + /// associated JSON instance + pointer m_object = nullptr; + /// the actual iterator of the associated instance + internal_iterator::type> m_it {}; +}; +} // namespace detail +} // namespace nlohmann + +// #include + +// #include + + +#include // ptrdiff_t +#include // reverse_iterator +#include // declval + +namespace nlohmann +{ +namespace detail +{ +////////////////////// +// reverse_iterator // +////////////////////// + +/*! +@brief a template for a reverse iterator class + +@tparam Base the base iterator type to reverse. Valid types are @ref +iterator (to create @ref reverse_iterator) and @ref const_iterator (to +create @ref const_reverse_iterator). + +@requirement The class satisfies the following concept requirements: +- +[BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator): + The iterator that can be moved can be moved in both directions (i.e. + incremented and decremented). +- [OutputIterator](https://en.cppreference.com/w/cpp/named_req/OutputIterator): + It is possible to write to the pointed-to element (only if @a Base is + @ref iterator). + +@since version 1.0.0 +*/ +template +class json_reverse_iterator : public std::reverse_iterator +{ + public: + using difference_type = std::ptrdiff_t; + /// shortcut to the reverse iterator adapter + using base_iterator = std::reverse_iterator; + /// the reference type for the pointed-to element + using reference = typename Base::reference; + + /// create reverse iterator from iterator + explicit json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept + : base_iterator(it) {} + + /// create reverse iterator from base class + explicit json_reverse_iterator(const base_iterator& it) noexcept : base_iterator(it) {} + + /// post-increment (it++) + json_reverse_iterator const operator++(int) // NOLINT(readability-const-return-type) + { + return static_cast(base_iterator::operator++(1)); + } + + /// pre-increment (++it) + json_reverse_iterator& operator++() + { + return static_cast(base_iterator::operator++()); + } + + /// post-decrement (it--) + json_reverse_iterator const operator--(int) // NOLINT(readability-const-return-type) + { + return static_cast(base_iterator::operator--(1)); + } + + /// pre-decrement (--it) + json_reverse_iterator& operator--() + { + return static_cast(base_iterator::operator--()); + } + + /// add to iterator + json_reverse_iterator& operator+=(difference_type i) + { + return static_cast(base_iterator::operator+=(i)); + } + + /// add to iterator + json_reverse_iterator operator+(difference_type i) const + { + return static_cast(base_iterator::operator+(i)); + } + + /// subtract from iterator + json_reverse_iterator operator-(difference_type i) const + { + return static_cast(base_iterator::operator-(i)); + } + + /// return difference + difference_type operator-(const json_reverse_iterator& other) const + { + return base_iterator(*this) - base_iterator(other); + } + + /// access to successor + reference operator[](difference_type n) const + { + return *(this->operator+(n)); + } + + /// return the key of an object iterator + auto key() const -> decltype(std::declval().key()) + { + auto it = --this->base(); + return it.key(); + } + + /// return the value of an iterator + reference value() const + { + auto it = --this->base(); + return it.operator * (); + } +}; +} // namespace detail +} // namespace nlohmann + +// #include + +// #include + + +#include // all_of +#include // isdigit +#include // max +#include // accumulate +#include // string +#include // move +#include // vector + +// #include + +// #include + +// #include + +// #include + + +namespace nlohmann +{ +template +class json_pointer +{ + // allow basic_json to access private members + NLOHMANN_BASIC_JSON_TPL_DECLARATION + friend class basic_json; + + public: + /*! + @brief create JSON pointer + + Create a JSON pointer according to the syntax described in + [Section 3 of RFC6901](https://tools.ietf.org/html/rfc6901#section-3). + + @param[in] s string representing the JSON pointer; if omitted, the empty + string is assumed which references the whole JSON value + + @throw parse_error.107 if the given JSON pointer @a s is nonempty and does + not begin with a slash (`/`); see example below + + @throw parse_error.108 if a tilde (`~`) in the given JSON pointer @a s is + not followed by `0` (representing `~`) or `1` (representing `/`); see + example below + + @liveexample{The example shows the construction several valid JSON pointers + as well as the exceptional behavior.,json_pointer} + + @since version 2.0.0 + */ + explicit json_pointer(const std::string& s = "") + : reference_tokens(split(s)) + {} + + /*! + @brief return a string representation of the JSON pointer + + @invariant For each JSON pointer `ptr`, it holds: + @code {.cpp} + ptr == json_pointer(ptr.to_string()); + @endcode + + @return a string representation of the JSON pointer + + @liveexample{The example shows the result of `to_string`.,json_pointer__to_string} + + @since version 2.0.0 + */ + std::string to_string() const + { + return std::accumulate(reference_tokens.begin(), reference_tokens.end(), + std::string{}, + [](const std::string & a, const std::string & b) + { + return a + "/" + detail::escape(b); + }); + } + + /// @copydoc to_string() + operator std::string() const + { + return to_string(); + } + + /*! + @brief append another JSON pointer at the end of this JSON pointer + + @param[in] ptr JSON pointer to append + @return JSON pointer with @a ptr appended + + @liveexample{The example shows the usage of `operator/=`.,json_pointer__operator_add} + + @complexity Linear in the length of @a ptr. + + @sa see @ref operator/=(std::string) to append a reference token + @sa see @ref operator/=(std::size_t) to append an array index + @sa see @ref operator/(const json_pointer&, const json_pointer&) for a binary operator + + @since version 3.6.0 + */ + json_pointer& operator/=(const json_pointer& ptr) + { + reference_tokens.insert(reference_tokens.end(), + ptr.reference_tokens.begin(), + ptr.reference_tokens.end()); + return *this; + } + + /*! + @brief append an unescaped reference token at the end of this JSON pointer + + @param[in] token reference token to append + @return JSON pointer with @a token appended without escaping @a token + + @liveexample{The example shows the usage of `operator/=`.,json_pointer__operator_add} + + @complexity Amortized constant. + + @sa see @ref operator/=(const json_pointer&) to append a JSON pointer + @sa see @ref operator/=(std::size_t) to append an array index + @sa see @ref operator/(const json_pointer&, std::size_t) for a binary operator + + @since version 3.6.0 + */ + json_pointer& operator/=(std::string token) + { + push_back(std::move(token)); + return *this; + } + + /*! + @brief append an array index at the end of this JSON pointer + + @param[in] array_idx array index to append + @return JSON pointer with @a array_idx appended + + @liveexample{The example shows the usage of `operator/=`.,json_pointer__operator_add} + + @complexity Amortized constant. + + @sa see @ref operator/=(const json_pointer&) to append a JSON pointer + @sa see @ref operator/=(std::string) to append a reference token + @sa see @ref operator/(const json_pointer&, std::string) for a binary operator + + @since version 3.6.0 + */ + json_pointer& operator/=(std::size_t array_idx) + { + return *this /= std::to_string(array_idx); + } + + /*! + @brief create a new JSON pointer by appending the right JSON pointer at the end of the left JSON pointer + + @param[in] lhs JSON pointer + @param[in] rhs JSON pointer + @return a new JSON pointer with @a rhs appended to @a lhs + + @liveexample{The example shows the usage of `operator/`.,json_pointer__operator_add_binary} + + @complexity Linear in the length of @a lhs and @a rhs. + + @sa see @ref operator/=(const json_pointer&) to append a JSON pointer + + @since version 3.6.0 + */ + friend json_pointer operator/(const json_pointer& lhs, + const json_pointer& rhs) + { + return json_pointer(lhs) /= rhs; + } + + /*! + @brief create a new JSON pointer by appending the unescaped token at the end of the JSON pointer + + @param[in] ptr JSON pointer + @param[in] token reference token + @return a new JSON pointer with unescaped @a token appended to @a ptr + + @liveexample{The example shows the usage of `operator/`.,json_pointer__operator_add_binary} + + @complexity Linear in the length of @a ptr. + + @sa see @ref operator/=(std::string) to append a reference token + + @since version 3.6.0 + */ + friend json_pointer operator/(const json_pointer& ptr, std::string token) // NOLINT(performance-unnecessary-value-param) + { + return json_pointer(ptr) /= std::move(token); + } + + /*! + @brief create a new JSON pointer by appending the array-index-token at the end of the JSON pointer + + @param[in] ptr JSON pointer + @param[in] array_idx array index + @return a new JSON pointer with @a array_idx appended to @a ptr + + @liveexample{The example shows the usage of `operator/`.,json_pointer__operator_add_binary} + + @complexity Linear in the length of @a ptr. + + @sa see @ref operator/=(std::size_t) to append an array index + + @since version 3.6.0 + */ + friend json_pointer operator/(const json_pointer& ptr, std::size_t array_idx) + { + return json_pointer(ptr) /= array_idx; + } + + /*! + @brief returns the parent of this JSON pointer + + @return parent of this JSON pointer; in case this JSON pointer is the root, + the root itself is returned + + @complexity Linear in the length of the JSON pointer. + + @liveexample{The example shows the result of `parent_pointer` for different + JSON Pointers.,json_pointer__parent_pointer} + + @since version 3.6.0 + */ + json_pointer parent_pointer() const + { + if (empty()) + { + return *this; + } + + json_pointer res = *this; + res.pop_back(); + return res; + } + + /*! + @brief remove last reference token + + @pre not `empty()` + + @liveexample{The example shows the usage of `pop_back`.,json_pointer__pop_back} + + @complexity Constant. + + @throw out_of_range.405 if JSON pointer has no parent + + @since version 3.6.0 + */ + void pop_back() + { + if (JSON_HEDLEY_UNLIKELY(empty())) + { + JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", BasicJsonType())); + } + + reference_tokens.pop_back(); + } + + /*! + @brief return last reference token + + @pre not `empty()` + @return last reference token + + @liveexample{The example shows the usage of `back`.,json_pointer__back} + + @complexity Constant. + + @throw out_of_range.405 if JSON pointer has no parent + + @since version 3.6.0 + */ + const std::string& back() const + { + if (JSON_HEDLEY_UNLIKELY(empty())) + { + JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", BasicJsonType())); + } + + return reference_tokens.back(); + } + + /*! + @brief append an unescaped token at the end of the reference pointer + + @param[in] token token to add + + @complexity Amortized constant. + + @liveexample{The example shows the result of `push_back` for different + JSON Pointers.,json_pointer__push_back} + + @since version 3.6.0 + */ + void push_back(const std::string& token) + { + reference_tokens.push_back(token); + } + + /// @copydoc push_back(const std::string&) + void push_back(std::string&& token) + { + reference_tokens.push_back(std::move(token)); + } + + /*! + @brief return whether pointer points to the root document + + @return true iff the JSON pointer points to the root document + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @liveexample{The example shows the result of `empty` for different JSON + Pointers.,json_pointer__empty} + + @since version 3.6.0 + */ + bool empty() const noexcept + { + return reference_tokens.empty(); + } + + private: + /*! + @param[in] s reference token to be converted into an array index + + @return integer representation of @a s + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index begins not with a digit + @throw out_of_range.404 if string @a s could not be converted to an integer + @throw out_of_range.410 if an array index exceeds size_type + */ + static typename BasicJsonType::size_type array_index(const std::string& s) + { + using size_type = typename BasicJsonType::size_type; + + // error condition (cf. RFC 6901, Sect. 4) + if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && s[0] == '0')) + { + JSON_THROW(detail::parse_error::create(106, 0, "array index '" + s + "' must not begin with '0'", BasicJsonType())); + } + + // error condition (cf. RFC 6901, Sect. 4) + if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && !(s[0] >= '1' && s[0] <= '9'))) + { + JSON_THROW(detail::parse_error::create(109, 0, "array index '" + s + "' is not a number", BasicJsonType())); + } + + std::size_t processed_chars = 0; + unsigned long long res = 0; // NOLINT(runtime/int) + JSON_TRY + { + res = std::stoull(s, &processed_chars); + } + JSON_CATCH(std::out_of_range&) + { + JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + s + "'", BasicJsonType())); + } + + // check if the string was completely read + if (JSON_HEDLEY_UNLIKELY(processed_chars != s.size())) + { + JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + s + "'", BasicJsonType())); + } + + // only triggered on special platforms (like 32bit), see also + // https://github.com/nlohmann/json/pull/2203 + if (res >= static_cast((std::numeric_limits::max)())) // NOLINT(runtime/int) + { + JSON_THROW(detail::out_of_range::create(410, "array index " + s + " exceeds size_type", BasicJsonType())); // LCOV_EXCL_LINE + } + + return static_cast(res); + } + + JSON_PRIVATE_UNLESS_TESTED: + json_pointer top() const + { + if (JSON_HEDLEY_UNLIKELY(empty())) + { + JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", BasicJsonType())); + } + + json_pointer result = *this; + result.reference_tokens = {reference_tokens[0]}; + return result; + } + + private: + /*! + @brief create and return a reference to the pointed to value + + @complexity Linear in the number of reference tokens. + + @throw parse_error.109 if array index is not a number + @throw type_error.313 if value cannot be unflattened + */ + BasicJsonType& get_and_create(BasicJsonType& j) const + { + auto* result = &j; + + // in case no reference tokens exist, return a reference to the JSON value + // j which will be overwritten by a primitive value + for (const auto& reference_token : reference_tokens) + { + switch (result->type()) + { + case detail::value_t::null: + { + if (reference_token == "0") + { + // start a new array if reference token is 0 + result = &result->operator[](0); + } + else + { + // start a new object otherwise + result = &result->operator[](reference_token); + } + break; + } + + case detail::value_t::object: + { + // create an entry in the object + result = &result->operator[](reference_token); + break; + } + + case detail::value_t::array: + { + // create an entry in the array + result = &result->operator[](array_index(reference_token)); + break; + } + + /* + The following code is only reached if there exists a reference + token _and_ the current value is primitive. In this case, we have + an error situation, because primitive values may only occur as + single value; that is, with an empty list of reference tokens. + */ + case detail::value_t::string: + case detail::value_t::boolean: + case detail::value_t::number_integer: + case detail::value_t::number_unsigned: + case detail::value_t::number_float: + case detail::value_t::binary: + case detail::value_t::discarded: + default: + JSON_THROW(detail::type_error::create(313, "invalid value to unflatten", j)); + } + } + + return *result; + } + + /*! + @brief return a reference to the pointed to value + + @note This version does not throw if a value is not present, but tries to + create nested values instead. For instance, calling this function + with pointer `"/this/that"` on a null value is equivalent to calling + `operator[]("this").operator[]("that")` on that value, effectively + changing the null value to an object. + + @param[in] ptr a JSON value + + @return reference to the JSON value pointed to by the JSON pointer + + @complexity Linear in the length of the JSON pointer. + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.404 if the JSON pointer can not be resolved + */ + BasicJsonType& get_unchecked(BasicJsonType* ptr) const + { + for (const auto& reference_token : reference_tokens) + { + // convert null values to arrays or objects before continuing + if (ptr->is_null()) + { + // check if reference token is a number + const bool nums = + std::all_of(reference_token.begin(), reference_token.end(), + [](const unsigned char x) + { + return std::isdigit(x); + }); + + // change value to array for numbers or "-" or to object otherwise + *ptr = (nums || reference_token == "-") + ? detail::value_t::array + : detail::value_t::object; + } + + switch (ptr->type()) + { + case detail::value_t::object: + { + // use unchecked object access + ptr = &ptr->operator[](reference_token); + break; + } + + case detail::value_t::array: + { + if (reference_token == "-") + { + // explicitly treat "-" as index beyond the end + ptr = &ptr->operator[](ptr->m_value.array->size()); + } + else + { + // convert array index to number; unchecked access + ptr = &ptr->operator[](array_index(reference_token)); + } + break; + } + + case detail::value_t::null: + case detail::value_t::string: + case detail::value_t::boolean: + case detail::value_t::number_integer: + case detail::value_t::number_unsigned: + case detail::value_t::number_float: + case detail::value_t::binary: + case detail::value_t::discarded: + default: + JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'", *ptr)); + } + } + + return *ptr; + } + + /*! + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved + */ + BasicJsonType& get_checked(BasicJsonType* ptr) const + { + for (const auto& reference_token : reference_tokens) + { + switch (ptr->type()) + { + case detail::value_t::object: + { + // note: at performs range check + ptr = &ptr->at(reference_token); + break; + } + + case detail::value_t::array: + { + if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) + { + // "-" always fails the range check + JSON_THROW(detail::out_of_range::create(402, + "array index '-' (" + std::to_string(ptr->m_value.array->size()) + + ") is out of range", *ptr)); + } + + // note: at performs range check + ptr = &ptr->at(array_index(reference_token)); + break; + } + + case detail::value_t::null: + case detail::value_t::string: + case detail::value_t::boolean: + case detail::value_t::number_integer: + case detail::value_t::number_unsigned: + case detail::value_t::number_float: + case detail::value_t::binary: + case detail::value_t::discarded: + default: + JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'", *ptr)); + } + } + + return *ptr; + } + + /*! + @brief return a const reference to the pointed to value + + @param[in] ptr a JSON value + + @return const reference to the JSON value pointed to by the JSON + pointer + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved + */ + const BasicJsonType& get_unchecked(const BasicJsonType* ptr) const + { + for (const auto& reference_token : reference_tokens) + { + switch (ptr->type()) + { + case detail::value_t::object: + { + // use unchecked object access + ptr = &ptr->operator[](reference_token); + break; + } + + case detail::value_t::array: + { + if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) + { + // "-" cannot be used for const access + JSON_THROW(detail::out_of_range::create(402, "array index '-' (" + std::to_string(ptr->m_value.array->size()) + ") is out of range", *ptr)); + } + + // use unchecked array access + ptr = &ptr->operator[](array_index(reference_token)); + break; + } + + case detail::value_t::null: + case detail::value_t::string: + case detail::value_t::boolean: + case detail::value_t::number_integer: + case detail::value_t::number_unsigned: + case detail::value_t::number_float: + case detail::value_t::binary: + case detail::value_t::discarded: + default: + JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'", *ptr)); + } + } + + return *ptr; + } + + /*! + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved + */ + const BasicJsonType& get_checked(const BasicJsonType* ptr) const + { + for (const auto& reference_token : reference_tokens) + { + switch (ptr->type()) + { + case detail::value_t::object: + { + // note: at performs range check + ptr = &ptr->at(reference_token); + break; + } + + case detail::value_t::array: + { + if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) + { + // "-" always fails the range check + JSON_THROW(detail::out_of_range::create(402, + "array index '-' (" + std::to_string(ptr->m_value.array->size()) + + ") is out of range", *ptr)); + } + + // note: at performs range check + ptr = &ptr->at(array_index(reference_token)); + break; + } + + case detail::value_t::null: + case detail::value_t::string: + case detail::value_t::boolean: + case detail::value_t::number_integer: + case detail::value_t::number_unsigned: + case detail::value_t::number_float: + case detail::value_t::binary: + case detail::value_t::discarded: + default: + JSON_THROW(detail::out_of_range::create(404, "unresolved reference token '" + reference_token + "'", *ptr)); + } + } + + return *ptr; + } + + /*! + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + */ + bool contains(const BasicJsonType* ptr) const + { + for (const auto& reference_token : reference_tokens) + { + switch (ptr->type()) + { + case detail::value_t::object: + { + if (!ptr->contains(reference_token)) + { + // we did not find the key in the object + return false; + } + + ptr = &ptr->operator[](reference_token); + break; + } + + case detail::value_t::array: + { + if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) + { + // "-" always fails the range check + return false; + } + if (JSON_HEDLEY_UNLIKELY(reference_token.size() == 1 && !("0" <= reference_token && reference_token <= "9"))) + { + // invalid char + return false; + } + if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1)) + { + if (JSON_HEDLEY_UNLIKELY(!('1' <= reference_token[0] && reference_token[0] <= '9'))) + { + // first char should be between '1' and '9' + return false; + } + for (std::size_t i = 1; i < reference_token.size(); i++) + { + if (JSON_HEDLEY_UNLIKELY(!('0' <= reference_token[i] && reference_token[i] <= '9'))) + { + // other char should be between '0' and '9' + return false; + } + } + } + + const auto idx = array_index(reference_token); + if (idx >= ptr->size()) + { + // index out of range + return false; + } + + ptr = &ptr->operator[](idx); + break; + } + + case detail::value_t::null: + case detail::value_t::string: + case detail::value_t::boolean: + case detail::value_t::number_integer: + case detail::value_t::number_unsigned: + case detail::value_t::number_float: + case detail::value_t::binary: + case detail::value_t::discarded: + default: + { + // we do not expect primitive values if there is still a + // reference token to process + return false; + } + } + } + + // no reference token left means we found a primitive value + return true; + } + + /*! + @brief split the string input to reference tokens + + @note This function is only called by the json_pointer constructor. + All exceptions below are documented there. + + @throw parse_error.107 if the pointer is not empty or begins with '/' + @throw parse_error.108 if character '~' is not followed by '0' or '1' + */ + static std::vector split(const std::string& reference_string) + { + std::vector result; + + // special case: empty reference string -> no reference tokens + if (reference_string.empty()) + { + return result; + } + + // check if nonempty reference string begins with slash + if (JSON_HEDLEY_UNLIKELY(reference_string[0] != '/')) + { + JSON_THROW(detail::parse_error::create(107, 1, "JSON pointer must be empty or begin with '/' - was: '" + reference_string + "'", BasicJsonType())); + } + + // extract the reference tokens: + // - slash: position of the last read slash (or end of string) + // - start: position after the previous slash + for ( + // search for the first slash after the first character + std::size_t slash = reference_string.find_first_of('/', 1), + // set the beginning of the first reference token + start = 1; + // we can stop if start == 0 (if slash == std::string::npos) + start != 0; + // set the beginning of the next reference token + // (will eventually be 0 if slash == std::string::npos) + start = (slash == std::string::npos) ? 0 : slash + 1, + // find next slash + slash = reference_string.find_first_of('/', start)) + { + // use the text between the beginning of the reference token + // (start) and the last slash (slash). + auto reference_token = reference_string.substr(start, slash - start); + + // check reference tokens are properly escaped + for (std::size_t pos = reference_token.find_first_of('~'); + pos != std::string::npos; + pos = reference_token.find_first_of('~', pos + 1)) + { + JSON_ASSERT(reference_token[pos] == '~'); + + // ~ must be followed by 0 or 1 + if (JSON_HEDLEY_UNLIKELY(pos == reference_token.size() - 1 || + (reference_token[pos + 1] != '0' && + reference_token[pos + 1] != '1'))) + { + JSON_THROW(detail::parse_error::create(108, 0, "escape character '~' must be followed with '0' or '1'", BasicJsonType())); + } + } + + // finally, store the reference token + detail::unescape(reference_token); + result.push_back(reference_token); + } + + return result; + } + + private: + /*! + @param[in] reference_string the reference string to the current value + @param[in] value the value to consider + @param[in,out] result the result object to insert values to + + @note Empty objects or arrays are flattened to `null`. + */ + static void flatten(const std::string& reference_string, + const BasicJsonType& value, + BasicJsonType& result) + { + switch (value.type()) + { + case detail::value_t::array: + { + if (value.m_value.array->empty()) + { + // flatten empty array as null + result[reference_string] = nullptr; + } + else + { + // iterate array and use index as reference string + for (std::size_t i = 0; i < value.m_value.array->size(); ++i) + { + flatten(reference_string + "/" + std::to_string(i), + value.m_value.array->operator[](i), result); + } + } + break; + } + + case detail::value_t::object: + { + if (value.m_value.object->empty()) + { + // flatten empty object as null + result[reference_string] = nullptr; + } + else + { + // iterate object and use keys as reference string + for (const auto& element : *value.m_value.object) + { + flatten(reference_string + "/" + detail::escape(element.first), element.second, result); + } + } + break; + } + + case detail::value_t::null: + case detail::value_t::string: + case detail::value_t::boolean: + case detail::value_t::number_integer: + case detail::value_t::number_unsigned: + case detail::value_t::number_float: + case detail::value_t::binary: + case detail::value_t::discarded: + default: + { + // add primitive value with its reference string + result[reference_string] = value; + break; + } + } + } + + /*! + @param[in] value flattened JSON + + @return unflattened JSON + + @throw parse_error.109 if array index is not a number + @throw type_error.314 if value is not an object + @throw type_error.315 if object values are not primitive + @throw type_error.313 if value cannot be unflattened + */ + static BasicJsonType + unflatten(const BasicJsonType& value) + { + if (JSON_HEDLEY_UNLIKELY(!value.is_object())) + { + JSON_THROW(detail::type_error::create(314, "only objects can be unflattened", value)); + } + + BasicJsonType result; + + // iterate the JSON object values + for (const auto& element : *value.m_value.object) + { + if (JSON_HEDLEY_UNLIKELY(!element.second.is_primitive())) + { + JSON_THROW(detail::type_error::create(315, "values in object must be primitive", element.second)); + } + + // assign value to reference pointed to by JSON pointer; Note that if + // the JSON pointer is "" (i.e., points to the whole value), function + // get_and_create returns a reference to result itself. An assignment + // will then create a primitive value. + json_pointer(element.first).get_and_create(result) = element.second; + } + + return result; + } + + /*! + @brief compares two JSON pointers for equality + + @param[in] lhs JSON pointer to compare + @param[in] rhs JSON pointer to compare + @return whether @a lhs is equal to @a rhs + + @complexity Linear in the length of the JSON pointer + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + */ + friend bool operator==(json_pointer const& lhs, + json_pointer const& rhs) noexcept + { + return lhs.reference_tokens == rhs.reference_tokens; + } + + /*! + @brief compares two JSON pointers for inequality + + @param[in] lhs JSON pointer to compare + @param[in] rhs JSON pointer to compare + @return whether @a lhs is not equal @a rhs + + @complexity Linear in the length of the JSON pointer + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + */ + friend bool operator!=(json_pointer const& lhs, + json_pointer const& rhs) noexcept + { + return !(lhs == rhs); + } + + /// the reference tokens + std::vector reference_tokens; +}; +} // namespace nlohmann + +// #include + + +#include +#include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +template +class json_ref +{ + public: + using value_type = BasicJsonType; + + json_ref(value_type&& value) + : owned_value(std::move(value)) + {} + + json_ref(const value_type& value) + : value_ref(&value) + {} + + json_ref(std::initializer_list init) + : owned_value(init) + {} + + template < + class... Args, + enable_if_t::value, int> = 0 > + json_ref(Args && ... args) + : owned_value(std::forward(args)...) + {} + + // class should be movable only + json_ref(json_ref&&) noexcept = default; + json_ref(const json_ref&) = delete; + json_ref& operator=(const json_ref&) = delete; + json_ref& operator=(json_ref&&) = delete; + ~json_ref() = default; + + value_type moved_or_copied() const + { + if (value_ref == nullptr) + { + return std::move(owned_value); + } + return *value_ref; + } + + value_type const& operator*() const + { + return value_ref ? *value_ref : owned_value; + } + + value_type const* operator->() const + { + return &** this; + } + + private: + mutable value_type owned_value = nullptr; + value_type const* value_ref = nullptr; +}; +} // namespace detail +} // namespace nlohmann + +// #include + +// #include + +// #include + +// #include + +// #include + + +#include // reverse +#include // array +#include // isnan, isinf +#include // uint8_t, uint16_t, uint32_t, uint64_t +#include // memcpy +#include // numeric_limits +#include // string +#include // move + +// #include + +// #include + +// #include + + +#include // copy +#include // size_t +#include // back_inserter +#include // shared_ptr, make_shared +#include // basic_string +#include // vector + +#ifndef JSON_NO_IO + #include // streamsize + #include // basic_ostream +#endif // JSON_NO_IO + +// #include + + +namespace nlohmann +{ +namespace detail +{ +/// abstract output adapter interface +template struct output_adapter_protocol +{ + virtual void write_character(CharType c) = 0; + virtual void write_characters(const CharType* s, std::size_t length) = 0; + virtual ~output_adapter_protocol() = default; + + output_adapter_protocol() = default; + output_adapter_protocol(const output_adapter_protocol&) = default; + output_adapter_protocol(output_adapter_protocol&&) noexcept = default; + output_adapter_protocol& operator=(const output_adapter_protocol&) = default; + output_adapter_protocol& operator=(output_adapter_protocol&&) noexcept = default; +}; + +/// a type to simplify interfaces +template +using output_adapter_t = std::shared_ptr>; + +/// output adapter for byte vectors +template> +class output_vector_adapter : public output_adapter_protocol +{ + public: + explicit output_vector_adapter(std::vector& vec) noexcept + : v(vec) + {} + + void write_character(CharType c) override + { + v.push_back(c); + } + + JSON_HEDLEY_NON_NULL(2) + void write_characters(const CharType* s, std::size_t length) override + { + std::copy(s, s + length, std::back_inserter(v)); + } + + private: + std::vector& v; +}; + +#ifndef JSON_NO_IO +/// output adapter for output streams +template +class output_stream_adapter : public output_adapter_protocol +{ + public: + explicit output_stream_adapter(std::basic_ostream& s) noexcept + : stream(s) + {} + + void write_character(CharType c) override + { + stream.put(c); + } + + JSON_HEDLEY_NON_NULL(2) + void write_characters(const CharType* s, std::size_t length) override + { + stream.write(s, static_cast(length)); + } + + private: + std::basic_ostream& stream; +}; +#endif // JSON_NO_IO + +/// output adapter for basic_string +template> +class output_string_adapter : public output_adapter_protocol +{ + public: + explicit output_string_adapter(StringType& s) noexcept + : str(s) + {} + + void write_character(CharType c) override + { + str.push_back(c); + } + + JSON_HEDLEY_NON_NULL(2) + void write_characters(const CharType* s, std::size_t length) override + { + str.append(s, length); + } + + private: + StringType& str; +}; + +template> +class output_adapter +{ + public: + template> + output_adapter(std::vector& vec) + : oa(std::make_shared>(vec)) {} + +#ifndef JSON_NO_IO + output_adapter(std::basic_ostream& s) + : oa(std::make_shared>(s)) {} +#endif // JSON_NO_IO + + output_adapter(StringType& s) + : oa(std::make_shared>(s)) {} + + operator output_adapter_t() + { + return oa; + } + + private: + output_adapter_t oa = nullptr; +}; +} // namespace detail +} // namespace nlohmann + + +namespace nlohmann +{ +namespace detail +{ +/////////////////// +// binary writer // +/////////////////// + +/*! +@brief serialization to CBOR and MessagePack values +*/ +template +class binary_writer +{ + using string_t = typename BasicJsonType::string_t; + using binary_t = typename BasicJsonType::binary_t; + using number_float_t = typename BasicJsonType::number_float_t; + + public: + /*! + @brief create a binary writer + + @param[in] adapter output adapter to write to + */ + explicit binary_writer(output_adapter_t adapter) : oa(std::move(adapter)) + { + JSON_ASSERT(oa); + } + + /*! + @param[in] j JSON value to serialize + @pre j.type() == value_t::object + */ + void write_bson(const BasicJsonType& j) + { + switch (j.type()) + { + case value_t::object: + { + write_bson_object(*j.m_value.object); + break; + } + + case value_t::null: + case value_t::array: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + { + JSON_THROW(type_error::create(317, "to serialize to BSON, top-level type must be object, but is " + std::string(j.type_name()), j)); + } + } + } + + /*! + @param[in] j JSON value to serialize + */ + void write_cbor(const BasicJsonType& j) + { + switch (j.type()) + { + case value_t::null: + { + oa->write_character(to_char_type(0xF6)); + break; + } + + case value_t::boolean: + { + oa->write_character(j.m_value.boolean + ? to_char_type(0xF5) + : to_char_type(0xF4)); + break; + } + + case value_t::number_integer: + { + if (j.m_value.number_integer >= 0) + { + // CBOR does not differentiate between positive signed + // integers and unsigned integers. Therefore, we used the + // code from the value_t::number_unsigned case here. + if (j.m_value.number_integer <= 0x17) + { + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x18)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x19)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x1A)); + write_number(static_cast(j.m_value.number_integer)); + } + else + { + oa->write_character(to_char_type(0x1B)); + write_number(static_cast(j.m_value.number_integer)); + } + } + else + { + // The conversions below encode the sign in the first + // byte, and the value is converted to a positive number. + const auto positive_number = -1 - j.m_value.number_integer; + if (j.m_value.number_integer >= -24) + { + write_number(static_cast(0x20 + positive_number)); + } + else if (positive_number <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x38)); + write_number(static_cast(positive_number)); + } + else if (positive_number <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x39)); + write_number(static_cast(positive_number)); + } + else if (positive_number <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x3A)); + write_number(static_cast(positive_number)); + } + else + { + oa->write_character(to_char_type(0x3B)); + write_number(static_cast(positive_number)); + } + } + break; + } + + case value_t::number_unsigned: + { + if (j.m_value.number_unsigned <= 0x17) + { + write_number(static_cast(j.m_value.number_unsigned)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x18)); + write_number(static_cast(j.m_value.number_unsigned)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x19)); + write_number(static_cast(j.m_value.number_unsigned)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x1A)); + write_number(static_cast(j.m_value.number_unsigned)); + } + else + { + oa->write_character(to_char_type(0x1B)); + write_number(static_cast(j.m_value.number_unsigned)); + } + break; + } + + case value_t::number_float: + { + if (std::isnan(j.m_value.number_float)) + { + // NaN is 0xf97e00 in CBOR + oa->write_character(to_char_type(0xF9)); + oa->write_character(to_char_type(0x7E)); + oa->write_character(to_char_type(0x00)); + } + else if (std::isinf(j.m_value.number_float)) + { + // Infinity is 0xf97c00, -Infinity is 0xf9fc00 + oa->write_character(to_char_type(0xf9)); + oa->write_character(j.m_value.number_float > 0 ? to_char_type(0x7C) : to_char_type(0xFC)); + oa->write_character(to_char_type(0x00)); + } + else + { + write_compact_float(j.m_value.number_float, detail::input_format_t::cbor); + } + break; + } + + case value_t::string: + { + // step 1: write control byte and the string length + const auto N = j.m_value.string->size(); + if (N <= 0x17) + { + write_number(static_cast(0x60 + N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x78)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x79)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x7A)); + write_number(static_cast(N)); + } + // LCOV_EXCL_START + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x7B)); + write_number(static_cast(N)); + } + // LCOV_EXCL_STOP + + // step 2: write the string + oa->write_characters( + reinterpret_cast(j.m_value.string->c_str()), + j.m_value.string->size()); + break; + } + + case value_t::array: + { + // step 1: write control byte and the array size + const auto N = j.m_value.array->size(); + if (N <= 0x17) + { + write_number(static_cast(0x80 + N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x98)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x99)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x9A)); + write_number(static_cast(N)); + } + // LCOV_EXCL_START + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x9B)); + write_number(static_cast(N)); + } + // LCOV_EXCL_STOP + + // step 2: write each element + for (const auto& el : *j.m_value.array) + { + write_cbor(el); + } + break; + } + + case value_t::binary: + { + if (j.m_value.binary->has_subtype()) + { + if (j.m_value.binary->subtype() <= (std::numeric_limits::max)()) + { + write_number(static_cast(0xd8)); + write_number(static_cast(j.m_value.binary->subtype())); + } + else if (j.m_value.binary->subtype() <= (std::numeric_limits::max)()) + { + write_number(static_cast(0xd9)); + write_number(static_cast(j.m_value.binary->subtype())); + } + else if (j.m_value.binary->subtype() <= (std::numeric_limits::max)()) + { + write_number(static_cast(0xda)); + write_number(static_cast(j.m_value.binary->subtype())); + } + else if (j.m_value.binary->subtype() <= (std::numeric_limits::max)()) + { + write_number(static_cast(0xdb)); + write_number(static_cast(j.m_value.binary->subtype())); + } + } + + // step 1: write control byte and the binary array size + const auto N = j.m_value.binary->size(); + if (N <= 0x17) + { + write_number(static_cast(0x40 + N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x58)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x59)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x5A)); + write_number(static_cast(N)); + } + // LCOV_EXCL_START + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0x5B)); + write_number(static_cast(N)); + } + // LCOV_EXCL_STOP + + // step 2: write each element + oa->write_characters( + reinterpret_cast(j.m_value.binary->data()), + N); + + break; + } + + case value_t::object: + { + // step 1: write control byte and the object size + const auto N = j.m_value.object->size(); + if (N <= 0x17) + { + write_number(static_cast(0xA0 + N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0xB8)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0xB9)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0xBA)); + write_number(static_cast(N)); + } + // LCOV_EXCL_START + else if (N <= (std::numeric_limits::max)()) + { + oa->write_character(to_char_type(0xBB)); + write_number(static_cast(N)); + } + // LCOV_EXCL_STOP + + // step 2: write each element + for (const auto& el : *j.m_value.object) + { + write_cbor(el.first); + write_cbor(el.second); + } + break; + } + + case value_t::discarded: + default: + break; + } + } + + /*! + @param[in] j JSON value to serialize + */ + void write_msgpack(const BasicJsonType& j) + { + switch (j.type()) + { + case value_t::null: // nil + { + oa->write_character(to_char_type(0xC0)); + break; + } + + case value_t::boolean: // true and false + { + oa->write_character(j.m_value.boolean + ? to_char_type(0xC3) + : to_char_type(0xC2)); + break; + } + + case value_t::number_integer: + { + if (j.m_value.number_integer >= 0) + { + // MessagePack does not differentiate between positive + // signed integers and unsigned integers. Therefore, we used + // the code from the value_t::number_unsigned case here. + if (j.m_value.number_unsigned < 128) + { + // positive fixnum + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 8 + oa->write_character(to_char_type(0xCC)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 16 + oa->write_character(to_char_type(0xCD)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 32 + oa->write_character(to_char_type(0xCE)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 64 + oa->write_character(to_char_type(0xCF)); + write_number(static_cast(j.m_value.number_integer)); + } + } + else + { + if (j.m_value.number_integer >= -32) + { + // negative fixnum + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer >= (std::numeric_limits::min)() && + j.m_value.number_integer <= (std::numeric_limits::max)()) + { + // int 8 + oa->write_character(to_char_type(0xD0)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer >= (std::numeric_limits::min)() && + j.m_value.number_integer <= (std::numeric_limits::max)()) + { + // int 16 + oa->write_character(to_char_type(0xD1)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer >= (std::numeric_limits::min)() && + j.m_value.number_integer <= (std::numeric_limits::max)()) + { + // int 32 + oa->write_character(to_char_type(0xD2)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_integer >= (std::numeric_limits::min)() && + j.m_value.number_integer <= (std::numeric_limits::max)()) + { + // int 64 + oa->write_character(to_char_type(0xD3)); + write_number(static_cast(j.m_value.number_integer)); + } + } + break; + } + + case value_t::number_unsigned: + { + if (j.m_value.number_unsigned < 128) + { + // positive fixnum + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 8 + oa->write_character(to_char_type(0xCC)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 16 + oa->write_character(to_char_type(0xCD)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 32 + oa->write_character(to_char_type(0xCE)); + write_number(static_cast(j.m_value.number_integer)); + } + else if (j.m_value.number_unsigned <= (std::numeric_limits::max)()) + { + // uint 64 + oa->write_character(to_char_type(0xCF)); + write_number(static_cast(j.m_value.number_integer)); + } + break; + } + + case value_t::number_float: + { + write_compact_float(j.m_value.number_float, detail::input_format_t::msgpack); + break; + } + + case value_t::string: + { + // step 1: write control byte and the string length + const auto N = j.m_value.string->size(); + if (N <= 31) + { + // fixstr + write_number(static_cast(0xA0 | N)); + } + else if (N <= (std::numeric_limits::max)()) + { + // str 8 + oa->write_character(to_char_type(0xD9)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + // str 16 + oa->write_character(to_char_type(0xDA)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + // str 32 + oa->write_character(to_char_type(0xDB)); + write_number(static_cast(N)); + } + + // step 2: write the string + oa->write_characters( + reinterpret_cast(j.m_value.string->c_str()), + j.m_value.string->size()); + break; + } + + case value_t::array: + { + // step 1: write control byte and the array size + const auto N = j.m_value.array->size(); + if (N <= 15) + { + // fixarray + write_number(static_cast(0x90 | N)); + } + else if (N <= (std::numeric_limits::max)()) + { + // array 16 + oa->write_character(to_char_type(0xDC)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + // array 32 + oa->write_character(to_char_type(0xDD)); + write_number(static_cast(N)); + } + + // step 2: write each element + for (const auto& el : *j.m_value.array) + { + write_msgpack(el); + } + break; + } + + case value_t::binary: + { + // step 0: determine if the binary type has a set subtype to + // determine whether or not to use the ext or fixext types + const bool use_ext = j.m_value.binary->has_subtype(); + + // step 1: write control byte and the byte string length + const auto N = j.m_value.binary->size(); + if (N <= (std::numeric_limits::max)()) + { + std::uint8_t output_type{}; + bool fixed = true; + if (use_ext) + { + switch (N) + { + case 1: + output_type = 0xD4; // fixext 1 + break; + case 2: + output_type = 0xD5; // fixext 2 + break; + case 4: + output_type = 0xD6; // fixext 4 + break; + case 8: + output_type = 0xD7; // fixext 8 + break; + case 16: + output_type = 0xD8; // fixext 16 + break; + default: + output_type = 0xC7; // ext 8 + fixed = false; + break; + } + + } + else + { + output_type = 0xC4; // bin 8 + fixed = false; + } + + oa->write_character(to_char_type(output_type)); + if (!fixed) + { + write_number(static_cast(N)); + } + } + else if (N <= (std::numeric_limits::max)()) + { + std::uint8_t output_type = use_ext + ? 0xC8 // ext 16 + : 0xC5; // bin 16 + + oa->write_character(to_char_type(output_type)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + std::uint8_t output_type = use_ext + ? 0xC9 // ext 32 + : 0xC6; // bin 32 + + oa->write_character(to_char_type(output_type)); + write_number(static_cast(N)); + } + + // step 1.5: if this is an ext type, write the subtype + if (use_ext) + { + write_number(static_cast(j.m_value.binary->subtype())); + } + + // step 2: write the byte string + oa->write_characters( + reinterpret_cast(j.m_value.binary->data()), + N); + + break; + } + + case value_t::object: + { + // step 1: write control byte and the object size + const auto N = j.m_value.object->size(); + if (N <= 15) + { + // fixmap + write_number(static_cast(0x80 | (N & 0xF))); + } + else if (N <= (std::numeric_limits::max)()) + { + // map 16 + oa->write_character(to_char_type(0xDE)); + write_number(static_cast(N)); + } + else if (N <= (std::numeric_limits::max)()) + { + // map 32 + oa->write_character(to_char_type(0xDF)); + write_number(static_cast(N)); + } + + // step 2: write each element + for (const auto& el : *j.m_value.object) + { + write_msgpack(el.first); + write_msgpack(el.second); + } + break; + } + + case value_t::discarded: + default: + break; + } + } + + /*! + @param[in] j JSON value to serialize + @param[in] use_count whether to use '#' prefixes (optimized format) + @param[in] use_type whether to use '$' prefixes (optimized format) + @param[in] add_prefix whether prefixes need to be used for this value + */ + void write_ubjson(const BasicJsonType& j, const bool use_count, + const bool use_type, const bool add_prefix = true) + { + switch (j.type()) + { + case value_t::null: + { + if (add_prefix) + { + oa->write_character(to_char_type('Z')); + } + break; + } + + case value_t::boolean: + { + if (add_prefix) + { + oa->write_character(j.m_value.boolean + ? to_char_type('T') + : to_char_type('F')); + } + break; + } + + case value_t::number_integer: + { + write_number_with_ubjson_prefix(j.m_value.number_integer, add_prefix); + break; + } + + case value_t::number_unsigned: + { + write_number_with_ubjson_prefix(j.m_value.number_unsigned, add_prefix); + break; + } + + case value_t::number_float: + { + write_number_with_ubjson_prefix(j.m_value.number_float, add_prefix); + break; + } + + case value_t::string: + { + if (add_prefix) + { + oa->write_character(to_char_type('S')); + } + write_number_with_ubjson_prefix(j.m_value.string->size(), true); + oa->write_characters( + reinterpret_cast(j.m_value.string->c_str()), + j.m_value.string->size()); + break; + } + + case value_t::array: + { + if (add_prefix) + { + oa->write_character(to_char_type('[')); + } + + bool prefix_required = true; + if (use_type && !j.m_value.array->empty()) + { + JSON_ASSERT(use_count); + const CharType first_prefix = ubjson_prefix(j.front()); + const bool same_prefix = std::all_of(j.begin() + 1, j.end(), + [this, first_prefix](const BasicJsonType & v) + { + return ubjson_prefix(v) == first_prefix; + }); + + if (same_prefix) + { + prefix_required = false; + oa->write_character(to_char_type('$')); + oa->write_character(first_prefix); + } + } + + if (use_count) + { + oa->write_character(to_char_type('#')); + write_number_with_ubjson_prefix(j.m_value.array->size(), true); + } + + for (const auto& el : *j.m_value.array) + { + write_ubjson(el, use_count, use_type, prefix_required); + } + + if (!use_count) + { + oa->write_character(to_char_type(']')); + } + + break; + } + + case value_t::binary: + { + if (add_prefix) + { + oa->write_character(to_char_type('[')); + } + + if (use_type && !j.m_value.binary->empty()) + { + JSON_ASSERT(use_count); + oa->write_character(to_char_type('$')); + oa->write_character('U'); + } + + if (use_count) + { + oa->write_character(to_char_type('#')); + write_number_with_ubjson_prefix(j.m_value.binary->size(), true); + } + + if (use_type) + { + oa->write_characters( + reinterpret_cast(j.m_value.binary->data()), + j.m_value.binary->size()); + } + else + { + for (size_t i = 0; i < j.m_value.binary->size(); ++i) + { + oa->write_character(to_char_type('U')); + oa->write_character(j.m_value.binary->data()[i]); + } + } + + if (!use_count) + { + oa->write_character(to_char_type(']')); + } + + break; + } + + case value_t::object: + { + if (add_prefix) + { + oa->write_character(to_char_type('{')); + } + + bool prefix_required = true; + if (use_type && !j.m_value.object->empty()) + { + JSON_ASSERT(use_count); + const CharType first_prefix = ubjson_prefix(j.front()); + const bool same_prefix = std::all_of(j.begin(), j.end(), + [this, first_prefix](const BasicJsonType & v) + { + return ubjson_prefix(v) == first_prefix; + }); + + if (same_prefix) + { + prefix_required = false; + oa->write_character(to_char_type('$')); + oa->write_character(first_prefix); + } + } + + if (use_count) + { + oa->write_character(to_char_type('#')); + write_number_with_ubjson_prefix(j.m_value.object->size(), true); + } + + for (const auto& el : *j.m_value.object) + { + write_number_with_ubjson_prefix(el.first.size(), true); + oa->write_characters( + reinterpret_cast(el.first.c_str()), + el.first.size()); + write_ubjson(el.second, use_count, use_type, prefix_required); + } + + if (!use_count) + { + oa->write_character(to_char_type('}')); + } + + break; + } + + case value_t::discarded: + default: + break; + } + } + + private: + ////////// + // BSON // + ////////// + + /*! + @return The size of a BSON document entry header, including the id marker + and the entry name size (and its null-terminator). + */ + static std::size_t calc_bson_entry_header_size(const string_t& name, const BasicJsonType& j) + { + const auto it = name.find(static_cast(0)); + if (JSON_HEDLEY_UNLIKELY(it != BasicJsonType::string_t::npos)) + { + JSON_THROW(out_of_range::create(409, "BSON key cannot contain code point U+0000 (at byte " + std::to_string(it) + ")", j)); + static_cast(j); + } + + return /*id*/ 1ul + name.size() + /*zero-terminator*/1u; + } + + /*! + @brief Writes the given @a element_type and @a name to the output adapter + */ + void write_bson_entry_header(const string_t& name, + const std::uint8_t element_type) + { + oa->write_character(to_char_type(element_type)); // boolean + oa->write_characters( + reinterpret_cast(name.c_str()), + name.size() + 1u); + } + + /*! + @brief Writes a BSON element with key @a name and boolean value @a value + */ + void write_bson_boolean(const string_t& name, + const bool value) + { + write_bson_entry_header(name, 0x08); + oa->write_character(value ? to_char_type(0x01) : to_char_type(0x00)); + } + + /*! + @brief Writes a BSON element with key @a name and double value @a value + */ + void write_bson_double(const string_t& name, + const double value) + { + write_bson_entry_header(name, 0x01); + write_number(value); + } + + /*! + @return The size of the BSON-encoded string in @a value + */ + static std::size_t calc_bson_string_size(const string_t& value) + { + return sizeof(std::int32_t) + value.size() + 1ul; + } + + /*! + @brief Writes a BSON element with key @a name and string value @a value + */ + void write_bson_string(const string_t& name, + const string_t& value) + { + write_bson_entry_header(name, 0x02); + + write_number(static_cast(value.size() + 1ul)); + oa->write_characters( + reinterpret_cast(value.c_str()), + value.size() + 1); + } + + /*! + @brief Writes a BSON element with key @a name and null value + */ + void write_bson_null(const string_t& name) + { + write_bson_entry_header(name, 0x0A); + } + + /*! + @return The size of the BSON-encoded integer @a value + */ + static std::size_t calc_bson_integer_size(const std::int64_t value) + { + return (std::numeric_limits::min)() <= value && value <= (std::numeric_limits::max)() + ? sizeof(std::int32_t) + : sizeof(std::int64_t); + } + + /*! + @brief Writes a BSON element with key @a name and integer @a value + */ + void write_bson_integer(const string_t& name, + const std::int64_t value) + { + if ((std::numeric_limits::min)() <= value && value <= (std::numeric_limits::max)()) + { + write_bson_entry_header(name, 0x10); // int32 + write_number(static_cast(value)); + } + else + { + write_bson_entry_header(name, 0x12); // int64 + write_number(static_cast(value)); + } + } + + /*! + @return The size of the BSON-encoded unsigned integer in @a j + */ + static constexpr std::size_t calc_bson_unsigned_size(const std::uint64_t value) noexcept + { + return (value <= static_cast((std::numeric_limits::max)())) + ? sizeof(std::int32_t) + : sizeof(std::int64_t); + } + + /*! + @brief Writes a BSON element with key @a name and unsigned @a value + */ + void write_bson_unsigned(const string_t& name, + const BasicJsonType& j) + { + if (j.m_value.number_unsigned <= static_cast((std::numeric_limits::max)())) + { + write_bson_entry_header(name, 0x10 /* int32 */); + write_number(static_cast(j.m_value.number_unsigned)); + } + else if (j.m_value.number_unsigned <= static_cast((std::numeric_limits::max)())) + { + write_bson_entry_header(name, 0x12 /* int64 */); + write_number(static_cast(j.m_value.number_unsigned)); + } + else + { + JSON_THROW(out_of_range::create(407, "integer number " + std::to_string(j.m_value.number_unsigned) + " cannot be represented by BSON as it does not fit int64", j)); + } + } + + /*! + @brief Writes a BSON element with key @a name and object @a value + */ + void write_bson_object_entry(const string_t& name, + const typename BasicJsonType::object_t& value) + { + write_bson_entry_header(name, 0x03); // object + write_bson_object(value); + } + + /*! + @return The size of the BSON-encoded array @a value + */ + static std::size_t calc_bson_array_size(const typename BasicJsonType::array_t& value) + { + std::size_t array_index = 0ul; + + const std::size_t embedded_document_size = std::accumulate(std::begin(value), std::end(value), std::size_t(0), [&array_index](std::size_t result, const typename BasicJsonType::array_t::value_type & el) + { + return result + calc_bson_element_size(std::to_string(array_index++), el); + }); + + return sizeof(std::int32_t) + embedded_document_size + 1ul; + } + + /*! + @return The size of the BSON-encoded binary array @a value + */ + static std::size_t calc_bson_binary_size(const typename BasicJsonType::binary_t& value) + { + return sizeof(std::int32_t) + value.size() + 1ul; + } + + /*! + @brief Writes a BSON element with key @a name and array @a value + */ + void write_bson_array(const string_t& name, + const typename BasicJsonType::array_t& value) + { + write_bson_entry_header(name, 0x04); // array + write_number(static_cast(calc_bson_array_size(value))); + + std::size_t array_index = 0ul; + + for (const auto& el : value) + { + write_bson_element(std::to_string(array_index++), el); + } + + oa->write_character(to_char_type(0x00)); + } + + /*! + @brief Writes a BSON element with key @a name and binary value @a value + */ + void write_bson_binary(const string_t& name, + const binary_t& value) + { + write_bson_entry_header(name, 0x05); + + write_number(static_cast(value.size())); + write_number(value.has_subtype() ? static_cast(value.subtype()) : std::uint8_t(0x00)); + + oa->write_characters(reinterpret_cast(value.data()), value.size()); + } + + /*! + @brief Calculates the size necessary to serialize the JSON value @a j with its @a name + @return The calculated size for the BSON document entry for @a j with the given @a name. + */ + static std::size_t calc_bson_element_size(const string_t& name, + const BasicJsonType& j) + { + const auto header_size = calc_bson_entry_header_size(name, j); + switch (j.type()) + { + case value_t::object: + return header_size + calc_bson_object_size(*j.m_value.object); + + case value_t::array: + return header_size + calc_bson_array_size(*j.m_value.array); + + case value_t::binary: + return header_size + calc_bson_binary_size(*j.m_value.binary); + + case value_t::boolean: + return header_size + 1ul; + + case value_t::number_float: + return header_size + 8ul; + + case value_t::number_integer: + return header_size + calc_bson_integer_size(j.m_value.number_integer); + + case value_t::number_unsigned: + return header_size + calc_bson_unsigned_size(j.m_value.number_unsigned); + + case value_t::string: + return header_size + calc_bson_string_size(*j.m_value.string); + + case value_t::null: + return header_size + 0ul; + + // LCOV_EXCL_START + case value_t::discarded: + default: + JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) + return 0ul; + // LCOV_EXCL_STOP + } + } + + /*! + @brief Serializes the JSON value @a j to BSON and associates it with the + key @a name. + @param name The name to associate with the JSON entity @a j within the + current BSON document + */ + void write_bson_element(const string_t& name, + const BasicJsonType& j) + { + switch (j.type()) + { + case value_t::object: + return write_bson_object_entry(name, *j.m_value.object); + + case value_t::array: + return write_bson_array(name, *j.m_value.array); + + case value_t::binary: + return write_bson_binary(name, *j.m_value.binary); + + case value_t::boolean: + return write_bson_boolean(name, j.m_value.boolean); + + case value_t::number_float: + return write_bson_double(name, j.m_value.number_float); + + case value_t::number_integer: + return write_bson_integer(name, j.m_value.number_integer); + + case value_t::number_unsigned: + return write_bson_unsigned(name, j); + + case value_t::string: + return write_bson_string(name, *j.m_value.string); + + case value_t::null: + return write_bson_null(name); + + // LCOV_EXCL_START + case value_t::discarded: + default: + JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) + return; + // LCOV_EXCL_STOP + } + } + + /*! + @brief Calculates the size of the BSON serialization of the given + JSON-object @a j. + @param[in] value JSON value to serialize + @pre value.type() == value_t::object + */ + static std::size_t calc_bson_object_size(const typename BasicJsonType::object_t& value) + { + std::size_t document_size = std::accumulate(value.begin(), value.end(), std::size_t(0), + [](size_t result, const typename BasicJsonType::object_t::value_type & el) + { + return result += calc_bson_element_size(el.first, el.second); + }); + + return sizeof(std::int32_t) + document_size + 1ul; + } + + /*! + @param[in] value JSON value to serialize + @pre value.type() == value_t::object + */ + void write_bson_object(const typename BasicJsonType::object_t& value) + { + write_number(static_cast(calc_bson_object_size(value))); + + for (const auto& el : value) + { + write_bson_element(el.first, el.second); + } + + oa->write_character(to_char_type(0x00)); + } + + ////////// + // CBOR // + ////////// + + static constexpr CharType get_cbor_float_prefix(float /*unused*/) + { + return to_char_type(0xFA); // Single-Precision Float + } + + static constexpr CharType get_cbor_float_prefix(double /*unused*/) + { + return to_char_type(0xFB); // Double-Precision Float + } + + ///////////// + // MsgPack // + ///////////// + + static constexpr CharType get_msgpack_float_prefix(float /*unused*/) + { + return to_char_type(0xCA); // float 32 + } + + static constexpr CharType get_msgpack_float_prefix(double /*unused*/) + { + return to_char_type(0xCB); // float 64 + } + + //////////// + // UBJSON // + //////////// + + // UBJSON: write number (floating point) + template::value, int>::type = 0> + void write_number_with_ubjson_prefix(const NumberType n, + const bool add_prefix) + { + if (add_prefix) + { + oa->write_character(get_ubjson_float_prefix(n)); + } + write_number(n); + } + + // UBJSON: write number (unsigned integer) + template::value, int>::type = 0> + void write_number_with_ubjson_prefix(const NumberType n, + const bool add_prefix) + { + if (n <= static_cast((std::numeric_limits::max)())) + { + if (add_prefix) + { + oa->write_character(to_char_type('i')); // int8 + } + write_number(static_cast(n)); + } + else if (n <= (std::numeric_limits::max)()) + { + if (add_prefix) + { + oa->write_character(to_char_type('U')); // uint8 + } + write_number(static_cast(n)); + } + else if (n <= static_cast((std::numeric_limits::max)())) + { + if (add_prefix) + { + oa->write_character(to_char_type('I')); // int16 + } + write_number(static_cast(n)); + } + else if (n <= static_cast((std::numeric_limits::max)())) + { + if (add_prefix) + { + oa->write_character(to_char_type('l')); // int32 + } + write_number(static_cast(n)); + } + else if (n <= static_cast((std::numeric_limits::max)())) + { + if (add_prefix) + { + oa->write_character(to_char_type('L')); // int64 + } + write_number(static_cast(n)); + } + else + { + if (add_prefix) + { + oa->write_character(to_char_type('H')); // high-precision number + } + + const auto number = BasicJsonType(n).dump(); + write_number_with_ubjson_prefix(number.size(), true); + for (std::size_t i = 0; i < number.size(); ++i) + { + oa->write_character(to_char_type(static_cast(number[i]))); + } + } + } + + // UBJSON: write number (signed integer) + template < typename NumberType, typename std::enable_if < + std::is_signed::value&& + !std::is_floating_point::value, int >::type = 0 > + void write_number_with_ubjson_prefix(const NumberType n, + const bool add_prefix) + { + if ((std::numeric_limits::min)() <= n && n <= (std::numeric_limits::max)()) + { + if (add_prefix) + { + oa->write_character(to_char_type('i')); // int8 + } + write_number(static_cast(n)); + } + else if (static_cast((std::numeric_limits::min)()) <= n && n <= static_cast((std::numeric_limits::max)())) + { + if (add_prefix) + { + oa->write_character(to_char_type('U')); // uint8 + } + write_number(static_cast(n)); + } + else if ((std::numeric_limits::min)() <= n && n <= (std::numeric_limits::max)()) + { + if (add_prefix) + { + oa->write_character(to_char_type('I')); // int16 + } + write_number(static_cast(n)); + } + else if ((std::numeric_limits::min)() <= n && n <= (std::numeric_limits::max)()) + { + if (add_prefix) + { + oa->write_character(to_char_type('l')); // int32 + } + write_number(static_cast(n)); + } + else if ((std::numeric_limits::min)() <= n && n <= (std::numeric_limits::max)()) + { + if (add_prefix) + { + oa->write_character(to_char_type('L')); // int64 + } + write_number(static_cast(n)); + } + // LCOV_EXCL_START + else + { + if (add_prefix) + { + oa->write_character(to_char_type('H')); // high-precision number + } + + const auto number = BasicJsonType(n).dump(); + write_number_with_ubjson_prefix(number.size(), true); + for (std::size_t i = 0; i < number.size(); ++i) + { + oa->write_character(to_char_type(static_cast(number[i]))); + } + } + // LCOV_EXCL_STOP + } + + /*! + @brief determine the type prefix of container values + */ + CharType ubjson_prefix(const BasicJsonType& j) const noexcept + { + switch (j.type()) + { + case value_t::null: + return 'Z'; + + case value_t::boolean: + return j.m_value.boolean ? 'T' : 'F'; + + case value_t::number_integer: + { + if ((std::numeric_limits::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits::max)()) + { + return 'i'; + } + if ((std::numeric_limits::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits::max)()) + { + return 'U'; + } + if ((std::numeric_limits::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits::max)()) + { + return 'I'; + } + if ((std::numeric_limits::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits::max)()) + { + return 'l'; + } + if ((std::numeric_limits::min)() <= j.m_value.number_integer && j.m_value.number_integer <= (std::numeric_limits::max)()) + { + return 'L'; + } + // anything else is treated as high-precision number + return 'H'; // LCOV_EXCL_LINE + } + + case value_t::number_unsigned: + { + if (j.m_value.number_unsigned <= static_cast((std::numeric_limits::max)())) + { + return 'i'; + } + if (j.m_value.number_unsigned <= static_cast((std::numeric_limits::max)())) + { + return 'U'; + } + if (j.m_value.number_unsigned <= static_cast((std::numeric_limits::max)())) + { + return 'I'; + } + if (j.m_value.number_unsigned <= static_cast((std::numeric_limits::max)())) + { + return 'l'; + } + if (j.m_value.number_unsigned <= static_cast((std::numeric_limits::max)())) + { + return 'L'; + } + // anything else is treated as high-precision number + return 'H'; // LCOV_EXCL_LINE + } + + case value_t::number_float: + return get_ubjson_float_prefix(j.m_value.number_float); + + case value_t::string: + return 'S'; + + case value_t::array: // fallthrough + case value_t::binary: + return '['; + + case value_t::object: + return '{'; + + case value_t::discarded: + default: // discarded values + return 'N'; + } + } + + static constexpr CharType get_ubjson_float_prefix(float /*unused*/) + { + return 'd'; // float 32 + } + + static constexpr CharType get_ubjson_float_prefix(double /*unused*/) + { + return 'D'; // float 64 + } + + /////////////////////// + // Utility functions // + /////////////////////// + + /* + @brief write a number to output input + @param[in] n number of type @a NumberType + @tparam NumberType the type of the number + @tparam OutputIsLittleEndian Set to true if output data is + required to be little endian + + @note This function needs to respect the system's endianess, because bytes + in CBOR, MessagePack, and UBJSON are stored in network order (big + endian) and therefore need reordering on little endian systems. + */ + template + void write_number(const NumberType n) + { + // step 1: write number to array of length NumberType + std::array vec{}; + std::memcpy(vec.data(), &n, sizeof(NumberType)); + + // step 2: write array to output (with possible reordering) + if (is_little_endian != OutputIsLittleEndian) + { + // reverse byte order prior to conversion if necessary + std::reverse(vec.begin(), vec.end()); + } + + oa->write_characters(vec.data(), sizeof(NumberType)); + } + + void write_compact_float(const number_float_t n, detail::input_format_t format) + { +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wfloat-equal" +#endif + if (static_cast(n) >= static_cast(std::numeric_limits::lowest()) && + static_cast(n) <= static_cast((std::numeric_limits::max)()) && + static_cast(static_cast(n)) == static_cast(n)) + { + oa->write_character(format == detail::input_format_t::cbor + ? get_cbor_float_prefix(static_cast(n)) + : get_msgpack_float_prefix(static_cast(n))); + write_number(static_cast(n)); + } + else + { + oa->write_character(format == detail::input_format_t::cbor + ? get_cbor_float_prefix(n) + : get_msgpack_float_prefix(n)); + write_number(n); + } +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + } + + public: + // The following to_char_type functions are implement the conversion + // between uint8_t and CharType. In case CharType is not unsigned, + // such a conversion is required to allow values greater than 128. + // See for a discussion. + template < typename C = CharType, + enable_if_t < std::is_signed::value && std::is_signed::value > * = nullptr > + static constexpr CharType to_char_type(std::uint8_t x) noexcept + { + return *reinterpret_cast(&x); + } + + template < typename C = CharType, + enable_if_t < std::is_signed::value && std::is_unsigned::value > * = nullptr > + static CharType to_char_type(std::uint8_t x) noexcept + { + static_assert(sizeof(std::uint8_t) == sizeof(CharType), "size of CharType must be equal to std::uint8_t"); + static_assert(std::is_trivial::value, "CharType must be trivial"); + CharType result; + std::memcpy(&result, &x, sizeof(x)); + return result; + } + + template::value>* = nullptr> + static constexpr CharType to_char_type(std::uint8_t x) noexcept + { + return x; + } + + template < typename InputCharType, typename C = CharType, + enable_if_t < + std::is_signed::value && + std::is_signed::value && + std::is_same::type>::value + > * = nullptr > + static constexpr CharType to_char_type(InputCharType x) noexcept + { + return x; + } + + private: + /// whether we can assume little endianess + const bool is_little_endian = little_endianess(); + + /// the output + output_adapter_t oa = nullptr; +}; +} // namespace detail +} // namespace nlohmann + +// #include + +// #include + + +#include // reverse, remove, fill, find, none_of +#include // array +#include // localeconv, lconv +#include // labs, isfinite, isnan, signbit +#include // size_t, ptrdiff_t +#include // uint8_t +#include // snprintf +#include // numeric_limits +#include // string, char_traits +#include // is_same +#include // move + +// #include + + +#include // array +#include // signbit, isfinite +#include // intN_t, uintN_t +#include // memcpy, memmove +#include // numeric_limits +#include // conditional + +// #include + + +namespace nlohmann +{ +namespace detail +{ + +/*! +@brief implements the Grisu2 algorithm for binary to decimal floating-point +conversion. + +This implementation is a slightly modified version of the reference +implementation which may be obtained from +http://florian.loitsch.com/publications (bench.tar.gz). + +The code is distributed under the MIT license, Copyright (c) 2009 Florian Loitsch. + +For a detailed description of the algorithm see: + +[1] Loitsch, "Printing Floating-Point Numbers Quickly and Accurately with + Integers", Proceedings of the ACM SIGPLAN 2010 Conference on Programming + Language Design and Implementation, PLDI 2010 +[2] Burger, Dybvig, "Printing Floating-Point Numbers Quickly and Accurately", + Proceedings of the ACM SIGPLAN 1996 Conference on Programming Language + Design and Implementation, PLDI 1996 +*/ +namespace dtoa_impl +{ + +template +Target reinterpret_bits(const Source source) +{ + static_assert(sizeof(Target) == sizeof(Source), "size mismatch"); + + Target target; + std::memcpy(&target, &source, sizeof(Source)); + return target; +} + +struct diyfp // f * 2^e +{ + static constexpr int kPrecision = 64; // = q + + std::uint64_t f = 0; + int e = 0; + + constexpr diyfp(std::uint64_t f_, int e_) noexcept : f(f_), e(e_) {} + + /*! + @brief returns x - y + @pre x.e == y.e and x.f >= y.f + */ + static diyfp sub(const diyfp& x, const diyfp& y) noexcept + { + JSON_ASSERT(x.e == y.e); + JSON_ASSERT(x.f >= y.f); + + return {x.f - y.f, x.e}; + } + + /*! + @brief returns x * y + @note The result is rounded. (Only the upper q bits are returned.) + */ + static diyfp mul(const diyfp& x, const diyfp& y) noexcept + { + static_assert(kPrecision == 64, "internal error"); + + // Computes: + // f = round((x.f * y.f) / 2^q) + // e = x.e + y.e + q + + // Emulate the 64-bit * 64-bit multiplication: + // + // p = u * v + // = (u_lo + 2^32 u_hi) (v_lo + 2^32 v_hi) + // = (u_lo v_lo ) + 2^32 ((u_lo v_hi ) + (u_hi v_lo )) + 2^64 (u_hi v_hi ) + // = (p0 ) + 2^32 ((p1 ) + (p2 )) + 2^64 (p3 ) + // = (p0_lo + 2^32 p0_hi) + 2^32 ((p1_lo + 2^32 p1_hi) + (p2_lo + 2^32 p2_hi)) + 2^64 (p3 ) + // = (p0_lo ) + 2^32 (p0_hi + p1_lo + p2_lo ) + 2^64 (p1_hi + p2_hi + p3) + // = (p0_lo ) + 2^32 (Q ) + 2^64 (H ) + // = (p0_lo ) + 2^32 (Q_lo + 2^32 Q_hi ) + 2^64 (H ) + // + // (Since Q might be larger than 2^32 - 1) + // + // = (p0_lo + 2^32 Q_lo) + 2^64 (Q_hi + H) + // + // (Q_hi + H does not overflow a 64-bit int) + // + // = p_lo + 2^64 p_hi + + const std::uint64_t u_lo = x.f & 0xFFFFFFFFu; + const std::uint64_t u_hi = x.f >> 32u; + const std::uint64_t v_lo = y.f & 0xFFFFFFFFu; + const std::uint64_t v_hi = y.f >> 32u; + + const std::uint64_t p0 = u_lo * v_lo; + const std::uint64_t p1 = u_lo * v_hi; + const std::uint64_t p2 = u_hi * v_lo; + const std::uint64_t p3 = u_hi * v_hi; + + const std::uint64_t p0_hi = p0 >> 32u; + const std::uint64_t p1_lo = p1 & 0xFFFFFFFFu; + const std::uint64_t p1_hi = p1 >> 32u; + const std::uint64_t p2_lo = p2 & 0xFFFFFFFFu; + const std::uint64_t p2_hi = p2 >> 32u; + + std::uint64_t Q = p0_hi + p1_lo + p2_lo; + + // The full product might now be computed as + // + // p_hi = p3 + p2_hi + p1_hi + (Q >> 32) + // p_lo = p0_lo + (Q << 32) + // + // But in this particular case here, the full p_lo is not required. + // Effectively we only need to add the highest bit in p_lo to p_hi (and + // Q_hi + 1 does not overflow). + + Q += std::uint64_t{1} << (64u - 32u - 1u); // round, ties up + + const std::uint64_t h = p3 + p2_hi + p1_hi + (Q >> 32u); + + return {h, x.e + y.e + 64}; + } + + /*! + @brief normalize x such that the significand is >= 2^(q-1) + @pre x.f != 0 + */ + static diyfp normalize(diyfp x) noexcept + { + JSON_ASSERT(x.f != 0); + + while ((x.f >> 63u) == 0) + { + x.f <<= 1u; + x.e--; + } + + return x; + } + + /*! + @brief normalize x such that the result has the exponent E + @pre e >= x.e and the upper e - x.e bits of x.f must be zero. + */ + static diyfp normalize_to(const diyfp& x, const int target_exponent) noexcept + { + const int delta = x.e - target_exponent; + + JSON_ASSERT(delta >= 0); + JSON_ASSERT(((x.f << delta) >> delta) == x.f); + + return {x.f << delta, target_exponent}; + } +}; + +struct boundaries +{ + diyfp w; + diyfp minus; + diyfp plus; +}; + +/*! +Compute the (normalized) diyfp representing the input number 'value' and its +boundaries. + +@pre value must be finite and positive +*/ +template +boundaries compute_boundaries(FloatType value) +{ + JSON_ASSERT(std::isfinite(value)); + JSON_ASSERT(value > 0); + + // Convert the IEEE representation into a diyfp. + // + // If v is denormal: + // value = 0.F * 2^(1 - bias) = ( F) * 2^(1 - bias - (p-1)) + // If v is normalized: + // value = 1.F * 2^(E - bias) = (2^(p-1) + F) * 2^(E - bias - (p-1)) + + static_assert(std::numeric_limits::is_iec559, + "internal error: dtoa_short requires an IEEE-754 floating-point implementation"); + + constexpr int kPrecision = std::numeric_limits::digits; // = p (includes the hidden bit) + constexpr int kBias = std::numeric_limits::max_exponent - 1 + (kPrecision - 1); + constexpr int kMinExp = 1 - kBias; + constexpr std::uint64_t kHiddenBit = std::uint64_t{1} << (kPrecision - 1); // = 2^(p-1) + + using bits_type = typename std::conditional::type; + + const auto bits = static_cast(reinterpret_bits(value)); + const std::uint64_t E = bits >> (kPrecision - 1); + const std::uint64_t F = bits & (kHiddenBit - 1); + + const bool is_denormal = E == 0; + const diyfp v = is_denormal + ? diyfp(F, kMinExp) + : diyfp(F + kHiddenBit, static_cast(E) - kBias); + + // Compute the boundaries m- and m+ of the floating-point value + // v = f * 2^e. + // + // Determine v- and v+, the floating-point predecessor and successor if v, + // respectively. + // + // v- = v - 2^e if f != 2^(p-1) or e == e_min (A) + // = v - 2^(e-1) if f == 2^(p-1) and e > e_min (B) + // + // v+ = v + 2^e + // + // Let m- = (v- + v) / 2 and m+ = (v + v+) / 2. All real numbers _strictly_ + // between m- and m+ round to v, regardless of how the input rounding + // algorithm breaks ties. + // + // ---+-------------+-------------+-------------+-------------+--- (A) + // v- m- v m+ v+ + // + // -----------------+------+------+-------------+-------------+--- (B) + // v- m- v m+ v+ + + const bool lower_boundary_is_closer = F == 0 && E > 1; + const diyfp m_plus = diyfp(2 * v.f + 1, v.e - 1); + const diyfp m_minus = lower_boundary_is_closer + ? diyfp(4 * v.f - 1, v.e - 2) // (B) + : diyfp(2 * v.f - 1, v.e - 1); // (A) + + // Determine the normalized w+ = m+. + const diyfp w_plus = diyfp::normalize(m_plus); + + // Determine w- = m- such that e_(w-) = e_(w+). + const diyfp w_minus = diyfp::normalize_to(m_minus, w_plus.e); + + return {diyfp::normalize(v), w_minus, w_plus}; +} + +// Given normalized diyfp w, Grisu needs to find a (normalized) cached +// power-of-ten c, such that the exponent of the product c * w = f * 2^e lies +// within a certain range [alpha, gamma] (Definition 3.2 from [1]) +// +// alpha <= e = e_c + e_w + q <= gamma +// +// or +// +// f_c * f_w * 2^alpha <= f_c 2^(e_c) * f_w 2^(e_w) * 2^q +// <= f_c * f_w * 2^gamma +// +// Since c and w are normalized, i.e. 2^(q-1) <= f < 2^q, this implies +// +// 2^(q-1) * 2^(q-1) * 2^alpha <= c * w * 2^q < 2^q * 2^q * 2^gamma +// +// or +// +// 2^(q - 2 + alpha) <= c * w < 2^(q + gamma) +// +// The choice of (alpha,gamma) determines the size of the table and the form of +// the digit generation procedure. Using (alpha,gamma)=(-60,-32) works out well +// in practice: +// +// The idea is to cut the number c * w = f * 2^e into two parts, which can be +// processed independently: An integral part p1, and a fractional part p2: +// +// f * 2^e = ( (f div 2^-e) * 2^-e + (f mod 2^-e) ) * 2^e +// = (f div 2^-e) + (f mod 2^-e) * 2^e +// = p1 + p2 * 2^e +// +// The conversion of p1 into decimal form requires a series of divisions and +// modulos by (a power of) 10. These operations are faster for 32-bit than for +// 64-bit integers, so p1 should ideally fit into a 32-bit integer. This can be +// achieved by choosing +// +// -e >= 32 or e <= -32 := gamma +// +// In order to convert the fractional part +// +// p2 * 2^e = p2 / 2^-e = d[-1] / 10^1 + d[-2] / 10^2 + ... +// +// into decimal form, the fraction is repeatedly multiplied by 10 and the digits +// d[-i] are extracted in order: +// +// (10 * p2) div 2^-e = d[-1] +// (10 * p2) mod 2^-e = d[-2] / 10^1 + ... +// +// The multiplication by 10 must not overflow. It is sufficient to choose +// +// 10 * p2 < 16 * p2 = 2^4 * p2 <= 2^64. +// +// Since p2 = f mod 2^-e < 2^-e, +// +// -e <= 60 or e >= -60 := alpha + +constexpr int kAlpha = -60; +constexpr int kGamma = -32; + +struct cached_power // c = f * 2^e ~= 10^k +{ + std::uint64_t f; + int e; + int k; +}; + +/*! +For a normalized diyfp w = f * 2^e, this function returns a (normalized) cached +power-of-ten c = f_c * 2^e_c, such that the exponent of the product w * c +satisfies (Definition 3.2 from [1]) + + alpha <= e_c + e + q <= gamma. +*/ +inline cached_power get_cached_power_for_binary_exponent(int e) +{ + // Now + // + // alpha <= e_c + e + q <= gamma (1) + // ==> f_c * 2^alpha <= c * 2^e * 2^q + // + // and since the c's are normalized, 2^(q-1) <= f_c, + // + // ==> 2^(q - 1 + alpha) <= c * 2^(e + q) + // ==> 2^(alpha - e - 1) <= c + // + // If c were an exact power of ten, i.e. c = 10^k, one may determine k as + // + // k = ceil( log_10( 2^(alpha - e - 1) ) ) + // = ceil( (alpha - e - 1) * log_10(2) ) + // + // From the paper: + // "In theory the result of the procedure could be wrong since c is rounded, + // and the computation itself is approximated [...]. In practice, however, + // this simple function is sufficient." + // + // For IEEE double precision floating-point numbers converted into + // normalized diyfp's w = f * 2^e, with q = 64, + // + // e >= -1022 (min IEEE exponent) + // -52 (p - 1) + // -52 (p - 1, possibly normalize denormal IEEE numbers) + // -11 (normalize the diyfp) + // = -1137 + // + // and + // + // e <= +1023 (max IEEE exponent) + // -52 (p - 1) + // -11 (normalize the diyfp) + // = 960 + // + // This binary exponent range [-1137,960] results in a decimal exponent + // range [-307,324]. One does not need to store a cached power for each + // k in this range. For each such k it suffices to find a cached power + // such that the exponent of the product lies in [alpha,gamma]. + // This implies that the difference of the decimal exponents of adjacent + // table entries must be less than or equal to + // + // floor( (gamma - alpha) * log_10(2) ) = 8. + // + // (A smaller distance gamma-alpha would require a larger table.) + + // NB: + // Actually this function returns c, such that -60 <= e_c + e + 64 <= -34. + + constexpr int kCachedPowersMinDecExp = -300; + constexpr int kCachedPowersDecStep = 8; + + static constexpr std::array kCachedPowers = + { + { + { 0xAB70FE17C79AC6CA, -1060, -300 }, + { 0xFF77B1FCBEBCDC4F, -1034, -292 }, + { 0xBE5691EF416BD60C, -1007, -284 }, + { 0x8DD01FAD907FFC3C, -980, -276 }, + { 0xD3515C2831559A83, -954, -268 }, + { 0x9D71AC8FADA6C9B5, -927, -260 }, + { 0xEA9C227723EE8BCB, -901, -252 }, + { 0xAECC49914078536D, -874, -244 }, + { 0x823C12795DB6CE57, -847, -236 }, + { 0xC21094364DFB5637, -821, -228 }, + { 0x9096EA6F3848984F, -794, -220 }, + { 0xD77485CB25823AC7, -768, -212 }, + { 0xA086CFCD97BF97F4, -741, -204 }, + { 0xEF340A98172AACE5, -715, -196 }, + { 0xB23867FB2A35B28E, -688, -188 }, + { 0x84C8D4DFD2C63F3B, -661, -180 }, + { 0xC5DD44271AD3CDBA, -635, -172 }, + { 0x936B9FCEBB25C996, -608, -164 }, + { 0xDBAC6C247D62A584, -582, -156 }, + { 0xA3AB66580D5FDAF6, -555, -148 }, + { 0xF3E2F893DEC3F126, -529, -140 }, + { 0xB5B5ADA8AAFF80B8, -502, -132 }, + { 0x87625F056C7C4A8B, -475, -124 }, + { 0xC9BCFF6034C13053, -449, -116 }, + { 0x964E858C91BA2655, -422, -108 }, + { 0xDFF9772470297EBD, -396, -100 }, + { 0xA6DFBD9FB8E5B88F, -369, -92 }, + { 0xF8A95FCF88747D94, -343, -84 }, + { 0xB94470938FA89BCF, -316, -76 }, + { 0x8A08F0F8BF0F156B, -289, -68 }, + { 0xCDB02555653131B6, -263, -60 }, + { 0x993FE2C6D07B7FAC, -236, -52 }, + { 0xE45C10C42A2B3B06, -210, -44 }, + { 0xAA242499697392D3, -183, -36 }, + { 0xFD87B5F28300CA0E, -157, -28 }, + { 0xBCE5086492111AEB, -130, -20 }, + { 0x8CBCCC096F5088CC, -103, -12 }, + { 0xD1B71758E219652C, -77, -4 }, + { 0x9C40000000000000, -50, 4 }, + { 0xE8D4A51000000000, -24, 12 }, + { 0xAD78EBC5AC620000, 3, 20 }, + { 0x813F3978F8940984, 30, 28 }, + { 0xC097CE7BC90715B3, 56, 36 }, + { 0x8F7E32CE7BEA5C70, 83, 44 }, + { 0xD5D238A4ABE98068, 109, 52 }, + { 0x9F4F2726179A2245, 136, 60 }, + { 0xED63A231D4C4FB27, 162, 68 }, + { 0xB0DE65388CC8ADA8, 189, 76 }, + { 0x83C7088E1AAB65DB, 216, 84 }, + { 0xC45D1DF942711D9A, 242, 92 }, + { 0x924D692CA61BE758, 269, 100 }, + { 0xDA01EE641A708DEA, 295, 108 }, + { 0xA26DA3999AEF774A, 322, 116 }, + { 0xF209787BB47D6B85, 348, 124 }, + { 0xB454E4A179DD1877, 375, 132 }, + { 0x865B86925B9BC5C2, 402, 140 }, + { 0xC83553C5C8965D3D, 428, 148 }, + { 0x952AB45CFA97A0B3, 455, 156 }, + { 0xDE469FBD99A05FE3, 481, 164 }, + { 0xA59BC234DB398C25, 508, 172 }, + { 0xF6C69A72A3989F5C, 534, 180 }, + { 0xB7DCBF5354E9BECE, 561, 188 }, + { 0x88FCF317F22241E2, 588, 196 }, + { 0xCC20CE9BD35C78A5, 614, 204 }, + { 0x98165AF37B2153DF, 641, 212 }, + { 0xE2A0B5DC971F303A, 667, 220 }, + { 0xA8D9D1535CE3B396, 694, 228 }, + { 0xFB9B7CD9A4A7443C, 720, 236 }, + { 0xBB764C4CA7A44410, 747, 244 }, + { 0x8BAB8EEFB6409C1A, 774, 252 }, + { 0xD01FEF10A657842C, 800, 260 }, + { 0x9B10A4E5E9913129, 827, 268 }, + { 0xE7109BFBA19C0C9D, 853, 276 }, + { 0xAC2820D9623BF429, 880, 284 }, + { 0x80444B5E7AA7CF85, 907, 292 }, + { 0xBF21E44003ACDD2D, 933, 300 }, + { 0x8E679C2F5E44FF8F, 960, 308 }, + { 0xD433179D9C8CB841, 986, 316 }, + { 0x9E19DB92B4E31BA9, 1013, 324 }, + } + }; + + // This computation gives exactly the same results for k as + // k = ceil((kAlpha - e - 1) * 0.30102999566398114) + // for |e| <= 1500, but doesn't require floating-point operations. + // NB: log_10(2) ~= 78913 / 2^18 + JSON_ASSERT(e >= -1500); + JSON_ASSERT(e <= 1500); + const int f = kAlpha - e - 1; + const int k = (f * 78913) / (1 << 18) + static_cast(f > 0); + + const int index = (-kCachedPowersMinDecExp + k + (kCachedPowersDecStep - 1)) / kCachedPowersDecStep; + JSON_ASSERT(index >= 0); + JSON_ASSERT(static_cast(index) < kCachedPowers.size()); + + const cached_power cached = kCachedPowers[static_cast(index)]; + JSON_ASSERT(kAlpha <= cached.e + e + 64); + JSON_ASSERT(kGamma >= cached.e + e + 64); + + return cached; +} + +/*! +For n != 0, returns k, such that pow10 := 10^(k-1) <= n < 10^k. +For n == 0, returns 1 and sets pow10 := 1. +*/ +inline int find_largest_pow10(const std::uint32_t n, std::uint32_t& pow10) +{ + // LCOV_EXCL_START + if (n >= 1000000000) + { + pow10 = 1000000000; + return 10; + } + // LCOV_EXCL_STOP + if (n >= 100000000) + { + pow10 = 100000000; + return 9; + } + if (n >= 10000000) + { + pow10 = 10000000; + return 8; + } + if (n >= 1000000) + { + pow10 = 1000000; + return 7; + } + if (n >= 100000) + { + pow10 = 100000; + return 6; + } + if (n >= 10000) + { + pow10 = 10000; + return 5; + } + if (n >= 1000) + { + pow10 = 1000; + return 4; + } + if (n >= 100) + { + pow10 = 100; + return 3; + } + if (n >= 10) + { + pow10 = 10; + return 2; + } + + pow10 = 1; + return 1; +} + +inline void grisu2_round(char* buf, int len, std::uint64_t dist, std::uint64_t delta, + std::uint64_t rest, std::uint64_t ten_k) +{ + JSON_ASSERT(len >= 1); + JSON_ASSERT(dist <= delta); + JSON_ASSERT(rest <= delta); + JSON_ASSERT(ten_k > 0); + + // <--------------------------- delta ----> + // <---- dist ---------> + // --------------[------------------+-------------------]-------------- + // M- w M+ + // + // ten_k + // <------> + // <---- rest ----> + // --------------[------------------+----+--------------]-------------- + // w V + // = buf * 10^k + // + // ten_k represents a unit-in-the-last-place in the decimal representation + // stored in buf. + // Decrement buf by ten_k while this takes buf closer to w. + + // The tests are written in this order to avoid overflow in unsigned + // integer arithmetic. + + while (rest < dist + && delta - rest >= ten_k + && (rest + ten_k < dist || dist - rest > rest + ten_k - dist)) + { + JSON_ASSERT(buf[len - 1] != '0'); + buf[len - 1]--; + rest += ten_k; + } +} + +/*! +Generates V = buffer * 10^decimal_exponent, such that M- <= V <= M+. +M- and M+ must be normalized and share the same exponent -60 <= e <= -32. +*/ +inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent, + diyfp M_minus, diyfp w, diyfp M_plus) +{ + static_assert(kAlpha >= -60, "internal error"); + static_assert(kGamma <= -32, "internal error"); + + // Generates the digits (and the exponent) of a decimal floating-point + // number V = buffer * 10^decimal_exponent in the range [M-, M+]. The diyfp's + // w, M- and M+ share the same exponent e, which satisfies alpha <= e <= gamma. + // + // <--------------------------- delta ----> + // <---- dist ---------> + // --------------[------------------+-------------------]-------------- + // M- w M+ + // + // Grisu2 generates the digits of M+ from left to right and stops as soon as + // V is in [M-,M+]. + + JSON_ASSERT(M_plus.e >= kAlpha); + JSON_ASSERT(M_plus.e <= kGamma); + + std::uint64_t delta = diyfp::sub(M_plus, M_minus).f; // (significand of (M+ - M-), implicit exponent is e) + std::uint64_t dist = diyfp::sub(M_plus, w ).f; // (significand of (M+ - w ), implicit exponent is e) + + // Split M+ = f * 2^e into two parts p1 and p2 (note: e < 0): + // + // M+ = f * 2^e + // = ((f div 2^-e) * 2^-e + (f mod 2^-e)) * 2^e + // = ((p1 ) * 2^-e + (p2 )) * 2^e + // = p1 + p2 * 2^e + + const diyfp one(std::uint64_t{1} << -M_plus.e, M_plus.e); + + auto p1 = static_cast(M_plus.f >> -one.e); // p1 = f div 2^-e (Since -e >= 32, p1 fits into a 32-bit int.) + std::uint64_t p2 = M_plus.f & (one.f - 1); // p2 = f mod 2^-e + + // 1) + // + // Generate the digits of the integral part p1 = d[n-1]...d[1]d[0] + + JSON_ASSERT(p1 > 0); + + std::uint32_t pow10{}; + const int k = find_largest_pow10(p1, pow10); + + // 10^(k-1) <= p1 < 10^k, pow10 = 10^(k-1) + // + // p1 = (p1 div 10^(k-1)) * 10^(k-1) + (p1 mod 10^(k-1)) + // = (d[k-1] ) * 10^(k-1) + (p1 mod 10^(k-1)) + // + // M+ = p1 + p2 * 2^e + // = d[k-1] * 10^(k-1) + (p1 mod 10^(k-1)) + p2 * 2^e + // = d[k-1] * 10^(k-1) + ((p1 mod 10^(k-1)) * 2^-e + p2) * 2^e + // = d[k-1] * 10^(k-1) + ( rest) * 2^e + // + // Now generate the digits d[n] of p1 from left to right (n = k-1,...,0) + // + // p1 = d[k-1]...d[n] * 10^n + d[n-1]...d[0] + // + // but stop as soon as + // + // rest * 2^e = (d[n-1]...d[0] * 2^-e + p2) * 2^e <= delta * 2^e + + int n = k; + while (n > 0) + { + // Invariants: + // M+ = buffer * 10^n + (p1 + p2 * 2^e) (buffer = 0 for n = k) + // pow10 = 10^(n-1) <= p1 < 10^n + // + const std::uint32_t d = p1 / pow10; // d = p1 div 10^(n-1) + const std::uint32_t r = p1 % pow10; // r = p1 mod 10^(n-1) + // + // M+ = buffer * 10^n + (d * 10^(n-1) + r) + p2 * 2^e + // = (buffer * 10 + d) * 10^(n-1) + (r + p2 * 2^e) + // + JSON_ASSERT(d <= 9); + buffer[length++] = static_cast('0' + d); // buffer := buffer * 10 + d + // + // M+ = buffer * 10^(n-1) + (r + p2 * 2^e) + // + p1 = r; + n--; + // + // M+ = buffer * 10^n + (p1 + p2 * 2^e) + // pow10 = 10^n + // + + // Now check if enough digits have been generated. + // Compute + // + // p1 + p2 * 2^e = (p1 * 2^-e + p2) * 2^e = rest * 2^e + // + // Note: + // Since rest and delta share the same exponent e, it suffices to + // compare the significands. + const std::uint64_t rest = (std::uint64_t{p1} << -one.e) + p2; + if (rest <= delta) + { + // V = buffer * 10^n, with M- <= V <= M+. + + decimal_exponent += n; + + // We may now just stop. But instead look if the buffer could be + // decremented to bring V closer to w. + // + // pow10 = 10^n is now 1 ulp in the decimal representation V. + // The rounding procedure works with diyfp's with an implicit + // exponent of e. + // + // 10^n = (10^n * 2^-e) * 2^e = ulp * 2^e + // + const std::uint64_t ten_n = std::uint64_t{pow10} << -one.e; + grisu2_round(buffer, length, dist, delta, rest, ten_n); + + return; + } + + pow10 /= 10; + // + // pow10 = 10^(n-1) <= p1 < 10^n + // Invariants restored. + } + + // 2) + // + // The digits of the integral part have been generated: + // + // M+ = d[k-1]...d[1]d[0] + p2 * 2^e + // = buffer + p2 * 2^e + // + // Now generate the digits of the fractional part p2 * 2^e. + // + // Note: + // No decimal point is generated: the exponent is adjusted instead. + // + // p2 actually represents the fraction + // + // p2 * 2^e + // = p2 / 2^-e + // = d[-1] / 10^1 + d[-2] / 10^2 + ... + // + // Now generate the digits d[-m] of p1 from left to right (m = 1,2,...) + // + // p2 * 2^e = d[-1]d[-2]...d[-m] * 10^-m + // + 10^-m * (d[-m-1] / 10^1 + d[-m-2] / 10^2 + ...) + // + // using + // + // 10^m * p2 = ((10^m * p2) div 2^-e) * 2^-e + ((10^m * p2) mod 2^-e) + // = ( d) * 2^-e + ( r) + // + // or + // 10^m * p2 * 2^e = d + r * 2^e + // + // i.e. + // + // M+ = buffer + p2 * 2^e + // = buffer + 10^-m * (d + r * 2^e) + // = (buffer * 10^m + d) * 10^-m + 10^-m * r * 2^e + // + // and stop as soon as 10^-m * r * 2^e <= delta * 2^e + + JSON_ASSERT(p2 > delta); + + int m = 0; + for (;;) + { + // Invariant: + // M+ = buffer * 10^-m + 10^-m * (d[-m-1] / 10 + d[-m-2] / 10^2 + ...) * 2^e + // = buffer * 10^-m + 10^-m * (p2 ) * 2^e + // = buffer * 10^-m + 10^-m * (1/10 * (10 * p2) ) * 2^e + // = buffer * 10^-m + 10^-m * (1/10 * ((10*p2 div 2^-e) * 2^-e + (10*p2 mod 2^-e)) * 2^e + // + JSON_ASSERT(p2 <= (std::numeric_limits::max)() / 10); + p2 *= 10; + const std::uint64_t d = p2 >> -one.e; // d = (10 * p2) div 2^-e + const std::uint64_t r = p2 & (one.f - 1); // r = (10 * p2) mod 2^-e + // + // M+ = buffer * 10^-m + 10^-m * (1/10 * (d * 2^-e + r) * 2^e + // = buffer * 10^-m + 10^-m * (1/10 * (d + r * 2^e)) + // = (buffer * 10 + d) * 10^(-m-1) + 10^(-m-1) * r * 2^e + // + JSON_ASSERT(d <= 9); + buffer[length++] = static_cast('0' + d); // buffer := buffer * 10 + d + // + // M+ = buffer * 10^(-m-1) + 10^(-m-1) * r * 2^e + // + p2 = r; + m++; + // + // M+ = buffer * 10^-m + 10^-m * p2 * 2^e + // Invariant restored. + + // Check if enough digits have been generated. + // + // 10^-m * p2 * 2^e <= delta * 2^e + // p2 * 2^e <= 10^m * delta * 2^e + // p2 <= 10^m * delta + delta *= 10; + dist *= 10; + if (p2 <= delta) + { + break; + } + } + + // V = buffer * 10^-m, with M- <= V <= M+. + + decimal_exponent -= m; + + // 1 ulp in the decimal representation is now 10^-m. + // Since delta and dist are now scaled by 10^m, we need to do the + // same with ulp in order to keep the units in sync. + // + // 10^m * 10^-m = 1 = 2^-e * 2^e = ten_m * 2^e + // + const std::uint64_t ten_m = one.f; + grisu2_round(buffer, length, dist, delta, p2, ten_m); + + // By construction this algorithm generates the shortest possible decimal + // number (Loitsch, Theorem 6.2) which rounds back to w. + // For an input number of precision p, at least + // + // N = 1 + ceil(p * log_10(2)) + // + // decimal digits are sufficient to identify all binary floating-point + // numbers (Matula, "In-and-Out conversions"). + // This implies that the algorithm does not produce more than N decimal + // digits. + // + // N = 17 for p = 53 (IEEE double precision) + // N = 9 for p = 24 (IEEE single precision) +} + +/*! +v = buf * 10^decimal_exponent +len is the length of the buffer (number of decimal digits) +The buffer must be large enough, i.e. >= max_digits10. +*/ +JSON_HEDLEY_NON_NULL(1) +inline void grisu2(char* buf, int& len, int& decimal_exponent, + diyfp m_minus, diyfp v, diyfp m_plus) +{ + JSON_ASSERT(m_plus.e == m_minus.e); + JSON_ASSERT(m_plus.e == v.e); + + // --------(-----------------------+-----------------------)-------- (A) + // m- v m+ + // + // --------------------(-----------+-----------------------)-------- (B) + // m- v m+ + // + // First scale v (and m- and m+) such that the exponent is in the range + // [alpha, gamma]. + + const cached_power cached = get_cached_power_for_binary_exponent(m_plus.e); + + const diyfp c_minus_k(cached.f, cached.e); // = c ~= 10^-k + + // The exponent of the products is = v.e + c_minus_k.e + q and is in the range [alpha,gamma] + const diyfp w = diyfp::mul(v, c_minus_k); + const diyfp w_minus = diyfp::mul(m_minus, c_minus_k); + const diyfp w_plus = diyfp::mul(m_plus, c_minus_k); + + // ----(---+---)---------------(---+---)---------------(---+---)---- + // w- w w+ + // = c*m- = c*v = c*m+ + // + // diyfp::mul rounds its result and c_minus_k is approximated too. w, w- and + // w+ are now off by a small amount. + // In fact: + // + // w - v * 10^k < 1 ulp + // + // To account for this inaccuracy, add resp. subtract 1 ulp. + // + // --------+---[---------------(---+---)---------------]---+-------- + // w- M- w M+ w+ + // + // Now any number in [M-, M+] (bounds included) will round to w when input, + // regardless of how the input rounding algorithm breaks ties. + // + // And digit_gen generates the shortest possible such number in [M-, M+]. + // Note that this does not mean that Grisu2 always generates the shortest + // possible number in the interval (m-, m+). + const diyfp M_minus(w_minus.f + 1, w_minus.e); + const diyfp M_plus (w_plus.f - 1, w_plus.e ); + + decimal_exponent = -cached.k; // = -(-k) = k + + grisu2_digit_gen(buf, len, decimal_exponent, M_minus, w, M_plus); +} + +/*! +v = buf * 10^decimal_exponent +len is the length of the buffer (number of decimal digits) +The buffer must be large enough, i.e. >= max_digits10. +*/ +template +JSON_HEDLEY_NON_NULL(1) +void grisu2(char* buf, int& len, int& decimal_exponent, FloatType value) +{ + static_assert(diyfp::kPrecision >= std::numeric_limits::digits + 3, + "internal error: not enough precision"); + + JSON_ASSERT(std::isfinite(value)); + JSON_ASSERT(value > 0); + + // If the neighbors (and boundaries) of 'value' are always computed for double-precision + // numbers, all float's can be recovered using strtod (and strtof). However, the resulting + // decimal representations are not exactly "short". + // + // The documentation for 'std::to_chars' (https://en.cppreference.com/w/cpp/utility/to_chars) + // says "value is converted to a string as if by std::sprintf in the default ("C") locale" + // and since sprintf promotes float's to double's, I think this is exactly what 'std::to_chars' + // does. + // On the other hand, the documentation for 'std::to_chars' requires that "parsing the + // representation using the corresponding std::from_chars function recovers value exactly". That + // indicates that single precision floating-point numbers should be recovered using + // 'std::strtof'. + // + // NB: If the neighbors are computed for single-precision numbers, there is a single float + // (7.0385307e-26f) which can't be recovered using strtod. The resulting double precision + // value is off by 1 ulp. +#if 0 + const boundaries w = compute_boundaries(static_cast(value)); +#else + const boundaries w = compute_boundaries(value); +#endif + + grisu2(buf, len, decimal_exponent, w.minus, w.w, w.plus); +} + +/*! +@brief appends a decimal representation of e to buf +@return a pointer to the element following the exponent. +@pre -1000 < e < 1000 +*/ +JSON_HEDLEY_NON_NULL(1) +JSON_HEDLEY_RETURNS_NON_NULL +inline char* append_exponent(char* buf, int e) +{ + JSON_ASSERT(e > -1000); + JSON_ASSERT(e < 1000); + + if (e < 0) + { + e = -e; + *buf++ = '-'; + } + else + { + *buf++ = '+'; + } + + auto k = static_cast(e); + if (k < 10) + { + // Always print at least two digits in the exponent. + // This is for compatibility with printf("%g"). + *buf++ = '0'; + *buf++ = static_cast('0' + k); + } + else if (k < 100) + { + *buf++ = static_cast('0' + k / 10); + k %= 10; + *buf++ = static_cast('0' + k); + } + else + { + *buf++ = static_cast('0' + k / 100); + k %= 100; + *buf++ = static_cast('0' + k / 10); + k %= 10; + *buf++ = static_cast('0' + k); + } + + return buf; +} + +/*! +@brief prettify v = buf * 10^decimal_exponent + +If v is in the range [10^min_exp, 10^max_exp) it will be printed in fixed-point +notation. Otherwise it will be printed in exponential notation. + +@pre min_exp < 0 +@pre max_exp > 0 +*/ +JSON_HEDLEY_NON_NULL(1) +JSON_HEDLEY_RETURNS_NON_NULL +inline char* format_buffer(char* buf, int len, int decimal_exponent, + int min_exp, int max_exp) +{ + JSON_ASSERT(min_exp < 0); + JSON_ASSERT(max_exp > 0); + + const int k = len; + const int n = len + decimal_exponent; + + // v = buf * 10^(n-k) + // k is the length of the buffer (number of decimal digits) + // n is the position of the decimal point relative to the start of the buffer. + + if (k <= n && n <= max_exp) + { + // digits[000] + // len <= max_exp + 2 + + std::memset(buf + k, '0', static_cast(n) - static_cast(k)); + // Make it look like a floating-point number (#362, #378) + buf[n + 0] = '.'; + buf[n + 1] = '0'; + return buf + (static_cast(n) + 2); + } + + if (0 < n && n <= max_exp) + { + // dig.its + // len <= max_digits10 + 1 + + JSON_ASSERT(k > n); + + std::memmove(buf + (static_cast(n) + 1), buf + n, static_cast(k) - static_cast(n)); + buf[n] = '.'; + return buf + (static_cast(k) + 1U); + } + + if (min_exp < n && n <= 0) + { + // 0.[000]digits + // len <= 2 + (-min_exp - 1) + max_digits10 + + std::memmove(buf + (2 + static_cast(-n)), buf, static_cast(k)); + buf[0] = '0'; + buf[1] = '.'; + std::memset(buf + 2, '0', static_cast(-n)); + return buf + (2U + static_cast(-n) + static_cast(k)); + } + + if (k == 1) + { + // dE+123 + // len <= 1 + 5 + + buf += 1; + } + else + { + // d.igitsE+123 + // len <= max_digits10 + 1 + 5 + + std::memmove(buf + 2, buf + 1, static_cast(k) - 1); + buf[1] = '.'; + buf += 1 + static_cast(k); + } + + *buf++ = 'e'; + return append_exponent(buf, n - 1); +} + +} // namespace dtoa_impl + +/*! +@brief generates a decimal representation of the floating-point number value in [first, last). + +The format of the resulting decimal representation is similar to printf's %g +format. Returns an iterator pointing past-the-end of the decimal representation. + +@note The input number must be finite, i.e. NaN's and Inf's are not supported. +@note The buffer must be large enough. +@note The result is NOT null-terminated. +*/ +template +JSON_HEDLEY_NON_NULL(1, 2) +JSON_HEDLEY_RETURNS_NON_NULL +char* to_chars(char* first, const char* last, FloatType value) +{ + static_cast(last); // maybe unused - fix warning + JSON_ASSERT(std::isfinite(value)); + + // Use signbit(value) instead of (value < 0) since signbit works for -0. + if (std::signbit(value)) + { + value = -value; + *first++ = '-'; + } + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wfloat-equal" +#endif + if (value == 0) // +-0 + { + *first++ = '0'; + // Make it look like a floating-point number (#362, #378) + *first++ = '.'; + *first++ = '0'; + return first; + } +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + + JSON_ASSERT(last - first >= std::numeric_limits::max_digits10); + + // Compute v = buffer * 10^decimal_exponent. + // The decimal digits are stored in the buffer, which needs to be interpreted + // as an unsigned decimal integer. + // len is the length of the buffer, i.e. the number of decimal digits. + int len = 0; + int decimal_exponent = 0; + dtoa_impl::grisu2(first, len, decimal_exponent, value); + + JSON_ASSERT(len <= std::numeric_limits::max_digits10); + + // Format the buffer like printf("%.*g", prec, value) + constexpr int kMinExp = -4; + // Use digits10 here to increase compatibility with version 2. + constexpr int kMaxExp = std::numeric_limits::digits10; + + JSON_ASSERT(last - first >= kMaxExp + 2); + JSON_ASSERT(last - first >= 2 + (-kMinExp - 1) + std::numeric_limits::max_digits10); + JSON_ASSERT(last - first >= std::numeric_limits::max_digits10 + 6); + + return dtoa_impl::format_buffer(first, len, decimal_exponent, kMinExp, kMaxExp); +} + +} // namespace detail +} // namespace nlohmann + +// #include + +// #include + +// #include + +// #include + +// #include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +/////////////////// +// serialization // +/////////////////// + +/// how to treat decoding errors +enum class error_handler_t +{ + strict, ///< throw a type_error exception in case of invalid UTF-8 + replace, ///< replace invalid UTF-8 sequences with U+FFFD + ignore ///< ignore invalid UTF-8 sequences +}; + +template +class serializer +{ + using string_t = typename BasicJsonType::string_t; + using number_float_t = typename BasicJsonType::number_float_t; + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using binary_char_t = typename BasicJsonType::binary_t::value_type; + static constexpr std::uint8_t UTF8_ACCEPT = 0; + static constexpr std::uint8_t UTF8_REJECT = 1; + + public: + /*! + @param[in] s output stream to serialize to + @param[in] ichar indentation character to use + @param[in] error_handler_ how to react on decoding errors + */ + serializer(output_adapter_t s, const char ichar, + error_handler_t error_handler_ = error_handler_t::strict) + : o(std::move(s)) + , loc(std::localeconv()) + , thousands_sep(loc->thousands_sep == nullptr ? '\0' : std::char_traits::to_char_type(* (loc->thousands_sep))) + , decimal_point(loc->decimal_point == nullptr ? '\0' : std::char_traits::to_char_type(* (loc->decimal_point))) + , indent_char(ichar) + , indent_string(512, indent_char) + , error_handler(error_handler_) + {} + + // delete because of pointer members + serializer(const serializer&) = delete; + serializer& operator=(const serializer&) = delete; + serializer(serializer&&) = delete; + serializer& operator=(serializer&&) = delete; + ~serializer() = default; + + /*! + @brief internal implementation of the serialization function + + This function is called by the public member function dump and organizes + the serialization internally. The indentation level is propagated as + additional parameter. In case of arrays and objects, the function is + called recursively. + + - strings and object keys are escaped using `escape_string()` + - integer numbers are converted implicitly via `operator<<` + - floating-point numbers are converted to a string using `"%g"` format + - binary values are serialized as objects containing the subtype and the + byte array + + @param[in] val value to serialize + @param[in] pretty_print whether the output shall be pretty-printed + @param[in] ensure_ascii If @a ensure_ascii is true, all non-ASCII characters + in the output are escaped with `\uXXXX` sequences, and the result consists + of ASCII characters only. + @param[in] indent_step the indent level + @param[in] current_indent the current indent level (only used internally) + */ + void dump(const BasicJsonType& val, + const bool pretty_print, + const bool ensure_ascii, + const unsigned int indent_step, + const unsigned int current_indent = 0) + { + switch (val.m_type) + { + case value_t::object: + { + if (val.m_value.object->empty()) + { + o->write_characters("{}", 2); + return; + } + + if (pretty_print) + { + o->write_characters("{\n", 2); + + // variable to hold indentation for recursive calls + const auto new_indent = current_indent + indent_step; + if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent)) + { + indent_string.resize(indent_string.size() * 2, ' '); + } + + // first n-1 elements + auto i = val.m_value.object->cbegin(); + for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i) + { + o->write_characters(indent_string.c_str(), new_indent); + o->write_character('\"'); + dump_escaped(i->first, ensure_ascii); + o->write_characters("\": ", 3); + dump(i->second, true, ensure_ascii, indent_step, new_indent); + o->write_characters(",\n", 2); + } + + // last element + JSON_ASSERT(i != val.m_value.object->cend()); + JSON_ASSERT(std::next(i) == val.m_value.object->cend()); + o->write_characters(indent_string.c_str(), new_indent); + o->write_character('\"'); + dump_escaped(i->first, ensure_ascii); + o->write_characters("\": ", 3); + dump(i->second, true, ensure_ascii, indent_step, new_indent); + + o->write_character('\n'); + o->write_characters(indent_string.c_str(), current_indent); + o->write_character('}'); + } + else + { + o->write_character('{'); + + // first n-1 elements + auto i = val.m_value.object->cbegin(); + for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i) + { + o->write_character('\"'); + dump_escaped(i->first, ensure_ascii); + o->write_characters("\":", 2); + dump(i->second, false, ensure_ascii, indent_step, current_indent); + o->write_character(','); + } + + // last element + JSON_ASSERT(i != val.m_value.object->cend()); + JSON_ASSERT(std::next(i) == val.m_value.object->cend()); + o->write_character('\"'); + dump_escaped(i->first, ensure_ascii); + o->write_characters("\":", 2); + dump(i->second, false, ensure_ascii, indent_step, current_indent); + + o->write_character('}'); + } + + return; + } + + case value_t::array: + { + if (val.m_value.array->empty()) + { + o->write_characters("[]", 2); + return; + } + + if (pretty_print) + { + o->write_characters("[\n", 2); + + // variable to hold indentation for recursive calls + const auto new_indent = current_indent + indent_step; + if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent)) + { + indent_string.resize(indent_string.size() * 2, ' '); + } + + // first n-1 elements + for (auto i = val.m_value.array->cbegin(); + i != val.m_value.array->cend() - 1; ++i) + { + o->write_characters(indent_string.c_str(), new_indent); + dump(*i, true, ensure_ascii, indent_step, new_indent); + o->write_characters(",\n", 2); + } + + // last element + JSON_ASSERT(!val.m_value.array->empty()); + o->write_characters(indent_string.c_str(), new_indent); + dump(val.m_value.array->back(), true, ensure_ascii, indent_step, new_indent); + + o->write_character('\n'); + o->write_characters(indent_string.c_str(), current_indent); + o->write_character(']'); + } + else + { + o->write_character('['); + + // first n-1 elements + for (auto i = val.m_value.array->cbegin(); + i != val.m_value.array->cend() - 1; ++i) + { + dump(*i, false, ensure_ascii, indent_step, current_indent); + o->write_character(','); + } + + // last element + JSON_ASSERT(!val.m_value.array->empty()); + dump(val.m_value.array->back(), false, ensure_ascii, indent_step, current_indent); + + o->write_character(']'); + } + + return; + } + + case value_t::string: + { + o->write_character('\"'); + dump_escaped(*val.m_value.string, ensure_ascii); + o->write_character('\"'); + return; + } + + case value_t::binary: + { + if (pretty_print) + { + o->write_characters("{\n", 2); + + // variable to hold indentation for recursive calls + const auto new_indent = current_indent + indent_step; + if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent)) + { + indent_string.resize(indent_string.size() * 2, ' '); + } + + o->write_characters(indent_string.c_str(), new_indent); + + o->write_characters("\"bytes\": [", 10); + + if (!val.m_value.binary->empty()) + { + for (auto i = val.m_value.binary->cbegin(); + i != val.m_value.binary->cend() - 1; ++i) + { + dump_integer(*i); + o->write_characters(", ", 2); + } + dump_integer(val.m_value.binary->back()); + } + + o->write_characters("],\n", 3); + o->write_characters(indent_string.c_str(), new_indent); + + o->write_characters("\"subtype\": ", 11); + if (val.m_value.binary->has_subtype()) + { + dump_integer(val.m_value.binary->subtype()); + } + else + { + o->write_characters("null", 4); + } + o->write_character('\n'); + o->write_characters(indent_string.c_str(), current_indent); + o->write_character('}'); + } + else + { + o->write_characters("{\"bytes\":[", 10); + + if (!val.m_value.binary->empty()) + { + for (auto i = val.m_value.binary->cbegin(); + i != val.m_value.binary->cend() - 1; ++i) + { + dump_integer(*i); + o->write_character(','); + } + dump_integer(val.m_value.binary->back()); + } + + o->write_characters("],\"subtype\":", 12); + if (val.m_value.binary->has_subtype()) + { + dump_integer(val.m_value.binary->subtype()); + o->write_character('}'); + } + else + { + o->write_characters("null}", 5); + } + } + return; + } + + case value_t::boolean: + { + if (val.m_value.boolean) + { + o->write_characters("true", 4); + } + else + { + o->write_characters("false", 5); + } + return; + } + + case value_t::number_integer: + { + dump_integer(val.m_value.number_integer); + return; + } + + case value_t::number_unsigned: + { + dump_integer(val.m_value.number_unsigned); + return; + } + + case value_t::number_float: + { + dump_float(val.m_value.number_float); + return; + } + + case value_t::discarded: + { + o->write_characters("", 11); + return; + } + + case value_t::null: + { + o->write_characters("null", 4); + return; + } + + default: // LCOV_EXCL_LINE + JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE + } + } + + JSON_PRIVATE_UNLESS_TESTED: + /*! + @brief dump escaped string + + Escape a string by replacing certain special characters by a sequence of an + escape character (backslash) and another character and other control + characters by a sequence of "\u" followed by a four-digit hex + representation. The escaped string is written to output stream @a o. + + @param[in] s the string to escape + @param[in] ensure_ascii whether to escape non-ASCII characters with + \uXXXX sequences + + @complexity Linear in the length of string @a s. + */ + void dump_escaped(const string_t& s, const bool ensure_ascii) + { + std::uint32_t codepoint{}; + std::uint8_t state = UTF8_ACCEPT; + std::size_t bytes = 0; // number of bytes written to string_buffer + + // number of bytes written at the point of the last valid byte + std::size_t bytes_after_last_accept = 0; + std::size_t undumped_chars = 0; + + for (std::size_t i = 0; i < s.size(); ++i) + { + const auto byte = static_cast(s[i]); + + switch (decode(state, codepoint, byte)) + { + case UTF8_ACCEPT: // decode found a new code point + { + switch (codepoint) + { + case 0x08: // backspace + { + string_buffer[bytes++] = '\\'; + string_buffer[bytes++] = 'b'; + break; + } + + case 0x09: // horizontal tab + { + string_buffer[bytes++] = '\\'; + string_buffer[bytes++] = 't'; + break; + } + + case 0x0A: // newline + { + string_buffer[bytes++] = '\\'; + string_buffer[bytes++] = 'n'; + break; + } + + case 0x0C: // formfeed + { + string_buffer[bytes++] = '\\'; + string_buffer[bytes++] = 'f'; + break; + } + + case 0x0D: // carriage return + { + string_buffer[bytes++] = '\\'; + string_buffer[bytes++] = 'r'; + break; + } + + case 0x22: // quotation mark + { + string_buffer[bytes++] = '\\'; + string_buffer[bytes++] = '\"'; + break; + } + + case 0x5C: // reverse solidus + { + string_buffer[bytes++] = '\\'; + string_buffer[bytes++] = '\\'; + break; + } + + default: + { + // escape control characters (0x00..0x1F) or, if + // ensure_ascii parameter is used, non-ASCII characters + if ((codepoint <= 0x1F) || (ensure_ascii && (codepoint >= 0x7F))) + { + if (codepoint <= 0xFFFF) + { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg) + (std::snprintf)(string_buffer.data() + bytes, 7, "\\u%04x", + static_cast(codepoint)); + bytes += 6; + } + else + { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg) + (std::snprintf)(string_buffer.data() + bytes, 13, "\\u%04x\\u%04x", + static_cast(0xD7C0u + (codepoint >> 10u)), + static_cast(0xDC00u + (codepoint & 0x3FFu))); + bytes += 12; + } + } + else + { + // copy byte to buffer (all previous bytes + // been copied have in default case above) + string_buffer[bytes++] = s[i]; + } + break; + } + } + + // write buffer and reset index; there must be 13 bytes + // left, as this is the maximal number of bytes to be + // written ("\uxxxx\uxxxx\0") for one code point + if (string_buffer.size() - bytes < 13) + { + o->write_characters(string_buffer.data(), bytes); + bytes = 0; + } + + // remember the byte position of this accept + bytes_after_last_accept = bytes; + undumped_chars = 0; + break; + } + + case UTF8_REJECT: // decode found invalid UTF-8 byte + { + switch (error_handler) + { + case error_handler_t::strict: + { + std::string sn(9, '\0'); + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg) + (std::snprintf)(&sn[0], sn.size(), "%.2X", byte); + JSON_THROW(type_error::create(316, "invalid UTF-8 byte at index " + std::to_string(i) + ": 0x" + sn, BasicJsonType())); + } + + case error_handler_t::ignore: + case error_handler_t::replace: + { + // in case we saw this character the first time, we + // would like to read it again, because the byte + // may be OK for itself, but just not OK for the + // previous sequence + if (undumped_chars > 0) + { + --i; + } + + // reset length buffer to the last accepted index; + // thus removing/ignoring the invalid characters + bytes = bytes_after_last_accept; + + if (error_handler == error_handler_t::replace) + { + // add a replacement character + if (ensure_ascii) + { + string_buffer[bytes++] = '\\'; + string_buffer[bytes++] = 'u'; + string_buffer[bytes++] = 'f'; + string_buffer[bytes++] = 'f'; + string_buffer[bytes++] = 'f'; + string_buffer[bytes++] = 'd'; + } + else + { + string_buffer[bytes++] = detail::binary_writer::to_char_type('\xEF'); + string_buffer[bytes++] = detail::binary_writer::to_char_type('\xBF'); + string_buffer[bytes++] = detail::binary_writer::to_char_type('\xBD'); + } + + // write buffer and reset index; there must be 13 bytes + // left, as this is the maximal number of bytes to be + // written ("\uxxxx\uxxxx\0") for one code point + if (string_buffer.size() - bytes < 13) + { + o->write_characters(string_buffer.data(), bytes); + bytes = 0; + } + + bytes_after_last_accept = bytes; + } + + undumped_chars = 0; + + // continue processing the string + state = UTF8_ACCEPT; + break; + } + + default: // LCOV_EXCL_LINE + JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE + } + break; + } + + default: // decode found yet incomplete multi-byte code point + { + if (!ensure_ascii) + { + // code point will not be escaped - copy byte to buffer + string_buffer[bytes++] = s[i]; + } + ++undumped_chars; + break; + } + } + } + + // we finished processing the string + if (JSON_HEDLEY_LIKELY(state == UTF8_ACCEPT)) + { + // write buffer + if (bytes > 0) + { + o->write_characters(string_buffer.data(), bytes); + } + } + else + { + // we finish reading, but do not accept: string was incomplete + switch (error_handler) + { + case error_handler_t::strict: + { + std::string sn(9, '\0'); + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg) + (std::snprintf)(&sn[0], sn.size(), "%.2X", static_cast(s.back())); + JSON_THROW(type_error::create(316, "incomplete UTF-8 string; last byte: 0x" + sn, BasicJsonType())); + } + + case error_handler_t::ignore: + { + // write all accepted bytes + o->write_characters(string_buffer.data(), bytes_after_last_accept); + break; + } + + case error_handler_t::replace: + { + // write all accepted bytes + o->write_characters(string_buffer.data(), bytes_after_last_accept); + // add a replacement character + if (ensure_ascii) + { + o->write_characters("\\ufffd", 6); + } + else + { + o->write_characters("\xEF\xBF\xBD", 3); + } + break; + } + + default: // LCOV_EXCL_LINE + JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE + } + } + } + + private: + /*! + @brief count digits + + Count the number of decimal (base 10) digits for an input unsigned integer. + + @param[in] x unsigned integer number to count its digits + @return number of decimal digits + */ + inline unsigned int count_digits(number_unsigned_t x) noexcept + { + unsigned int n_digits = 1; + for (;;) + { + if (x < 10) + { + return n_digits; + } + if (x < 100) + { + return n_digits + 1; + } + if (x < 1000) + { + return n_digits + 2; + } + if (x < 10000) + { + return n_digits + 3; + } + x = x / 10000u; + n_digits += 4; + } + } + + /*! + @brief dump an integer + + Dump a given integer to output stream @a o. Works internally with + @a number_buffer. + + @param[in] x integer number (signed or unsigned) to dump + @tparam NumberType either @a number_integer_t or @a number_unsigned_t + */ + template < typename NumberType, detail::enable_if_t < + std::is_integral::value || + std::is_same::value || + std::is_same::value || + std::is_same::value, + int > = 0 > + void dump_integer(NumberType x) + { + static constexpr std::array, 100> digits_to_99 + { + { + {{'0', '0'}}, {{'0', '1'}}, {{'0', '2'}}, {{'0', '3'}}, {{'0', '4'}}, {{'0', '5'}}, {{'0', '6'}}, {{'0', '7'}}, {{'0', '8'}}, {{'0', '9'}}, + {{'1', '0'}}, {{'1', '1'}}, {{'1', '2'}}, {{'1', '3'}}, {{'1', '4'}}, {{'1', '5'}}, {{'1', '6'}}, {{'1', '7'}}, {{'1', '8'}}, {{'1', '9'}}, + {{'2', '0'}}, {{'2', '1'}}, {{'2', '2'}}, {{'2', '3'}}, {{'2', '4'}}, {{'2', '5'}}, {{'2', '6'}}, {{'2', '7'}}, {{'2', '8'}}, {{'2', '9'}}, + {{'3', '0'}}, {{'3', '1'}}, {{'3', '2'}}, {{'3', '3'}}, {{'3', '4'}}, {{'3', '5'}}, {{'3', '6'}}, {{'3', '7'}}, {{'3', '8'}}, {{'3', '9'}}, + {{'4', '0'}}, {{'4', '1'}}, {{'4', '2'}}, {{'4', '3'}}, {{'4', '4'}}, {{'4', '5'}}, {{'4', '6'}}, {{'4', '7'}}, {{'4', '8'}}, {{'4', '9'}}, + {{'5', '0'}}, {{'5', '1'}}, {{'5', '2'}}, {{'5', '3'}}, {{'5', '4'}}, {{'5', '5'}}, {{'5', '6'}}, {{'5', '7'}}, {{'5', '8'}}, {{'5', '9'}}, + {{'6', '0'}}, {{'6', '1'}}, {{'6', '2'}}, {{'6', '3'}}, {{'6', '4'}}, {{'6', '5'}}, {{'6', '6'}}, {{'6', '7'}}, {{'6', '8'}}, {{'6', '9'}}, + {{'7', '0'}}, {{'7', '1'}}, {{'7', '2'}}, {{'7', '3'}}, {{'7', '4'}}, {{'7', '5'}}, {{'7', '6'}}, {{'7', '7'}}, {{'7', '8'}}, {{'7', '9'}}, + {{'8', '0'}}, {{'8', '1'}}, {{'8', '2'}}, {{'8', '3'}}, {{'8', '4'}}, {{'8', '5'}}, {{'8', '6'}}, {{'8', '7'}}, {{'8', '8'}}, {{'8', '9'}}, + {{'9', '0'}}, {{'9', '1'}}, {{'9', '2'}}, {{'9', '3'}}, {{'9', '4'}}, {{'9', '5'}}, {{'9', '6'}}, {{'9', '7'}}, {{'9', '8'}}, {{'9', '9'}}, + } + }; + + // special case for "0" + if (x == 0) + { + o->write_character('0'); + return; + } + + // use a pointer to fill the buffer + auto buffer_ptr = number_buffer.begin(); // NOLINT(llvm-qualified-auto,readability-qualified-auto,cppcoreguidelines-pro-type-vararg,hicpp-vararg) + + const bool is_negative = std::is_signed::value && !(x >= 0); // see issue #755 + number_unsigned_t abs_value; + + unsigned int n_chars{}; + + if (is_negative) + { + *buffer_ptr = '-'; + abs_value = remove_sign(static_cast(x)); + + // account one more byte for the minus sign + n_chars = 1 + count_digits(abs_value); + } + else + { + abs_value = static_cast(x); + n_chars = count_digits(abs_value); + } + + // spare 1 byte for '\0' + JSON_ASSERT(n_chars < number_buffer.size() - 1); + + // jump to the end to generate the string from backward + // so we later avoid reversing the result + buffer_ptr += n_chars; + + // Fast int2ascii implementation inspired by "Fastware" talk by Andrei Alexandrescu + // See: https://www.youtube.com/watch?v=o4-CwDo2zpg + while (abs_value >= 100) + { + const auto digits_index = static_cast((abs_value % 100)); + abs_value /= 100; + *(--buffer_ptr) = digits_to_99[digits_index][1]; + *(--buffer_ptr) = digits_to_99[digits_index][0]; + } + + if (abs_value >= 10) + { + const auto digits_index = static_cast(abs_value); + *(--buffer_ptr) = digits_to_99[digits_index][1]; + *(--buffer_ptr) = digits_to_99[digits_index][0]; + } + else + { + *(--buffer_ptr) = static_cast('0' + abs_value); + } + + o->write_characters(number_buffer.data(), n_chars); + } + + /*! + @brief dump a floating-point number + + Dump a given floating-point number to output stream @a o. Works internally + with @a number_buffer. + + @param[in] x floating-point number to dump + */ + void dump_float(number_float_t x) + { + // NaN / inf + if (!std::isfinite(x)) + { + o->write_characters("null", 4); + return; + } + + // If number_float_t is an IEEE-754 single or double precision number, + // use the Grisu2 algorithm to produce short numbers which are + // guaranteed to round-trip, using strtof and strtod, resp. + // + // NB: The test below works if == . + static constexpr bool is_ieee_single_or_double + = (std::numeric_limits::is_iec559 && std::numeric_limits::digits == 24 && std::numeric_limits::max_exponent == 128) || + (std::numeric_limits::is_iec559 && std::numeric_limits::digits == 53 && std::numeric_limits::max_exponent == 1024); + + dump_float(x, std::integral_constant()); + } + + void dump_float(number_float_t x, std::true_type /*is_ieee_single_or_double*/) + { + auto* begin = number_buffer.data(); + auto* end = ::nlohmann::detail::to_chars(begin, begin + number_buffer.size(), x); + + o->write_characters(begin, static_cast(end - begin)); + } + + void dump_float(number_float_t x, std::false_type /*is_ieee_single_or_double*/) + { + // get number of digits for a float -> text -> float round-trip + static constexpr auto d = std::numeric_limits::max_digits10; + + // the actual conversion + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg) + std::ptrdiff_t len = (std::snprintf)(number_buffer.data(), number_buffer.size(), "%.*g", d, x); + + // negative value indicates an error + JSON_ASSERT(len > 0); + // check if buffer was large enough + JSON_ASSERT(static_cast(len) < number_buffer.size()); + + // erase thousands separator + if (thousands_sep != '\0') + { + // NOLINTNEXTLINE(readability-qualified-auto,llvm-qualified-auto): std::remove returns an iterator, see https://github.com/nlohmann/json/issues/3081 + const auto end = std::remove(number_buffer.begin(), number_buffer.begin() + len, thousands_sep); + std::fill(end, number_buffer.end(), '\0'); + JSON_ASSERT((end - number_buffer.begin()) <= len); + len = (end - number_buffer.begin()); + } + + // convert decimal point to '.' + if (decimal_point != '\0' && decimal_point != '.') + { + // NOLINTNEXTLINE(readability-qualified-auto,llvm-qualified-auto): std::find returns an iterator, see https://github.com/nlohmann/json/issues/3081 + const auto dec_pos = std::find(number_buffer.begin(), number_buffer.end(), decimal_point); + if (dec_pos != number_buffer.end()) + { + *dec_pos = '.'; + } + } + + o->write_characters(number_buffer.data(), static_cast(len)); + + // determine if need to append ".0" + const bool value_is_int_like = + std::none_of(number_buffer.begin(), number_buffer.begin() + len + 1, + [](char c) + { + return c == '.' || c == 'e'; + }); + + if (value_is_int_like) + { + o->write_characters(".0", 2); + } + } + + /*! + @brief check whether a string is UTF-8 encoded + + The function checks each byte of a string whether it is UTF-8 encoded. The + result of the check is stored in the @a state parameter. The function must + be called initially with state 0 (accept). State 1 means the string must + be rejected, because the current byte is not allowed. If the string is + completely processed, but the state is non-zero, the string ended + prematurely; that is, the last byte indicated more bytes should have + followed. + + @param[in,out] state the state of the decoding + @param[in,out] codep codepoint (valid only if resulting state is UTF8_ACCEPT) + @param[in] byte next byte to decode + @return new state + + @note The function has been edited: a std::array is used. + + @copyright Copyright (c) 2008-2009 Bjoern Hoehrmann + @sa http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ + */ + static std::uint8_t decode(std::uint8_t& state, std::uint32_t& codep, const std::uint8_t byte) noexcept + { + static const std::array utf8d = + { + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00..1F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20..3F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40..5F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60..7F + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 80..9F + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // A0..BF + 8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // C0..DF + 0xA, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, // E0..EF + 0xB, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, // F0..FF + 0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, // s0..s0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, // s1..s2 + 1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // s3..s4 + 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, // s5..s6 + 1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // s7..s8 + } + }; + + JSON_ASSERT(byte < utf8d.size()); + const std::uint8_t type = utf8d[byte]; + + codep = (state != UTF8_ACCEPT) + ? (byte & 0x3fu) | (codep << 6u) + : (0xFFu >> type) & (byte); + + std::size_t index = 256u + static_cast(state) * 16u + static_cast(type); + JSON_ASSERT(index < 400); + state = utf8d[index]; + return state; + } + + /* + * Overload to make the compiler happy while it is instantiating + * dump_integer for number_unsigned_t. + * Must never be called. + */ + number_unsigned_t remove_sign(number_unsigned_t x) + { + JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE + return x; // LCOV_EXCL_LINE + } + + /* + * Helper function for dump_integer + * + * This function takes a negative signed integer and returns its absolute + * value as unsigned integer. The plus/minus shuffling is necessary as we can + * not directly remove the sign of an arbitrary signed integer as the + * absolute values of INT_MIN and INT_MAX are usually not the same. See + * #1708 for details. + */ + inline number_unsigned_t remove_sign(number_integer_t x) noexcept + { + JSON_ASSERT(x < 0 && x < (std::numeric_limits::max)()); // NOLINT(misc-redundant-expression) + return static_cast(-(x + 1)) + 1; + } + + private: + /// the output of the serializer + output_adapter_t o = nullptr; + + /// a (hopefully) large enough character buffer + std::array number_buffer{{}}; + + /// the locale + const std::lconv* loc = nullptr; + /// the locale's thousand separator character + const char thousands_sep = '\0'; + /// the locale's decimal point character + const char decimal_point = '\0'; + + /// string buffer + std::array string_buffer{{}}; + + /// the indentation character + const char indent_char; + /// the indentation string + string_t indent_string; + + /// error_handler how to react on decoding errors + const error_handler_t error_handler; +}; +} // namespace detail +} // namespace nlohmann + +// #include + +// #include + +// #include + + +#include // less +#include // initializer_list +#include // input_iterator_tag, iterator_traits +#include // allocator +#include // for out_of_range +#include // enable_if, is_convertible +#include // pair +#include // vector + +// #include + + +namespace nlohmann +{ + +/// ordered_map: a minimal map-like container that preserves insertion order +/// for use within nlohmann::basic_json +template , + class Allocator = std::allocator>> + struct ordered_map : std::vector, Allocator> +{ + using key_type = Key; + using mapped_type = T; + using Container = std::vector, Allocator>; + using typename Container::iterator; + using typename Container::const_iterator; + using typename Container::size_type; + using typename Container::value_type; + + // Explicit constructors instead of `using Container::Container` + // otherwise older compilers choke on it (GCC <= 5.5, xcode <= 9.4) + ordered_map(const Allocator& alloc = Allocator()) : Container{alloc} {} + template + ordered_map(It first, It last, const Allocator& alloc = Allocator()) + : Container{first, last, alloc} {} + ordered_map(std::initializer_list init, const Allocator& alloc = Allocator() ) + : Container{init, alloc} {} + + std::pair emplace(const key_type& key, T&& t) + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (it->first == key) + { + return {it, false}; + } + } + Container::emplace_back(key, t); + return {--this->end(), true}; + } + + T& operator[](const Key& key) + { + return emplace(key, T{}).first->second; + } + + const T& operator[](const Key& key) const + { + return at(key); + } + + T& at(const Key& key) + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (it->first == key) + { + return it->second; + } + } + + JSON_THROW(std::out_of_range("key not found")); + } + + const T& at(const Key& key) const + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (it->first == key) + { + return it->second; + } + } + + JSON_THROW(std::out_of_range("key not found")); + } + + size_type erase(const Key& key) + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (it->first == key) + { + // Since we cannot move const Keys, re-construct them in place + for (auto next = it; ++next != this->end(); ++it) + { + it->~value_type(); // Destroy but keep allocation + new (&*it) value_type{std::move(*next)}; + } + Container::pop_back(); + return 1; + } + } + return 0; + } + + iterator erase(iterator pos) + { + auto it = pos; + + // Since we cannot move const Keys, re-construct them in place + for (auto next = it; ++next != this->end(); ++it) + { + it->~value_type(); // Destroy but keep allocation + new (&*it) value_type{std::move(*next)}; + } + Container::pop_back(); + return pos; + } + + size_type count(const Key& key) const + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (it->first == key) + { + return 1; + } + } + return 0; + } + + iterator find(const Key& key) + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (it->first == key) + { + return it; + } + } + return Container::end(); + } + + const_iterator find(const Key& key) const + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (it->first == key) + { + return it; + } + } + return Container::end(); + } + + std::pair insert( value_type&& value ) + { + return emplace(value.first, std::move(value.second)); + } + + std::pair insert( const value_type& value ) + { + for (auto it = this->begin(); it != this->end(); ++it) + { + if (it->first == value.first) + { + return {it, false}; + } + } + Container::push_back(value); + return {--this->end(), true}; + } + + template + using require_input_iter = typename std::enable_if::iterator_category, + std::input_iterator_tag>::value>::type; + + template> + void insert(InputIt first, InputIt last) + { + for (auto it = first; it != last; ++it) + { + insert(*it); + } + } +}; + +} // namespace nlohmann + + +#if defined(JSON_HAS_CPP_17) + #include +#endif + +/*! +@brief namespace for Niels Lohmann +@see https://github.com/nlohmann +@since version 1.0.0 +*/ +namespace nlohmann +{ + +/*! +@brief a class to store JSON values + +@tparam ObjectType type for JSON objects (`std::map` by default; will be used +in @ref object_t) +@tparam ArrayType type for JSON arrays (`std::vector` by default; will be used +in @ref array_t) +@tparam StringType type for JSON strings and object keys (`std::string` by +default; will be used in @ref string_t) +@tparam BooleanType type for JSON booleans (`bool` by default; will be used +in @ref boolean_t) +@tparam NumberIntegerType type for JSON integer numbers (`int64_t` by +default; will be used in @ref number_integer_t) +@tparam NumberUnsignedType type for JSON unsigned integer numbers (@c +`uint64_t` by default; will be used in @ref number_unsigned_t) +@tparam NumberFloatType type for JSON floating-point numbers (`double` by +default; will be used in @ref number_float_t) +@tparam BinaryType type for packed binary data for compatibility with binary +serialization formats (`std::vector` by default; will be used in +@ref binary_t) +@tparam AllocatorType type of the allocator to use (`std::allocator` by +default) +@tparam JSONSerializer the serializer to resolve internal calls to `to_json()` +and `from_json()` (@ref adl_serializer by default) + +@requirement The class satisfies the following concept requirements: +- Basic + - [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible): + JSON values can be default constructed. The result will be a JSON null + value. + - [MoveConstructible](https://en.cppreference.com/w/cpp/named_req/MoveConstructible): + A JSON value can be constructed from an rvalue argument. + - [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible): + A JSON value can be copy-constructed from an lvalue expression. + - [MoveAssignable](https://en.cppreference.com/w/cpp/named_req/MoveAssignable): + A JSON value van be assigned from an rvalue argument. + - [CopyAssignable](https://en.cppreference.com/w/cpp/named_req/CopyAssignable): + A JSON value can be copy-assigned from an lvalue expression. + - [Destructible](https://en.cppreference.com/w/cpp/named_req/Destructible): + JSON values can be destructed. +- Layout + - [StandardLayoutType](https://en.cppreference.com/w/cpp/named_req/StandardLayoutType): + JSON values have + [standard layout](https://en.cppreference.com/w/cpp/language/data_members#Standard_layout): + All non-static data members are private and standard layout types, the + class has no virtual functions or (virtual) base classes. +- Library-wide + - [EqualityComparable](https://en.cppreference.com/w/cpp/named_req/EqualityComparable): + JSON values can be compared with `==`, see @ref + operator==(const_reference,const_reference). + - [LessThanComparable](https://en.cppreference.com/w/cpp/named_req/LessThanComparable): + JSON values can be compared with `<`, see @ref + operator<(const_reference,const_reference). + - [Swappable](https://en.cppreference.com/w/cpp/named_req/Swappable): + Any JSON lvalue or rvalue of can be swapped with any lvalue or rvalue of + other compatible types, using unqualified function call @ref swap(). + - [NullablePointer](https://en.cppreference.com/w/cpp/named_req/NullablePointer): + JSON values can be compared against `std::nullptr_t` objects which are used + to model the `null` value. +- Container + - [Container](https://en.cppreference.com/w/cpp/named_req/Container): + JSON values can be used like STL containers and provide iterator access. + - [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer); + JSON values can be used like STL containers and provide reverse iterator + access. + +@invariant The member variables @a m_value and @a m_type have the following +relationship: +- If `m_type == value_t::object`, then `m_value.object != nullptr`. +- If `m_type == value_t::array`, then `m_value.array != nullptr`. +- If `m_type == value_t::string`, then `m_value.string != nullptr`. +The invariants are checked by member function assert_invariant(). + +@internal +@note ObjectType trick from https://stackoverflow.com/a/9860911 +@endinternal + +@see [RFC 8259: The JavaScript Object Notation (JSON) Data Interchange +Format](https://tools.ietf.org/html/rfc8259) + +@since version 1.0.0 + +@nosubgrouping +*/ +NLOHMANN_BASIC_JSON_TPL_DECLARATION +class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions) +{ + private: + template friend struct detail::external_constructor; + friend ::nlohmann::json_pointer; + + template + friend class ::nlohmann::detail::parser; + friend ::nlohmann::detail::serializer; + template + friend class ::nlohmann::detail::iter_impl; + template + friend class ::nlohmann::detail::binary_writer; + template + friend class ::nlohmann::detail::binary_reader; + template + friend class ::nlohmann::detail::json_sax_dom_parser; + template + friend class ::nlohmann::detail::json_sax_dom_callback_parser; + friend class ::nlohmann::detail::exception; + + /// workaround type for MSVC + using basic_json_t = NLOHMANN_BASIC_JSON_TPL; + + JSON_PRIVATE_UNLESS_TESTED: + // convenience aliases for types residing in namespace detail; + using lexer = ::nlohmann::detail::lexer_base; + + template + static ::nlohmann::detail::parser parser( + InputAdapterType adapter, + detail::parser_callback_tcb = nullptr, + const bool allow_exceptions = true, + const bool ignore_comments = false + ) + { + return ::nlohmann::detail::parser(std::move(adapter), + std::move(cb), allow_exceptions, ignore_comments); + } + + private: + using primitive_iterator_t = ::nlohmann::detail::primitive_iterator_t; + template + using internal_iterator = ::nlohmann::detail::internal_iterator; + template + using iter_impl = ::nlohmann::detail::iter_impl; + template + using iteration_proxy = ::nlohmann::detail::iteration_proxy; + template using json_reverse_iterator = ::nlohmann::detail::json_reverse_iterator; + + template + using output_adapter_t = ::nlohmann::detail::output_adapter_t; + + template + using binary_reader = ::nlohmann::detail::binary_reader; + template using binary_writer = ::nlohmann::detail::binary_writer; + + JSON_PRIVATE_UNLESS_TESTED: + using serializer = ::nlohmann::detail::serializer; + + public: + using value_t = detail::value_t; + /// JSON Pointer, see @ref nlohmann::json_pointer + using json_pointer = ::nlohmann::json_pointer; + template + using json_serializer = JSONSerializer; + /// how to treat decoding errors + using error_handler_t = detail::error_handler_t; + /// how to treat CBOR tags + using cbor_tag_handler_t = detail::cbor_tag_handler_t; + /// helper type for initializer lists of basic_json values + using initializer_list_t = std::initializer_list>; + + using input_format_t = detail::input_format_t; + /// SAX interface type, see @ref nlohmann::json_sax + using json_sax_t = json_sax; + + //////////////// + // exceptions // + //////////////// + + /// @name exceptions + /// Classes to implement user-defined exceptions. + /// @{ + + /// @copydoc detail::exception + using exception = detail::exception; + /// @copydoc detail::parse_error + using parse_error = detail::parse_error; + /// @copydoc detail::invalid_iterator + using invalid_iterator = detail::invalid_iterator; + /// @copydoc detail::type_error + using type_error = detail::type_error; + /// @copydoc detail::out_of_range + using out_of_range = detail::out_of_range; + /// @copydoc detail::other_error + using other_error = detail::other_error; + + /// @} + + + ///////////////////// + // container types // + ///////////////////// + + /// @name container types + /// The canonic container types to use @ref basic_json like any other STL + /// container. + /// @{ + + /// the type of elements in a basic_json container + using value_type = basic_json; + + /// the type of an element reference + using reference = value_type&; + /// the type of an element const reference + using const_reference = const value_type&; + + /// a type to represent differences between iterators + using difference_type = std::ptrdiff_t; + /// a type to represent container sizes + using size_type = std::size_t; + + /// the allocator type + using allocator_type = AllocatorType; + + /// the type of an element pointer + using pointer = typename std::allocator_traits::pointer; + /// the type of an element const pointer + using const_pointer = typename std::allocator_traits::const_pointer; + + /// an iterator for a basic_json container + using iterator = iter_impl; + /// a const iterator for a basic_json container + using const_iterator = iter_impl; + /// a reverse iterator for a basic_json container + using reverse_iterator = json_reverse_iterator; + /// a const reverse iterator for a basic_json container + using const_reverse_iterator = json_reverse_iterator; + + /// @} + + + /*! + @brief returns the allocator associated with the container + */ + static allocator_type get_allocator() + { + return allocator_type(); + } + + /*! + @brief returns version information on the library + + This function returns a JSON object with information about the library, + including the version number and information on the platform and compiler. + + @return JSON object holding version information + key | description + ----------- | --------------- + `compiler` | Information on the used compiler. It is an object with the following keys: `c++` (the used C++ standard), `family` (the compiler family; possible values are `clang`, `icc`, `gcc`, `ilecpp`, `msvc`, `pgcpp`, `sunpro`, and `unknown`), and `version` (the compiler version). + `copyright` | The copyright line for the library as string. + `name` | The name of the library as string. + `platform` | The used platform as string. Possible values are `win32`, `linux`, `apple`, `unix`, and `unknown`. + `url` | The URL of the project as string. + `version` | The version of the library. It is an object with the following keys: `major`, `minor`, and `patch` as defined by [Semantic Versioning](http://semver.org), and `string` (the version string). + + @liveexample{The following code shows an example output of the `meta()` + function.,meta} + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @complexity Constant. + + @since 2.1.0 + */ + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json meta() + { + basic_json result; + + result["copyright"] = "(C) 2013-2021 Niels Lohmann"; + result["name"] = "JSON for Modern C++"; + result["url"] = "https://github.com/nlohmann/json"; + result["version"]["string"] = + std::to_string(NLOHMANN_JSON_VERSION_MAJOR) + "." + + std::to_string(NLOHMANN_JSON_VERSION_MINOR) + "." + + std::to_string(NLOHMANN_JSON_VERSION_PATCH); + result["version"]["major"] = NLOHMANN_JSON_VERSION_MAJOR; + result["version"]["minor"] = NLOHMANN_JSON_VERSION_MINOR; + result["version"]["patch"] = NLOHMANN_JSON_VERSION_PATCH; + +#ifdef _WIN32 + result["platform"] = "win32"; +#elif defined __linux__ + result["platform"] = "linux"; +#elif defined __APPLE__ + result["platform"] = "apple"; +#elif defined __unix__ + result["platform"] = "unix"; +#else + result["platform"] = "unknown"; +#endif + +#if defined(__ICC) || defined(__INTEL_COMPILER) + result["compiler"] = {{"family", "icc"}, {"version", __INTEL_COMPILER}}; +#elif defined(__clang__) + result["compiler"] = {{"family", "clang"}, {"version", __clang_version__}}; +#elif defined(__GNUC__) || defined(__GNUG__) + result["compiler"] = {{"family", "gcc"}, {"version", std::to_string(__GNUC__) + "." + std::to_string(__GNUC_MINOR__) + "." + std::to_string(__GNUC_PATCHLEVEL__)}}; +#elif defined(__HP_cc) || defined(__HP_aCC) + result["compiler"] = "hp" +#elif defined(__IBMCPP__) + result["compiler"] = {{"family", "ilecpp"}, {"version", __IBMCPP__}}; +#elif defined(_MSC_VER) + result["compiler"] = {{"family", "msvc"}, {"version", _MSC_VER}}; +#elif defined(__PGI) + result["compiler"] = {{"family", "pgcpp"}, {"version", __PGI}}; +#elif defined(__SUNPRO_CC) + result["compiler"] = {{"family", "sunpro"}, {"version", __SUNPRO_CC}}; +#else + result["compiler"] = {{"family", "unknown"}, {"version", "unknown"}}; +#endif + +#ifdef __cplusplus + result["compiler"]["c++"] = std::to_string(__cplusplus); +#else + result["compiler"]["c++"] = "unknown"; +#endif + return result; + } + + + /////////////////////////// + // JSON value data types // + /////////////////////////// + + /// @name JSON value data types + /// The data types to store a JSON value. These types are derived from + /// the template arguments passed to class @ref basic_json. + /// @{ + +#if defined(JSON_HAS_CPP_14) + // Use transparent comparator if possible, combined with perfect forwarding + // on find() and count() calls prevents unnecessary string construction. + using object_comparator_t = std::less<>; +#else + using object_comparator_t = std::less; +#endif + + /*! + @brief a type for an object + + [RFC 8259](https://tools.ietf.org/html/rfc8259) describes JSON objects as follows: + > An object is an unordered collection of zero or more name/value pairs, + > where a name is a string and a value is a string, number, boolean, null, + > object, or array. + + To store objects in C++, a type is defined by the template parameters + described below. + + @tparam ObjectType the container to store objects (e.g., `std::map` or + `std::unordered_map`) + @tparam StringType the type of the keys or names (e.g., `std::string`). + The comparison function `std::less` is used to order elements + inside the container. + @tparam AllocatorType the allocator to use for objects (e.g., + `std::allocator`) + + #### Default type + + With the default values for @a ObjectType (`std::map`), @a StringType + (`std::string`), and @a AllocatorType (`std::allocator`), the default + value for @a object_t is: + + @code {.cpp} + std::map< + std::string, // key_type + basic_json, // value_type + std::less, // key_compare + std::allocator> // allocator_type + > + @endcode + + #### Behavior + + The choice of @a object_t influences the behavior of the JSON class. With + the default type, objects have the following behavior: + + - When all names are unique, objects will be interoperable in the sense + that all software implementations receiving that object will agree on + the name-value mappings. + - When the names within an object are not unique, it is unspecified which + one of the values for a given key will be chosen. For instance, + `{"key": 2, "key": 1}` could be equal to either `{"key": 1}` or + `{"key": 2}`. + - Internally, name/value pairs are stored in lexicographical order of the + names. Objects will also be serialized (see @ref dump) in this order. + For instance, `{"b": 1, "a": 2}` and `{"a": 2, "b": 1}` will be stored + and serialized as `{"a": 2, "b": 1}`. + - When comparing objects, the order of the name/value pairs is irrelevant. + This makes objects interoperable in the sense that they will not be + affected by these differences. For instance, `{"b": 1, "a": 2}` and + `{"a": 2, "b": 1}` will be treated as equal. + + #### Limits + + [RFC 8259](https://tools.ietf.org/html/rfc8259) specifies: + > An implementation may set limits on the maximum depth of nesting. + + In this class, the object's limit of nesting is not explicitly constrained. + However, a maximum depth of nesting may be introduced by the compiler or + runtime environment. A theoretical limit can be queried by calling the + @ref max_size function of a JSON object. + + #### Storage + + Objects are stored as pointers in a @ref basic_json type. That is, for any + access to object values, a pointer of type `object_t*` must be + dereferenced. + + @sa see @ref array_t -- type for an array value + + @since version 1.0.0 + + @note The order name/value pairs are added to the object is *not* + preserved by the library. Therefore, iterating an object may return + name/value pairs in a different order than they were originally stored. In + fact, keys will be traversed in alphabetical order as `std::map` with + `std::less` is used by default. Please note this behavior conforms to [RFC + 8259](https://tools.ietf.org/html/rfc8259), because any order implements the + specified "unordered" nature of JSON objects. + */ + using object_t = ObjectType>>; + + /*! + @brief a type for an array + + [RFC 8259](https://tools.ietf.org/html/rfc8259) describes JSON arrays as follows: + > An array is an ordered sequence of zero or more values. + + To store objects in C++, a type is defined by the template parameters + explained below. + + @tparam ArrayType container type to store arrays (e.g., `std::vector` or + `std::list`) + @tparam AllocatorType allocator to use for arrays (e.g., `std::allocator`) + + #### Default type + + With the default values for @a ArrayType (`std::vector`) and @a + AllocatorType (`std::allocator`), the default value for @a array_t is: + + @code {.cpp} + std::vector< + basic_json, // value_type + std::allocator // allocator_type + > + @endcode + + #### Limits + + [RFC 8259](https://tools.ietf.org/html/rfc8259) specifies: + > An implementation may set limits on the maximum depth of nesting. + + In this class, the array's limit of nesting is not explicitly constrained. + However, a maximum depth of nesting may be introduced by the compiler or + runtime environment. A theoretical limit can be queried by calling the + @ref max_size function of a JSON array. + + #### Storage + + Arrays are stored as pointers in a @ref basic_json type. That is, for any + access to array values, a pointer of type `array_t*` must be dereferenced. + + @sa see @ref object_t -- type for an object value + + @since version 1.0.0 + */ + using array_t = ArrayType>; + + /*! + @brief a type for a string + + [RFC 8259](https://tools.ietf.org/html/rfc8259) describes JSON strings as follows: + > A string is a sequence of zero or more Unicode characters. + + To store objects in C++, a type is defined by the template parameter + described below. Unicode values are split by the JSON class into + byte-sized characters during deserialization. + + @tparam StringType the container to store strings (e.g., `std::string`). + Note this container is used for keys/names in objects, see @ref object_t. + + #### Default type + + With the default values for @a StringType (`std::string`), the default + value for @a string_t is: + + @code {.cpp} + std::string + @endcode + + #### Encoding + + Strings are stored in UTF-8 encoding. Therefore, functions like + `std::string::size()` or `std::string::length()` return the number of + bytes in the string rather than the number of characters or glyphs. + + #### String comparison + + [RFC 8259](https://tools.ietf.org/html/rfc8259) states: + > Software implementations are typically required to test names of object + > members for equality. Implementations that transform the textual + > representation into sequences of Unicode code units and then perform the + > comparison numerically, code unit by code unit, are interoperable in the + > sense that implementations will agree in all cases on equality or + > inequality of two strings. For example, implementations that compare + > strings with escaped characters unconverted may incorrectly find that + > `"a\\b"` and `"a\u005Cb"` are not equal. + + This implementation is interoperable as it does compare strings code unit + by code unit. + + #### Storage + + String values are stored as pointers in a @ref basic_json type. That is, + for any access to string values, a pointer of type `string_t*` must be + dereferenced. + + @since version 1.0.0 + */ + using string_t = StringType; + + /*! + @brief a type for a boolean + + [RFC 8259](https://tools.ietf.org/html/rfc8259) implicitly describes a boolean as a + type which differentiates the two literals `true` and `false`. + + To store objects in C++, a type is defined by the template parameter @a + BooleanType which chooses the type to use. + + #### Default type + + With the default values for @a BooleanType (`bool`), the default value for + @a boolean_t is: + + @code {.cpp} + bool + @endcode + + #### Storage + + Boolean values are stored directly inside a @ref basic_json type. + + @since version 1.0.0 + */ + using boolean_t = BooleanType; + + /*! + @brief a type for a number (integer) + + [RFC 8259](https://tools.ietf.org/html/rfc8259) describes numbers as follows: + > The representation of numbers is similar to that used in most + > programming languages. A number is represented in base 10 using decimal + > digits. It contains an integer component that may be prefixed with an + > optional minus sign, which may be followed by a fraction part and/or an + > exponent part. Leading zeros are not allowed. (...) Numeric values that + > cannot be represented in the grammar below (such as Infinity and NaN) + > are not permitted. + + This description includes both integer and floating-point numbers. + However, C++ allows more precise storage if it is known whether the number + is a signed integer, an unsigned integer or a floating-point number. + Therefore, three different types, @ref number_integer_t, @ref + number_unsigned_t and @ref number_float_t are used. + + To store integer numbers in C++, a type is defined by the template + parameter @a NumberIntegerType which chooses the type to use. + + #### Default type + + With the default values for @a NumberIntegerType (`int64_t`), the default + value for @a number_integer_t is: + + @code {.cpp} + int64_t + @endcode + + #### Default behavior + + - The restrictions about leading zeros is not enforced in C++. Instead, + leading zeros in integer literals lead to an interpretation as octal + number. Internally, the value will be stored as decimal number. For + instance, the C++ integer literal `010` will be serialized to `8`. + During deserialization, leading zeros yield an error. + - Not-a-number (NaN) values will be serialized to `null`. + + #### Limits + + [RFC 8259](https://tools.ietf.org/html/rfc8259) specifies: + > An implementation may set limits on the range and precision of numbers. + + When the default type is used, the maximal integer number that can be + stored is `9223372036854775807` (INT64_MAX) and the minimal integer number + that can be stored is `-9223372036854775808` (INT64_MIN). Integer numbers + that are out of range will yield over/underflow when used in a + constructor. During deserialization, too large or small integer numbers + will be automatically be stored as @ref number_unsigned_t or @ref + number_float_t. + + [RFC 8259](https://tools.ietf.org/html/rfc8259) further states: + > Note that when such software is used, numbers that are integers and are + > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense + > that implementations will agree exactly on their numeric values. + + As this range is a subrange of the exactly supported range [INT64_MIN, + INT64_MAX], this class's integer type is interoperable. + + #### Storage + + Integer number values are stored directly inside a @ref basic_json type. + + @sa see @ref number_float_t -- type for number values (floating-point) + + @sa see @ref number_unsigned_t -- type for number values (unsigned integer) + + @since version 1.0.0 + */ + using number_integer_t = NumberIntegerType; + + /*! + @brief a type for a number (unsigned) + + [RFC 8259](https://tools.ietf.org/html/rfc8259) describes numbers as follows: + > The representation of numbers is similar to that used in most + > programming languages. A number is represented in base 10 using decimal + > digits. It contains an integer component that may be prefixed with an + > optional minus sign, which may be followed by a fraction part and/or an + > exponent part. Leading zeros are not allowed. (...) Numeric values that + > cannot be represented in the grammar below (such as Infinity and NaN) + > are not permitted. + + This description includes both integer and floating-point numbers. + However, C++ allows more precise storage if it is known whether the number + is a signed integer, an unsigned integer or a floating-point number. + Therefore, three different types, @ref number_integer_t, @ref + number_unsigned_t and @ref number_float_t are used. + + To store unsigned integer numbers in C++, a type is defined by the + template parameter @a NumberUnsignedType which chooses the type to use. + + #### Default type + + With the default values for @a NumberUnsignedType (`uint64_t`), the + default value for @a number_unsigned_t is: + + @code {.cpp} + uint64_t + @endcode + + #### Default behavior + + - The restrictions about leading zeros is not enforced in C++. Instead, + leading zeros in integer literals lead to an interpretation as octal + number. Internally, the value will be stored as decimal number. For + instance, the C++ integer literal `010` will be serialized to `8`. + During deserialization, leading zeros yield an error. + - Not-a-number (NaN) values will be serialized to `null`. + + #### Limits + + [RFC 8259](https://tools.ietf.org/html/rfc8259) specifies: + > An implementation may set limits on the range and precision of numbers. + + When the default type is used, the maximal integer number that can be + stored is `18446744073709551615` (UINT64_MAX) and the minimal integer + number that can be stored is `0`. Integer numbers that are out of range + will yield over/underflow when used in a constructor. During + deserialization, too large or small integer numbers will be automatically + be stored as @ref number_integer_t or @ref number_float_t. + + [RFC 8259](https://tools.ietf.org/html/rfc8259) further states: + > Note that when such software is used, numbers that are integers and are + > in the range \f$[-2^{53}+1, 2^{53}-1]\f$ are interoperable in the sense + > that implementations will agree exactly on their numeric values. + + As this range is a subrange (when considered in conjunction with the + number_integer_t type) of the exactly supported range [0, UINT64_MAX], + this class's integer type is interoperable. + + #### Storage + + Integer number values are stored directly inside a @ref basic_json type. + + @sa see @ref number_float_t -- type for number values (floating-point) + @sa see @ref number_integer_t -- type for number values (integer) + + @since version 2.0.0 + */ + using number_unsigned_t = NumberUnsignedType; + + /*! + @brief a type for a number (floating-point) + + [RFC 8259](https://tools.ietf.org/html/rfc8259) describes numbers as follows: + > The representation of numbers is similar to that used in most + > programming languages. A number is represented in base 10 using decimal + > digits. It contains an integer component that may be prefixed with an + > optional minus sign, which may be followed by a fraction part and/or an + > exponent part. Leading zeros are not allowed. (...) Numeric values that + > cannot be represented in the grammar below (such as Infinity and NaN) + > are not permitted. + + This description includes both integer and floating-point numbers. + However, C++ allows more precise storage if it is known whether the number + is a signed integer, an unsigned integer or a floating-point number. + Therefore, three different types, @ref number_integer_t, @ref + number_unsigned_t and @ref number_float_t are used. + + To store floating-point numbers in C++, a type is defined by the template + parameter @a NumberFloatType which chooses the type to use. + + #### Default type + + With the default values for @a NumberFloatType (`double`), the default + value for @a number_float_t is: + + @code {.cpp} + double + @endcode + + #### Default behavior + + - The restrictions about leading zeros is not enforced in C++. Instead, + leading zeros in floating-point literals will be ignored. Internally, + the value will be stored as decimal number. For instance, the C++ + floating-point literal `01.2` will be serialized to `1.2`. During + deserialization, leading zeros yield an error. + - Not-a-number (NaN) values will be serialized to `null`. + + #### Limits + + [RFC 8259](https://tools.ietf.org/html/rfc8259) states: + > This specification allows implementations to set limits on the range and + > precision of numbers accepted. Since software that implements IEEE + > 754-2008 binary64 (double precision) numbers is generally available and + > widely used, good interoperability can be achieved by implementations + > that expect no more precision or range than these provide, in the sense + > that implementations will approximate JSON numbers within the expected + > precision. + + This implementation does exactly follow this approach, as it uses double + precision floating-point numbers. Note values smaller than + `-1.79769313486232e+308` and values greater than `1.79769313486232e+308` + will be stored as NaN internally and be serialized to `null`. + + #### Storage + + Floating-point number values are stored directly inside a @ref basic_json + type. + + @sa see @ref number_integer_t -- type for number values (integer) + + @sa see @ref number_unsigned_t -- type for number values (unsigned integer) + + @since version 1.0.0 + */ + using number_float_t = NumberFloatType; + + /*! + @brief a type for a packed binary type + + This type is a type designed to carry binary data that appears in various + serialized formats, such as CBOR's Major Type 2, MessagePack's bin, and + BSON's generic binary subtype. This type is NOT a part of standard JSON and + exists solely for compatibility with these binary types. As such, it is + simply defined as an ordered sequence of zero or more byte values. + + Additionally, as an implementation detail, the subtype of the binary data is + carried around as a `std::uint8_t`, which is compatible with both of the + binary data formats that use binary subtyping, (though the specific + numbering is incompatible with each other, and it is up to the user to + translate between them). + + [CBOR's RFC 7049](https://tools.ietf.org/html/rfc7049) describes this type + as: + > Major type 2: a byte string. The string's length in bytes is represented + > following the rules for positive integers (major type 0). + + [MessagePack's documentation on the bin type + family](https://github.com/msgpack/msgpack/blob/master/spec.md#bin-format-family) + describes this type as: + > Bin format family stores an byte array in 2, 3, or 5 bytes of extra bytes + > in addition to the size of the byte array. + + [BSON's specifications](http://bsonspec.org/spec.html) describe several + binary types; however, this type is intended to represent the generic binary + type which has the description: + > Generic binary subtype - This is the most commonly used binary subtype and + > should be the 'default' for drivers and tools. + + None of these impose any limitations on the internal representation other + than the basic unit of storage be some type of array whose parts are + decomposable into bytes. + + The default representation of this binary format is a + `std::vector`, which is a very common way to represent a byte + array in modern C++. + + #### Default type + + The default values for @a BinaryType is `std::vector` + + #### Storage + + Binary Arrays are stored as pointers in a @ref basic_json type. That is, + for any access to array values, a pointer of the type `binary_t*` must be + dereferenced. + + #### Notes on subtypes + + - CBOR + - Binary values are represented as byte strings. Subtypes are serialized + as tagged values. + - MessagePack + - If a subtype is given and the binary array contains exactly 1, 2, 4, 8, + or 16 elements, the fixext family (fixext1, fixext2, fixext4, fixext8) + is used. For other sizes, the ext family (ext8, ext16, ext32) is used. + The subtype is then added as singed 8-bit integer. + - If no subtype is given, the bin family (bin8, bin16, bin32) is used. + - BSON + - If a subtype is given, it is used and added as unsigned 8-bit integer. + - If no subtype is given, the generic binary subtype 0x00 is used. + + @sa see @ref binary -- create a binary array + + @since version 3.8.0 + */ + using binary_t = nlohmann::byte_container_with_subtype; + /// @} + + private: + + /// helper for exception-safe object creation + template + JSON_HEDLEY_RETURNS_NON_NULL + static T* create(Args&& ... args) + { + AllocatorType alloc; + using AllocatorTraits = std::allocator_traits>; + + auto deleter = [&](T * obj) + { + AllocatorTraits::deallocate(alloc, obj, 1); + }; + std::unique_ptr obj(AllocatorTraits::allocate(alloc, 1), deleter); + AllocatorTraits::construct(alloc, obj.get(), std::forward(args)...); + JSON_ASSERT(obj != nullptr); + return obj.release(); + } + + //////////////////////// + // JSON value storage // + //////////////////////// + + JSON_PRIVATE_UNLESS_TESTED: + /*! + @brief a JSON value + + The actual storage for a JSON value of the @ref basic_json class. This + union combines the different storage types for the JSON value types + defined in @ref value_t. + + JSON type | value_t type | used type + --------- | --------------- | ------------------------ + object | object | pointer to @ref object_t + array | array | pointer to @ref array_t + string | string | pointer to @ref string_t + boolean | boolean | @ref boolean_t + number | number_integer | @ref number_integer_t + number | number_unsigned | @ref number_unsigned_t + number | number_float | @ref number_float_t + binary | binary | pointer to @ref binary_t + null | null | *no value is stored* + + @note Variable-length types (objects, arrays, and strings) are stored as + pointers. The size of the union should not exceed 64 bits if the default + value types are used. + + @since version 1.0.0 + */ + union json_value + { + /// object (stored with pointer to save storage) + object_t* object; + /// array (stored with pointer to save storage) + array_t* array; + /// string (stored with pointer to save storage) + string_t* string; + /// binary (stored with pointer to save storage) + binary_t* binary; + /// boolean + boolean_t boolean; + /// number (integer) + number_integer_t number_integer; + /// number (unsigned integer) + number_unsigned_t number_unsigned; + /// number (floating-point) + number_float_t number_float; + + /// default constructor (for null values) + json_value() = default; + /// constructor for booleans + json_value(boolean_t v) noexcept : boolean(v) {} + /// constructor for numbers (integer) + json_value(number_integer_t v) noexcept : number_integer(v) {} + /// constructor for numbers (unsigned) + json_value(number_unsigned_t v) noexcept : number_unsigned(v) {} + /// constructor for numbers (floating-point) + json_value(number_float_t v) noexcept : number_float(v) {} + /// constructor for empty values of a given type + json_value(value_t t) + { + switch (t) + { + case value_t::object: + { + object = create(); + break; + } + + case value_t::array: + { + array = create(); + break; + } + + case value_t::string: + { + string = create(""); + break; + } + + case value_t::binary: + { + binary = create(); + break; + } + + case value_t::boolean: + { + boolean = boolean_t(false); + break; + } + + case value_t::number_integer: + { + number_integer = number_integer_t(0); + break; + } + + case value_t::number_unsigned: + { + number_unsigned = number_unsigned_t(0); + break; + } + + case value_t::number_float: + { + number_float = number_float_t(0.0); + break; + } + + case value_t::null: + { + object = nullptr; // silence warning, see #821 + break; + } + + case value_t::discarded: + default: + { + object = nullptr; // silence warning, see #821 + if (JSON_HEDLEY_UNLIKELY(t == value_t::null)) + { + JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.10.4", basic_json())); // LCOV_EXCL_LINE + } + break; + } + } + } + + /// constructor for strings + json_value(const string_t& value) + { + string = create(value); + } + + /// constructor for rvalue strings + json_value(string_t&& value) + { + string = create(std::move(value)); + } + + /// constructor for objects + json_value(const object_t& value) + { + object = create(value); + } + + /// constructor for rvalue objects + json_value(object_t&& value) + { + object = create(std::move(value)); + } + + /// constructor for arrays + json_value(const array_t& value) + { + array = create(value); + } + + /// constructor for rvalue arrays + json_value(array_t&& value) + { + array = create(std::move(value)); + } + + /// constructor for binary arrays + json_value(const typename binary_t::container_type& value) + { + binary = create(value); + } + + /// constructor for rvalue binary arrays + json_value(typename binary_t::container_type&& value) + { + binary = create(std::move(value)); + } + + /// constructor for binary arrays (internal type) + json_value(const binary_t& value) + { + binary = create(value); + } + + /// constructor for rvalue binary arrays (internal type) + json_value(binary_t&& value) + { + binary = create(std::move(value)); + } + + void destroy(value_t t) + { + if (t == value_t::array || t == value_t::object) + { + // flatten the current json_value to a heap-allocated stack + std::vector stack; + + // move the top-level items to stack + if (t == value_t::array) + { + stack.reserve(array->size()); + std::move(array->begin(), array->end(), std::back_inserter(stack)); + } + else + { + stack.reserve(object->size()); + for (auto&& it : *object) + { + stack.push_back(std::move(it.second)); + } + } + + while (!stack.empty()) + { + // move the last item to local variable to be processed + basic_json current_item(std::move(stack.back())); + stack.pop_back(); + + // if current_item is array/object, move + // its children to the stack to be processed later + if (current_item.is_array()) + { + std::move(current_item.m_value.array->begin(), current_item.m_value.array->end(), std::back_inserter(stack)); + + current_item.m_value.array->clear(); + } + else if (current_item.is_object()) + { + for (auto&& it : *current_item.m_value.object) + { + stack.push_back(std::move(it.second)); + } + + current_item.m_value.object->clear(); + } + + // it's now safe that current_item get destructed + // since it doesn't have any children + } + } + + switch (t) + { + case value_t::object: + { + AllocatorType alloc; + std::allocator_traits::destroy(alloc, object); + std::allocator_traits::deallocate(alloc, object, 1); + break; + } + + case value_t::array: + { + AllocatorType alloc; + std::allocator_traits::destroy(alloc, array); + std::allocator_traits::deallocate(alloc, array, 1); + break; + } + + case value_t::string: + { + AllocatorType alloc; + std::allocator_traits::destroy(alloc, string); + std::allocator_traits::deallocate(alloc, string, 1); + break; + } + + case value_t::binary: + { + AllocatorType alloc; + std::allocator_traits::destroy(alloc, binary); + std::allocator_traits::deallocate(alloc, binary, 1); + break; + } + + case value_t::null: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::discarded: + default: + { + break; + } + } + } + }; + + private: + /*! + @brief checks the class invariants + + This function asserts the class invariants. It needs to be called at the + end of every constructor to make sure that created objects respect the + invariant. Furthermore, it has to be called each time the type of a JSON + value is changed, because the invariant expresses a relationship between + @a m_type and @a m_value. + + Furthermore, the parent relation is checked for arrays and objects: If + @a check_parents true and the value is an array or object, then the + container's elements must have the current value as parent. + + @param[in] check_parents whether the parent relation should be checked. + The value is true by default and should only be set to false + during destruction of objects when the invariant does not + need to hold. + */ + void assert_invariant(bool check_parents = true) const noexcept + { + JSON_ASSERT(m_type != value_t::object || m_value.object != nullptr); + JSON_ASSERT(m_type != value_t::array || m_value.array != nullptr); + JSON_ASSERT(m_type != value_t::string || m_value.string != nullptr); + JSON_ASSERT(m_type != value_t::binary || m_value.binary != nullptr); + +#if JSON_DIAGNOSTICS + JSON_TRY + { + // cppcheck-suppress assertWithSideEffect + JSON_ASSERT(!check_parents || !is_structured() || std::all_of(begin(), end(), [this](const basic_json & j) + { + return j.m_parent == this; + })); + } + JSON_CATCH(...) {} // LCOV_EXCL_LINE +#endif + static_cast(check_parents); + } + + void set_parents() + { +#if JSON_DIAGNOSTICS + switch (m_type) + { + case value_t::array: + { + for (auto& element : *m_value.array) + { + element.m_parent = this; + } + break; + } + + case value_t::object: + { + for (auto& element : *m_value.object) + { + element.second.m_parent = this; + } + break; + } + + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + break; + } +#endif + } + + iterator set_parents(iterator it, typename iterator::difference_type count) + { +#if JSON_DIAGNOSTICS + for (typename iterator::difference_type i = 0; i < count; ++i) + { + (it + i)->m_parent = this; + } +#else + static_cast(count); +#endif + return it; + } + + reference set_parent(reference j, std::size_t old_capacity = std::size_t(-1)) + { +#if JSON_DIAGNOSTICS + if (old_capacity != std::size_t(-1)) + { + // see https://github.com/nlohmann/json/issues/2838 + JSON_ASSERT(type() == value_t::array); + if (JSON_HEDLEY_UNLIKELY(m_value.array->capacity() != old_capacity)) + { + // capacity has changed: update all parents + set_parents(); + return j; + } + } + + // ordered_json uses a vector internally, so pointers could have + // been invalidated; see https://github.com/nlohmann/json/issues/2962 +#ifdef JSON_HEDLEY_MSVC_VERSION +#pragma warning(push ) +#pragma warning(disable : 4127) // ignore warning to replace if with if constexpr +#endif + if (detail::is_ordered_map::value) + { + set_parents(); + return j; + } +#ifdef JSON_HEDLEY_MSVC_VERSION +#pragma warning( pop ) +#endif + + j.m_parent = this; +#else + static_cast(j); + static_cast(old_capacity); +#endif + return j; + } + + public: + ////////////////////////// + // JSON parser callback // + ////////////////////////// + + /*! + @brief parser event types + + The parser callback distinguishes the following events: + - `object_start`: the parser read `{` and started to process a JSON object + - `key`: the parser read a key of a value in an object + - `object_end`: the parser read `}` and finished processing a JSON object + - `array_start`: the parser read `[` and started to process a JSON array + - `array_end`: the parser read `]` and finished processing a JSON array + - `value`: the parser finished reading a JSON value + + @image html callback_events.png "Example when certain parse events are triggered" + + @sa see @ref parser_callback_t for more information and examples + */ + using parse_event_t = detail::parse_event_t; + + /*! + @brief per-element parser callback type + + With a parser callback function, the result of parsing a JSON text can be + influenced. When passed to @ref parse, it is called on certain events + (passed as @ref parse_event_t via parameter @a event) with a set recursion + depth @a depth and context JSON value @a parsed. The return value of the + callback function is a boolean indicating whether the element that emitted + the callback shall be kept or not. + + We distinguish six scenarios (determined by the event type) in which the + callback function can be called. The following table describes the values + of the parameters @a depth, @a event, and @a parsed. + + parameter @a event | description | parameter @a depth | parameter @a parsed + ------------------ | ----------- | ------------------ | ------------------- + parse_event_t::object_start | the parser read `{` and started to process a JSON object | depth of the parent of the JSON object | a JSON value with type discarded + parse_event_t::key | the parser read a key of a value in an object | depth of the currently parsed JSON object | a JSON string containing the key + parse_event_t::object_end | the parser read `}` and finished processing a JSON object | depth of the parent of the JSON object | the parsed JSON object + parse_event_t::array_start | the parser read `[` and started to process a JSON array | depth of the parent of the JSON array | a JSON value with type discarded + parse_event_t::array_end | the parser read `]` and finished processing a JSON array | depth of the parent of the JSON array | the parsed JSON array + parse_event_t::value | the parser finished reading a JSON value | depth of the value | the parsed JSON value + + @image html callback_events.png "Example when certain parse events are triggered" + + Discarding a value (i.e., returning `false`) has different effects + depending on the context in which function was called: + + - Discarded values in structured types are skipped. That is, the parser + will behave as if the discarded value was never read. + - In case a value outside a structured type is skipped, it is replaced + with `null`. This case happens if the top-level element is skipped. + + @param[in] depth the depth of the recursion during parsing + + @param[in] event an event of type parse_event_t indicating the context in + the callback function has been called + + @param[in,out] parsed the current intermediate parse result; note that + writing to this value has no effect for parse_event_t::key events + + @return Whether the JSON value which called the function during parsing + should be kept (`true`) or not (`false`). In the latter case, it is either + skipped completely or replaced by an empty discarded object. + + @sa see @ref parse for examples + + @since version 1.0.0 + */ + using parser_callback_t = detail::parser_callback_t; + + ////////////////// + // constructors // + ////////////////// + + /// @name constructors and destructors + /// Constructors of class @ref basic_json, copy/move constructor, copy + /// assignment, static functions creating objects, and the destructor. + /// @{ + + /*! + @brief create an empty value with a given type + + Create an empty JSON value with a given type. The value will be default + initialized with an empty value which depends on the type: + + Value type | initial value + ----------- | ------------- + null | `null` + boolean | `false` + string | `""` + number | `0` + object | `{}` + array | `[]` + binary | empty array + + @param[in] v the type of the value to create + + @complexity Constant. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The following code shows the constructor for different @ref + value_t values,basic_json__value_t} + + @sa see @ref clear() -- restores the postcondition of this constructor + + @since version 1.0.0 + */ + basic_json(const value_t v) + : m_type(v), m_value(v) + { + assert_invariant(); + } + + /*! + @brief create a null object + + Create a `null` JSON value. It either takes a null pointer as parameter + (explicitly creating `null`) or no parameter (implicitly creating `null`). + The passed null pointer itself is not read -- it is only used to choose + the right constructor. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this constructor never throws + exceptions. + + @liveexample{The following code shows the constructor with and without a + null pointer parameter.,basic_json__nullptr_t} + + @since version 1.0.0 + */ + basic_json(std::nullptr_t = nullptr) noexcept + : basic_json(value_t::null) + { + assert_invariant(); + } + + /*! + @brief create a JSON value + + This is a "catch all" constructor for all compatible JSON types; that is, + types for which a `to_json()` method exists. The constructor forwards the + parameter @a val to that method (to `json_serializer::to_json` method + with `U = uncvref_t`, to be exact). + + Template type @a CompatibleType includes, but is not limited to, the + following types: + - **arrays**: @ref array_t and all kinds of compatible containers such as + `std::vector`, `std::deque`, `std::list`, `std::forward_list`, + `std::array`, `std::valarray`, `std::set`, `std::unordered_set`, + `std::multiset`, and `std::unordered_multiset` with a `value_type` from + which a @ref basic_json value can be constructed. + - **objects**: @ref object_t and all kinds of compatible associative + containers such as `std::map`, `std::unordered_map`, `std::multimap`, + and `std::unordered_multimap` with a `key_type` compatible to + @ref string_t and a `value_type` from which a @ref basic_json value can + be constructed. + - **strings**: @ref string_t, string literals, and all compatible string + containers can be used. + - **numbers**: @ref number_integer_t, @ref number_unsigned_t, + @ref number_float_t, and all convertible number types such as `int`, + `size_t`, `int64_t`, `float` or `double` can be used. + - **boolean**: @ref boolean_t / `bool` can be used. + - **binary**: @ref binary_t / `std::vector` may be used, + unfortunately because string literals cannot be distinguished from binary + character arrays by the C++ type system, all types compatible with `const + char*` will be directed to the string constructor instead. This is both + for backwards compatibility, and due to the fact that a binary type is not + a standard JSON type. + + See the examples below. + + @tparam CompatibleType a type such that: + - @a CompatibleType is not derived from `std::istream`, + - @a CompatibleType is not @ref basic_json (to avoid hijacking copy/move + constructors), + - @a CompatibleType is not a different @ref basic_json type (i.e. with different template arguments) + - @a CompatibleType is not a @ref basic_json nested type (e.g., + @ref json_pointer, @ref iterator, etc ...) + - `json_serializer` has a `to_json(basic_json_t&, CompatibleType&&)` method + + @tparam U = `uncvref_t` + + @param[in] val the value to be forwarded to the respective constructor + + @complexity Usually linear in the size of the passed @a val, also + depending on the implementation of the called `to_json()` + method. + + @exceptionsafety Depends on the called constructor. For types directly + supported by the library (i.e., all types for which no `to_json()` function + was provided), strong guarantee holds: if an exception is thrown, there are + no changes to any JSON value. + + @liveexample{The following code shows the constructor with several + compatible types.,basic_json__CompatibleType} + + @since version 2.1.0 + */ + template < typename CompatibleType, + typename U = detail::uncvref_t, + detail::enable_if_t < + !detail::is_basic_json::value && detail::is_compatible_type::value, int > = 0 > + basic_json(CompatibleType && val) noexcept(noexcept( // NOLINT(bugprone-forwarding-reference-overload,bugprone-exception-escape) + JSONSerializer::to_json(std::declval(), + std::forward(val)))) + { + JSONSerializer::to_json(*this, std::forward(val)); + set_parents(); + assert_invariant(); + } + + /*! + @brief create a JSON value from an existing one + + This is a constructor for existing @ref basic_json types. + It does not hijack copy/move constructors, since the parameter has different + template arguments than the current ones. + + The constructor tries to convert the internal @ref m_value of the parameter. + + @tparam BasicJsonType a type such that: + - @a BasicJsonType is a @ref basic_json type. + - @a BasicJsonType has different template arguments than @ref basic_json_t. + + @param[in] val the @ref basic_json value to be converted. + + @complexity Usually linear in the size of the passed @a val, also + depending on the implementation of the called `to_json()` + method. + + @exceptionsafety Depends on the called constructor. For types directly + supported by the library (i.e., all types for which no `to_json()` function + was provided), strong guarantee holds: if an exception is thrown, there are + no changes to any JSON value. + + @since version 3.2.0 + */ + template < typename BasicJsonType, + detail::enable_if_t < + detail::is_basic_json::value&& !std::is_same::value, int > = 0 > + basic_json(const BasicJsonType& val) + { + using other_boolean_t = typename BasicJsonType::boolean_t; + using other_number_float_t = typename BasicJsonType::number_float_t; + using other_number_integer_t = typename BasicJsonType::number_integer_t; + using other_number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using other_string_t = typename BasicJsonType::string_t; + using other_object_t = typename BasicJsonType::object_t; + using other_array_t = typename BasicJsonType::array_t; + using other_binary_t = typename BasicJsonType::binary_t; + + switch (val.type()) + { + case value_t::boolean: + JSONSerializer::to_json(*this, val.template get()); + break; + case value_t::number_float: + JSONSerializer::to_json(*this, val.template get()); + break; + case value_t::number_integer: + JSONSerializer::to_json(*this, val.template get()); + break; + case value_t::number_unsigned: + JSONSerializer::to_json(*this, val.template get()); + break; + case value_t::string: + JSONSerializer::to_json(*this, val.template get_ref()); + break; + case value_t::object: + JSONSerializer::to_json(*this, val.template get_ref()); + break; + case value_t::array: + JSONSerializer::to_json(*this, val.template get_ref()); + break; + case value_t::binary: + JSONSerializer::to_json(*this, val.template get_ref()); + break; + case value_t::null: + *this = nullptr; + break; + case value_t::discarded: + m_type = value_t::discarded; + break; + default: // LCOV_EXCL_LINE + JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE + } + set_parents(); + assert_invariant(); + } + + /*! + @brief create a container (array or object) from an initializer list + + Creates a JSON value of type array or object from the passed initializer + list @a init. In case @a type_deduction is `true` (default), the type of + the JSON value to be created is deducted from the initializer list @a init + according to the following rules: + + 1. If the list is empty, an empty JSON object value `{}` is created. + 2. If the list consists of pairs whose first element is a string, a JSON + object value is created where the first elements of the pairs are + treated as keys and the second elements are as values. + 3. In all other cases, an array is created. + + The rules aim to create the best fit between a C++ initializer list and + JSON values. The rationale is as follows: + + 1. The empty initializer list is written as `{}` which is exactly an empty + JSON object. + 2. C++ has no way of describing mapped types other than to list a list of + pairs. As JSON requires that keys must be of type string, rule 2 is the + weakest constraint one can pose on initializer lists to interpret them + as an object. + 3. In all other cases, the initializer list could not be interpreted as + JSON object type, so interpreting it as JSON array type is safe. + + With the rules described above, the following JSON values cannot be + expressed by an initializer list: + + - the empty array (`[]`): use @ref array(initializer_list_t) + with an empty initializer list in this case + - arrays whose elements satisfy rule 2: use @ref + array(initializer_list_t) with the same initializer list + in this case + + @note When used without parentheses around an empty initializer list, @ref + basic_json() is called instead of this function, yielding the JSON null + value. + + @param[in] init initializer list with JSON values + + @param[in] type_deduction internal parameter; when set to `true`, the type + of the JSON value is deducted from the initializer list @a init; when set + to `false`, the type provided via @a manual_type is forced. This mode is + used by the functions @ref array(initializer_list_t) and + @ref object(initializer_list_t). + + @param[in] manual_type internal parameter; when @a type_deduction is set + to `false`, the created JSON value will use the provided type (only @ref + value_t::array and @ref value_t::object are valid); when @a type_deduction + is set to `true`, this parameter has no effect + + @throw type_error.301 if @a type_deduction is `false`, @a manual_type is + `value_t::object`, but @a init contains an element which is not a pair + whose first element is a string. In this case, the constructor could not + create an object. If @a type_deduction would have be `true`, an array + would have been created. See @ref object(initializer_list_t) + for an example. + + @complexity Linear in the size of the initializer list @a init. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The example below shows how JSON values are created from + initializer lists.,basic_json__list_init_t} + + @sa see @ref array(initializer_list_t) -- create a JSON array + value from an initializer list + @sa see @ref object(initializer_list_t) -- create a JSON object + value from an initializer list + + @since version 1.0.0 + */ + basic_json(initializer_list_t init, + bool type_deduction = true, + value_t manual_type = value_t::array) + { + // check if each element is an array with two elements whose first + // element is a string + bool is_an_object = std::all_of(init.begin(), init.end(), + [](const detail::json_ref& element_ref) + { + return element_ref->is_array() && element_ref->size() == 2 && (*element_ref)[0].is_string(); + }); + + // adjust type if type deduction is not wanted + if (!type_deduction) + { + // if array is wanted, do not create an object though possible + if (manual_type == value_t::array) + { + is_an_object = false; + } + + // if object is wanted but impossible, throw an exception + if (JSON_HEDLEY_UNLIKELY(manual_type == value_t::object && !is_an_object)) + { + JSON_THROW(type_error::create(301, "cannot create object from initializer list", basic_json())); + } + } + + if (is_an_object) + { + // the initializer list is a list of pairs -> create object + m_type = value_t::object; + m_value = value_t::object; + + for (auto& element_ref : init) + { + auto element = element_ref.moved_or_copied(); + m_value.object->emplace( + std::move(*((*element.m_value.array)[0].m_value.string)), + std::move((*element.m_value.array)[1])); + } + } + else + { + // the initializer list describes an array -> create array + m_type = value_t::array; + m_value.array = create(init.begin(), init.end()); + } + + set_parents(); + assert_invariant(); + } + + /*! + @brief explicitly create a binary array (without subtype) + + Creates a JSON binary array value from a given binary container. Binary + values are part of various binary formats, such as CBOR, MessagePack, and + BSON. This constructor is used to create a value for serialization to those + formats. + + @note Note, this function exists because of the difficulty in correctly + specifying the correct template overload in the standard value ctor, as both + JSON arrays and JSON binary arrays are backed with some form of a + `std::vector`. Because JSON binary arrays are a non-standard extension it + was decided that it would be best to prevent automatic initialization of a + binary array type, for backwards compatibility and so it does not happen on + accident. + + @param[in] init container containing bytes to use as binary type + + @return JSON binary array value + + @complexity Linear in the size of @a init. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @since version 3.8.0 + */ + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json binary(const typename binary_t::container_type& init) + { + auto res = basic_json(); + res.m_type = value_t::binary; + res.m_value = init; + return res; + } + + /*! + @brief explicitly create a binary array (with subtype) + + Creates a JSON binary array value from a given binary container. Binary + values are part of various binary formats, such as CBOR, MessagePack, and + BSON. This constructor is used to create a value for serialization to those + formats. + + @note Note, this function exists because of the difficulty in correctly + specifying the correct template overload in the standard value ctor, as both + JSON arrays and JSON binary arrays are backed with some form of a + `std::vector`. Because JSON binary arrays are a non-standard extension it + was decided that it would be best to prevent automatic initialization of a + binary array type, for backwards compatibility and so it does not happen on + accident. + + @param[in] init container containing bytes to use as binary type + @param[in] subtype subtype to use in MessagePack and BSON + + @return JSON binary array value + + @complexity Linear in the size of @a init. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @since version 3.8.0 + */ + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json binary(const typename binary_t::container_type& init, typename binary_t::subtype_type subtype) + { + auto res = basic_json(); + res.m_type = value_t::binary; + res.m_value = binary_t(init, subtype); + return res; + } + + /// @copydoc binary(const typename binary_t::container_type&) + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json binary(typename binary_t::container_type&& init) + { + auto res = basic_json(); + res.m_type = value_t::binary; + res.m_value = std::move(init); + return res; + } + + /// @copydoc binary(const typename binary_t::container_type&, typename binary_t::subtype_type) + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json binary(typename binary_t::container_type&& init, typename binary_t::subtype_type subtype) + { + auto res = basic_json(); + res.m_type = value_t::binary; + res.m_value = binary_t(std::move(init), subtype); + return res; + } + + /*! + @brief explicitly create an array from an initializer list + + Creates a JSON array value from a given initializer list. That is, given a + list of values `a, b, c`, creates the JSON value `[a, b, c]`. If the + initializer list is empty, the empty array `[]` is created. + + @note This function is only needed to express two edge cases that cannot + be realized with the initializer list constructor (@ref + basic_json(initializer_list_t, bool, value_t)). These cases + are: + 1. creating an array whose elements are all pairs whose first element is a + string -- in this case, the initializer list constructor would create an + object, taking the first elements as keys + 2. creating an empty array -- passing the empty initializer list to the + initializer list constructor yields an empty object + + @param[in] init initializer list with JSON values to create an array from + (optional) + + @return JSON array value + + @complexity Linear in the size of @a init. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The following code shows an example for the `array` + function.,array} + + @sa see @ref basic_json(initializer_list_t, bool, value_t) -- + create a JSON value from an initializer list + @sa see @ref object(initializer_list_t) -- create a JSON object + value from an initializer list + + @since version 1.0.0 + */ + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json array(initializer_list_t init = {}) + { + return basic_json(init, false, value_t::array); + } + + /*! + @brief explicitly create an object from an initializer list + + Creates a JSON object value from a given initializer list. The initializer + lists elements must be pairs, and their first elements must be strings. If + the initializer list is empty, the empty object `{}` is created. + + @note This function is only added for symmetry reasons. In contrast to the + related function @ref array(initializer_list_t), there are + no cases which can only be expressed by this function. That is, any + initializer list @a init can also be passed to the initializer list + constructor @ref basic_json(initializer_list_t, bool, value_t). + + @param[in] init initializer list to create an object from (optional) + + @return JSON object value + + @throw type_error.301 if @a init is not a list of pairs whose first + elements are strings. In this case, no object can be created. When such a + value is passed to @ref basic_json(initializer_list_t, bool, value_t), + an array would have been created from the passed initializer list @a init. + See example below. + + @complexity Linear in the size of @a init. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The following code shows an example for the `object` + function.,object} + + @sa see @ref basic_json(initializer_list_t, bool, value_t) -- + create a JSON value from an initializer list + @sa see @ref array(initializer_list_t) -- create a JSON array + value from an initializer list + + @since version 1.0.0 + */ + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json object(initializer_list_t init = {}) + { + return basic_json(init, false, value_t::object); + } + + /*! + @brief construct an array with count copies of given value + + Constructs a JSON array value by creating @a cnt copies of a passed value. + In case @a cnt is `0`, an empty array is created. + + @param[in] cnt the number of JSON copies of @a val to create + @param[in] val the JSON value to copy + + @post `std::distance(begin(),end()) == cnt` holds. + + @complexity Linear in @a cnt. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The following code shows examples for the @ref + basic_json(size_type\, const basic_json&) + constructor.,basic_json__size_type_basic_json} + + @since version 1.0.0 + */ + basic_json(size_type cnt, const basic_json& val) + : m_type(value_t::array) + { + m_value.array = create(cnt, val); + set_parents(); + assert_invariant(); + } + + /*! + @brief construct a JSON container given an iterator range + + Constructs the JSON value with the contents of the range `[first, last)`. + The semantics depends on the different types a JSON value can have: + - In case of a null type, invalid_iterator.206 is thrown. + - In case of other primitive types (number, boolean, or string), @a first + must be `begin()` and @a last must be `end()`. In this case, the value is + copied. Otherwise, invalid_iterator.204 is thrown. + - In case of structured types (array, object), the constructor behaves as + similar versions for `std::vector` or `std::map`; that is, a JSON array + or object is constructed from the values in the range. + + @tparam InputIT an input iterator type (@ref iterator or @ref + const_iterator) + + @param[in] first begin of the range to copy from (included) + @param[in] last end of the range to copy from (excluded) + + @pre Iterators @a first and @a last must be initialized. **This + precondition is enforced with an assertion (see warning).** If + assertions are switched off, a violation of this precondition yields + undefined behavior. + + @pre Range `[first, last)` is valid. Usually, this precondition cannot be + checked efficiently. Only certain edge cases are detected; see the + description of the exceptions below. A violation of this precondition + yields undefined behavior. + + @warning A precondition is enforced with a runtime assertion that will + result in calling `std::abort` if this precondition is not met. + Assertions can be disabled by defining `NDEBUG` at compile time. + See https://en.cppreference.com/w/cpp/error/assert for more + information. + + @throw invalid_iterator.201 if iterators @a first and @a last are not + compatible (i.e., do not belong to the same JSON value). In this case, + the range `[first, last)` is undefined. + @throw invalid_iterator.204 if iterators @a first and @a last belong to a + primitive type (number, boolean, or string), but @a first does not point + to the first element any more. In this case, the range `[first, last)` is + undefined. See example code below. + @throw invalid_iterator.206 if iterators @a first and @a last belong to a + null value. In this case, the range `[first, last)` is undefined. + + @complexity Linear in distance between @a first and @a last. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @liveexample{The example below shows several ways to create JSON values by + specifying a subrange with iterators.,basic_json__InputIt_InputIt} + + @since version 1.0.0 + */ + template < class InputIT, typename std::enable_if < + std::is_same::value || + std::is_same::value, int >::type = 0 > + basic_json(InputIT first, InputIT last) + { + JSON_ASSERT(first.m_object != nullptr); + JSON_ASSERT(last.m_object != nullptr); + + // make sure iterator fits the current value + if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object)) + { + JSON_THROW(invalid_iterator::create(201, "iterators are not compatible", basic_json())); + } + + // copy type from first iterator + m_type = first.m_object->m_type; + + // check if iterator range is complete for primitive values + switch (m_type) + { + case value_t::boolean: + case value_t::number_float: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::string: + { + if (JSON_HEDLEY_UNLIKELY(!first.m_it.primitive_iterator.is_begin() + || !last.m_it.primitive_iterator.is_end())) + { + JSON_THROW(invalid_iterator::create(204, "iterators out of range", *first.m_object)); + } + break; + } + + case value_t::null: + case value_t::object: + case value_t::array: + case value_t::binary: + case value_t::discarded: + default: + break; + } + + switch (m_type) + { + case value_t::number_integer: + { + m_value.number_integer = first.m_object->m_value.number_integer; + break; + } + + case value_t::number_unsigned: + { + m_value.number_unsigned = first.m_object->m_value.number_unsigned; + break; + } + + case value_t::number_float: + { + m_value.number_float = first.m_object->m_value.number_float; + break; + } + + case value_t::boolean: + { + m_value.boolean = first.m_object->m_value.boolean; + break; + } + + case value_t::string: + { + m_value = *first.m_object->m_value.string; + break; + } + + case value_t::object: + { + m_value.object = create(first.m_it.object_iterator, + last.m_it.object_iterator); + break; + } + + case value_t::array: + { + m_value.array = create(first.m_it.array_iterator, + last.m_it.array_iterator); + break; + } + + case value_t::binary: + { + m_value = *first.m_object->m_value.binary; + break; + } + + case value_t::null: + case value_t::discarded: + default: + JSON_THROW(invalid_iterator::create(206, "cannot construct with iterators from " + std::string(first.m_object->type_name()), *first.m_object)); + } + + set_parents(); + assert_invariant(); + } + + + /////////////////////////////////////// + // other constructors and destructor // + /////////////////////////////////////// + + template, + std::is_same>::value, int> = 0 > + basic_json(const JsonRef& ref) : basic_json(ref.moved_or_copied()) {} + + /*! + @brief copy constructor + + Creates a copy of a given JSON value. + + @param[in] other the JSON value to copy + + @post `*this == other` + + @complexity Linear in the size of @a other. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + + @requirement This function helps `basic_json` satisfying the + [Container](https://en.cppreference.com/w/cpp/named_req/Container) + requirements: + - The complexity is linear. + - As postcondition, it holds: `other == basic_json(other)`. + + @liveexample{The following code shows an example for the copy + constructor.,basic_json__basic_json} + + @since version 1.0.0 + */ + basic_json(const basic_json& other) + : m_type(other.m_type) + { + // check of passed value is valid + other.assert_invariant(); + + switch (m_type) + { + case value_t::object: + { + m_value = *other.m_value.object; + break; + } + + case value_t::array: + { + m_value = *other.m_value.array; + break; + } + + case value_t::string: + { + m_value = *other.m_value.string; + break; + } + + case value_t::boolean: + { + m_value = other.m_value.boolean; + break; + } + + case value_t::number_integer: + { + m_value = other.m_value.number_integer; + break; + } + + case value_t::number_unsigned: + { + m_value = other.m_value.number_unsigned; + break; + } + + case value_t::number_float: + { + m_value = other.m_value.number_float; + break; + } + + case value_t::binary: + { + m_value = *other.m_value.binary; + break; + } + + case value_t::null: + case value_t::discarded: + default: + break; + } + + set_parents(); + assert_invariant(); + } + + /*! + @brief move constructor + + Move constructor. Constructs a JSON value with the contents of the given + value @a other using move semantics. It "steals" the resources from @a + other and leaves it as JSON null value. + + @param[in,out] other value to move to this object + + @post `*this` has the same value as @a other before the call. + @post @a other is a JSON null value. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this constructor never throws + exceptions. + + @requirement This function helps `basic_json` satisfying the + [MoveConstructible](https://en.cppreference.com/w/cpp/named_req/MoveConstructible) + requirements. + + @liveexample{The code below shows the move constructor explicitly called + via std::move.,basic_json__moveconstructor} + + @since version 1.0.0 + */ + basic_json(basic_json&& other) noexcept + : m_type(std::move(other.m_type)), + m_value(std::move(other.m_value)) + { + // check that passed value is valid + other.assert_invariant(false); + + // invalidate payload + other.m_type = value_t::null; + other.m_value = {}; + + set_parents(); + assert_invariant(); + } + + /*! + @brief copy assignment + + Copy assignment operator. Copies a JSON value via the "copy and swap" + strategy: It is expressed in terms of the copy constructor, destructor, + and the `swap()` member function. + + @param[in] other value to copy from + + @complexity Linear. + + @requirement This function helps `basic_json` satisfying the + [Container](https://en.cppreference.com/w/cpp/named_req/Container) + requirements: + - The complexity is linear. + + @liveexample{The code below shows and example for the copy assignment. It + creates a copy of value `a` which is then swapped with `b`. Finally\, the + copy of `a` (which is the null value after the swap) is + destroyed.,basic_json__copyassignment} + + @since version 1.0.0 + */ + basic_json& operator=(basic_json other) noexcept ( + std::is_nothrow_move_constructible::value&& + std::is_nothrow_move_assignable::value&& + std::is_nothrow_move_constructible::value&& + std::is_nothrow_move_assignable::value + ) + { + // check that passed value is valid + other.assert_invariant(); + + using std::swap; + swap(m_type, other.m_type); + swap(m_value, other.m_value); + + set_parents(); + assert_invariant(); + return *this; + } + + /*! + @brief destructor + + Destroys the JSON value and frees all allocated memory. + + @complexity Linear. + + @requirement This function helps `basic_json` satisfying the + [Container](https://en.cppreference.com/w/cpp/named_req/Container) + requirements: + - The complexity is linear. + - All stored elements are destroyed and all memory is freed. + + @since version 1.0.0 + */ + ~basic_json() noexcept + { + assert_invariant(false); + m_value.destroy(m_type); + } + + /// @} + + public: + /////////////////////// + // object inspection // + /////////////////////// + + /// @name object inspection + /// Functions to inspect the type of a JSON value. + /// @{ + + /*! + @brief serialization + + Serialization function for JSON values. The function tries to mimic + Python's `json.dumps()` function, and currently supports its @a indent + and @a ensure_ascii parameters. + + @param[in] indent If indent is nonnegative, then array elements and object + members will be pretty-printed with that indent level. An indent level of + `0` will only insert newlines. `-1` (the default) selects the most compact + representation. + @param[in] indent_char The character to use for indentation if @a indent is + greater than `0`. The default is ` ` (space). + @param[in] ensure_ascii If @a ensure_ascii is true, all non-ASCII characters + in the output are escaped with `\uXXXX` sequences, and the result consists + of ASCII characters only. + @param[in] error_handler how to react on decoding errors; there are three + possible values: `strict` (throws and exception in case a decoding error + occurs; default), `replace` (replace invalid UTF-8 sequences with U+FFFD), + and `ignore` (ignore invalid UTF-8 sequences during serialization; all + bytes are copied to the output unchanged). + + @return string containing the serialization of the JSON value + + @throw type_error.316 if a string stored inside the JSON value is not + UTF-8 encoded and @a error_handler is set to strict + + @note Binary values are serialized as object containing two keys: + - "bytes": an array of bytes as integers + - "subtype": the subtype as integer or "null" if the binary has no subtype + + @complexity Linear. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @liveexample{The following example shows the effect of different @a indent\, + @a indent_char\, and @a ensure_ascii parameters to the result of the + serialization.,dump} + + @see https://docs.python.org/2/library/json.html#json.dump + + @since version 1.0.0; indentation character @a indent_char, option + @a ensure_ascii and exceptions added in version 3.0.0; error + handlers added in version 3.4.0; serialization of binary values added + in version 3.8.0. + */ + string_t dump(const int indent = -1, + const char indent_char = ' ', + const bool ensure_ascii = false, + const error_handler_t error_handler = error_handler_t::strict) const + { + string_t result; + serializer s(detail::output_adapter(result), indent_char, error_handler); + + if (indent >= 0) + { + s.dump(*this, true, ensure_ascii, static_cast(indent)); + } + else + { + s.dump(*this, false, ensure_ascii, 0); + } + + return result; + } + + /*! + @brief return the type of the JSON value (explicit) + + Return the type of the JSON value as a value from the @ref value_t + enumeration. + + @return the type of the JSON value + Value type | return value + ------------------------- | ------------------------- + null | value_t::null + boolean | value_t::boolean + string | value_t::string + number (integer) | value_t::number_integer + number (unsigned integer) | value_t::number_unsigned + number (floating-point) | value_t::number_float + object | value_t::object + array | value_t::array + binary | value_t::binary + discarded | value_t::discarded + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `type()` for all JSON + types.,type} + + @sa see @ref operator value_t() -- return the type of the JSON value (implicit) + @sa see @ref type_name() -- return the type as string + + @since version 1.0.0 + */ + constexpr value_t type() const noexcept + { + return m_type; + } + + /*! + @brief return whether type is primitive + + This function returns true if and only if the JSON type is primitive + (string, number, boolean, or null). + + @return `true` if type is primitive (string, number, boolean, or null), + `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_primitive()` for all JSON + types.,is_primitive} + + @sa see @ref is_structured() -- returns whether JSON value is structured + @sa see @ref is_null() -- returns whether JSON value is `null` + @sa see @ref is_string() -- returns whether JSON value is a string + @sa see @ref is_boolean() -- returns whether JSON value is a boolean + @sa see @ref is_number() -- returns whether JSON value is a number + @sa see @ref is_binary() -- returns whether JSON value is a binary array + + @since version 1.0.0 + */ + constexpr bool is_primitive() const noexcept + { + return is_null() || is_string() || is_boolean() || is_number() || is_binary(); + } + + /*! + @brief return whether type is structured + + This function returns true if and only if the JSON type is structured + (array or object). + + @return `true` if type is structured (array or object), `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_structured()` for all JSON + types.,is_structured} + + @sa see @ref is_primitive() -- returns whether value is primitive + @sa see @ref is_array() -- returns whether value is an array + @sa see @ref is_object() -- returns whether value is an object + + @since version 1.0.0 + */ + constexpr bool is_structured() const noexcept + { + return is_array() || is_object(); + } + + /*! + @brief return whether value is null + + This function returns true if and only if the JSON value is null. + + @return `true` if type is null, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_null()` for all JSON + types.,is_null} + + @since version 1.0.0 + */ + constexpr bool is_null() const noexcept + { + return m_type == value_t::null; + } + + /*! + @brief return whether value is a boolean + + This function returns true if and only if the JSON value is a boolean. + + @return `true` if type is boolean, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_boolean()` for all JSON + types.,is_boolean} + + @since version 1.0.0 + */ + constexpr bool is_boolean() const noexcept + { + return m_type == value_t::boolean; + } + + /*! + @brief return whether value is a number + + This function returns true if and only if the JSON value is a number. This + includes both integer (signed and unsigned) and floating-point values. + + @return `true` if type is number (regardless whether integer, unsigned + integer or floating-type), `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_number()` for all JSON + types.,is_number} + + @sa see @ref is_number_integer() -- check if value is an integer or unsigned + integer number + @sa see @ref is_number_unsigned() -- check if value is an unsigned integer + number + @sa see @ref is_number_float() -- check if value is a floating-point number + + @since version 1.0.0 + */ + constexpr bool is_number() const noexcept + { + return is_number_integer() || is_number_float(); + } + + /*! + @brief return whether value is an integer number + + This function returns true if and only if the JSON value is a signed or + unsigned integer number. This excludes floating-point values. + + @return `true` if type is an integer or unsigned integer number, `false` + otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_number_integer()` for all + JSON types.,is_number_integer} + + @sa see @ref is_number() -- check if value is a number + @sa see @ref is_number_unsigned() -- check if value is an unsigned integer + number + @sa see @ref is_number_float() -- check if value is a floating-point number + + @since version 1.0.0 + */ + constexpr bool is_number_integer() const noexcept + { + return m_type == value_t::number_integer || m_type == value_t::number_unsigned; + } + + /*! + @brief return whether value is an unsigned integer number + + This function returns true if and only if the JSON value is an unsigned + integer number. This excludes floating-point and signed integer values. + + @return `true` if type is an unsigned integer number, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_number_unsigned()` for all + JSON types.,is_number_unsigned} + + @sa see @ref is_number() -- check if value is a number + @sa see @ref is_number_integer() -- check if value is an integer or unsigned + integer number + @sa see @ref is_number_float() -- check if value is a floating-point number + + @since version 2.0.0 + */ + constexpr bool is_number_unsigned() const noexcept + { + return m_type == value_t::number_unsigned; + } + + /*! + @brief return whether value is a floating-point number + + This function returns true if and only if the JSON value is a + floating-point number. This excludes signed and unsigned integer values. + + @return `true` if type is a floating-point number, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_number_float()` for all + JSON types.,is_number_float} + + @sa see @ref is_number() -- check if value is number + @sa see @ref is_number_integer() -- check if value is an integer number + @sa see @ref is_number_unsigned() -- check if value is an unsigned integer + number + + @since version 1.0.0 + */ + constexpr bool is_number_float() const noexcept + { + return m_type == value_t::number_float; + } + + /*! + @brief return whether value is an object + + This function returns true if and only if the JSON value is an object. + + @return `true` if type is object, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_object()` for all JSON + types.,is_object} + + @since version 1.0.0 + */ + constexpr bool is_object() const noexcept + { + return m_type == value_t::object; + } + + /*! + @brief return whether value is an array + + This function returns true if and only if the JSON value is an array. + + @return `true` if type is array, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_array()` for all JSON + types.,is_array} + + @since version 1.0.0 + */ + constexpr bool is_array() const noexcept + { + return m_type == value_t::array; + } + + /*! + @brief return whether value is a string + + This function returns true if and only if the JSON value is a string. + + @return `true` if type is string, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_string()` for all JSON + types.,is_string} + + @since version 1.0.0 + */ + constexpr bool is_string() const noexcept + { + return m_type == value_t::string; + } + + /*! + @brief return whether value is a binary array + + This function returns true if and only if the JSON value is a binary array. + + @return `true` if type is binary array, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_binary()` for all JSON + types.,is_binary} + + @since version 3.8.0 + */ + constexpr bool is_binary() const noexcept + { + return m_type == value_t::binary; + } + + /*! + @brief return whether value is discarded + + This function returns true if and only if the JSON value was discarded + during parsing with a callback function (see @ref parser_callback_t). + + @note This function will always be `false` for JSON values after parsing. + That is, discarded values can only occur during parsing, but will be + removed when inside a structured value or replaced by null in other cases. + + @return `true` if type is discarded, `false` otherwise. + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies `is_discarded()` for all JSON + types.,is_discarded} + + @since version 1.0.0 + */ + constexpr bool is_discarded() const noexcept + { + return m_type == value_t::discarded; + } + + /*! + @brief return the type of the JSON value (implicit) + + Implicitly return the type of the JSON value as a value from the @ref + value_t enumeration. + + @return the type of the JSON value + + @complexity Constant. + + @exceptionsafety No-throw guarantee: this member function never throws + exceptions. + + @liveexample{The following code exemplifies the @ref value_t operator for + all JSON types.,operator__value_t} + + @sa see @ref type() -- return the type of the JSON value (explicit) + @sa see @ref type_name() -- return the type as string + + @since version 1.0.0 + */ + constexpr operator value_t() const noexcept + { + return m_type; + } + + /// @} + + private: + ////////////////// + // value access // + ////////////////// + + /// get a boolean (explicit) + boolean_t get_impl(boolean_t* /*unused*/) const + { + if (JSON_HEDLEY_LIKELY(is_boolean())) + { + return m_value.boolean; + } + + JSON_THROW(type_error::create(302, "type must be boolean, but is " + std::string(type_name()), *this)); + } + + /// get a pointer to the value (object) + object_t* get_impl_ptr(object_t* /*unused*/) noexcept + { + return is_object() ? m_value.object : nullptr; + } + + /// get a pointer to the value (object) + constexpr const object_t* get_impl_ptr(const object_t* /*unused*/) const noexcept + { + return is_object() ? m_value.object : nullptr; + } + + /// get a pointer to the value (array) + array_t* get_impl_ptr(array_t* /*unused*/) noexcept + { + return is_array() ? m_value.array : nullptr; + } + + /// get a pointer to the value (array) + constexpr const array_t* get_impl_ptr(const array_t* /*unused*/) const noexcept + { + return is_array() ? m_value.array : nullptr; + } + + /// get a pointer to the value (string) + string_t* get_impl_ptr(string_t* /*unused*/) noexcept + { + return is_string() ? m_value.string : nullptr; + } + + /// get a pointer to the value (string) + constexpr const string_t* get_impl_ptr(const string_t* /*unused*/) const noexcept + { + return is_string() ? m_value.string : nullptr; + } + + /// get a pointer to the value (boolean) + boolean_t* get_impl_ptr(boolean_t* /*unused*/) noexcept + { + return is_boolean() ? &m_value.boolean : nullptr; + } + + /// get a pointer to the value (boolean) + constexpr const boolean_t* get_impl_ptr(const boolean_t* /*unused*/) const noexcept + { + return is_boolean() ? &m_value.boolean : nullptr; + } + + /// get a pointer to the value (integer number) + number_integer_t* get_impl_ptr(number_integer_t* /*unused*/) noexcept + { + return is_number_integer() ? &m_value.number_integer : nullptr; + } + + /// get a pointer to the value (integer number) + constexpr const number_integer_t* get_impl_ptr(const number_integer_t* /*unused*/) const noexcept + { + return is_number_integer() ? &m_value.number_integer : nullptr; + } + + /// get a pointer to the value (unsigned number) + number_unsigned_t* get_impl_ptr(number_unsigned_t* /*unused*/) noexcept + { + return is_number_unsigned() ? &m_value.number_unsigned : nullptr; + } + + /// get a pointer to the value (unsigned number) + constexpr const number_unsigned_t* get_impl_ptr(const number_unsigned_t* /*unused*/) const noexcept + { + return is_number_unsigned() ? &m_value.number_unsigned : nullptr; + } + + /// get a pointer to the value (floating-point number) + number_float_t* get_impl_ptr(number_float_t* /*unused*/) noexcept + { + return is_number_float() ? &m_value.number_float : nullptr; + } + + /// get a pointer to the value (floating-point number) + constexpr const number_float_t* get_impl_ptr(const number_float_t* /*unused*/) const noexcept + { + return is_number_float() ? &m_value.number_float : nullptr; + } + + /// get a pointer to the value (binary) + binary_t* get_impl_ptr(binary_t* /*unused*/) noexcept + { + return is_binary() ? m_value.binary : nullptr; + } + + /// get a pointer to the value (binary) + constexpr const binary_t* get_impl_ptr(const binary_t* /*unused*/) const noexcept + { + return is_binary() ? m_value.binary : nullptr; + } + + /*! + @brief helper function to implement get_ref() + + This function helps to implement get_ref() without code duplication for + const and non-const overloads + + @tparam ThisType will be deduced as `basic_json` or `const basic_json` + + @throw type_error.303 if ReferenceType does not match underlying value + type of the current JSON + */ + template + static ReferenceType get_ref_impl(ThisType& obj) + { + // delegate the call to get_ptr<>() + auto* ptr = obj.template get_ptr::type>(); + + if (JSON_HEDLEY_LIKELY(ptr != nullptr)) + { + return *ptr; + } + + JSON_THROW(type_error::create(303, "incompatible ReferenceType for get_ref, actual type is " + std::string(obj.type_name()), obj)); + } + + public: + /// @name value access + /// Direct access to the stored value of a JSON value. + /// @{ + + /*! + @brief get a pointer value (implicit) + + Implicit pointer access to the internally stored JSON value. No copies are + made. + + @warning Writing data to the pointee of the result yields an undefined + state. + + @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref + object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, + @ref number_unsigned_t, or @ref number_float_t. Enforced by a static + assertion. + + @return pointer to the internally stored JSON value if the requested + pointer type @a PointerType fits to the JSON value; `nullptr` otherwise + + @complexity Constant. + + @liveexample{The example below shows how pointers to internal values of a + JSON value can be requested. Note that no type conversions are made and a + `nullptr` is returned if the value and the requested pointer type does not + match.,get_ptr} + + @since version 1.0.0 + */ + template::value, int>::type = 0> + auto get_ptr() noexcept -> decltype(std::declval().get_impl_ptr(std::declval())) + { + // delegate the call to get_impl_ptr<>() + return get_impl_ptr(static_cast(nullptr)); + } + + /*! + @brief get a pointer value (implicit) + @copydoc get_ptr() + */ + template < typename PointerType, typename std::enable_if < + std::is_pointer::value&& + std::is_const::type>::value, int >::type = 0 > + constexpr auto get_ptr() const noexcept -> decltype(std::declval().get_impl_ptr(std::declval())) + { + // delegate the call to get_impl_ptr<>() const + return get_impl_ptr(static_cast(nullptr)); + } + + private: + /*! + @brief get a value (explicit) + + Explicit type conversion between the JSON value and a compatible value + which is [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible) + and [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible). + The value is converted by calling the @ref json_serializer + `from_json()` method. + + The function is equivalent to executing + @code {.cpp} + ValueType ret; + JSONSerializer::from_json(*this, ret); + return ret; + @endcode + + This overloads is chosen if: + - @a ValueType is not @ref basic_json, + - @ref json_serializer has a `from_json()` method of the form + `void from_json(const basic_json&, ValueType&)`, and + - @ref json_serializer does not have a `from_json()` method of + the form `ValueType from_json(const basic_json&)` + + @tparam ValueType the returned value type + + @return copy of the JSON value, converted to @a ValueType + + @throw what @ref json_serializer `from_json()` method throws + + @liveexample{The example below shows several conversions from JSON values + to other types. There a few things to note: (1) Floating-point numbers can + be converted to integers\, (2) A JSON array can be converted to a standard + `std::vector`\, (3) A JSON object can be converted to C++ + associative containers such as `std::unordered_map`.,get__ValueType_const} + + @since version 2.1.0 + */ + template < typename ValueType, + detail::enable_if_t < + detail::is_default_constructible::value&& + detail::has_from_json::value, + int > = 0 > + ValueType get_impl(detail::priority_tag<0> /*unused*/) const noexcept(noexcept( + JSONSerializer::from_json(std::declval(), std::declval()))) + { + auto ret = ValueType(); + JSONSerializer::from_json(*this, ret); + return ret; + } + + /*! + @brief get a value (explicit); special case + + Explicit type conversion between the JSON value and a compatible value + which is **not** [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible) + and **not** [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible). + The value is converted by calling the @ref json_serializer + `from_json()` method. + + The function is equivalent to executing + @code {.cpp} + return JSONSerializer::from_json(*this); + @endcode + + This overloads is chosen if: + - @a ValueType is not @ref basic_json and + - @ref json_serializer has a `from_json()` method of the form + `ValueType from_json(const basic_json&)` + + @note If @ref json_serializer has both overloads of + `from_json()`, this one is chosen. + + @tparam ValueType the returned value type + + @return copy of the JSON value, converted to @a ValueType + + @throw what @ref json_serializer `from_json()` method throws + + @since version 2.1.0 + */ + template < typename ValueType, + detail::enable_if_t < + detail::has_non_default_from_json::value, + int > = 0 > + ValueType get_impl(detail::priority_tag<1> /*unused*/) const noexcept(noexcept( + JSONSerializer::from_json(std::declval()))) + { + return JSONSerializer::from_json(*this); + } + + /*! + @brief get special-case overload + + This overloads converts the current @ref basic_json in a different + @ref basic_json type + + @tparam BasicJsonType == @ref basic_json + + @return a copy of *this, converted into @a BasicJsonType + + @complexity Depending on the implementation of the called `from_json()` + method. + + @since version 3.2.0 + */ + template < typename BasicJsonType, + detail::enable_if_t < + detail::is_basic_json::value, + int > = 0 > + BasicJsonType get_impl(detail::priority_tag<2> /*unused*/) const + { + return *this; + } + + /*! + @brief get special-case overload + + This overloads avoids a lot of template boilerplate, it can be seen as the + identity method + + @tparam BasicJsonType == @ref basic_json + + @return a copy of *this + + @complexity Constant. + + @since version 2.1.0 + */ + template::value, + int> = 0> + basic_json get_impl(detail::priority_tag<3> /*unused*/) const + { + return *this; + } + + /*! + @brief get a pointer value (explicit) + @copydoc get() + */ + template::value, + int> = 0> + constexpr auto get_impl(detail::priority_tag<4> /*unused*/) const noexcept + -> decltype(std::declval().template get_ptr()) + { + // delegate the call to get_ptr + return get_ptr(); + } + + public: + /*! + @brief get a (pointer) value (explicit) + + Performs explicit type conversion between the JSON value and a compatible value if required. + + - If the requested type is a pointer to the internally stored JSON value that pointer is returned. + No copies are made. + + - If the requested type is the current @ref basic_json, or a different @ref basic_json convertible + from the current @ref basic_json. + + - Otherwise the value is converted by calling the @ref json_serializer `from_json()` + method. + + @tparam ValueTypeCV the provided value type + @tparam ValueType the returned value type + + @return copy of the JSON value, converted to @tparam ValueType if necessary + + @throw what @ref json_serializer `from_json()` method throws if conversion is required + + @since version 2.1.0 + */ + template < typename ValueTypeCV, typename ValueType = detail::uncvref_t> +#if defined(JSON_HAS_CPP_14) + constexpr +#endif + auto get() const noexcept( + noexcept(std::declval().template get_impl(detail::priority_tag<4> {}))) + -> decltype(std::declval().template get_impl(detail::priority_tag<4> {})) + { + // we cannot static_assert on ValueTypeCV being non-const, because + // there is support for get(), which is why we + // still need the uncvref + static_assert(!std::is_reference::value, + "get() cannot be used with reference types, you might want to use get_ref()"); + return get_impl(detail::priority_tag<4> {}); + } + + /*! + @brief get a pointer value (explicit) + + Explicit pointer access to the internally stored JSON value. No copies are + made. + + @warning The pointer becomes invalid if the underlying JSON object + changes. + + @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref + object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, + @ref number_unsigned_t, or @ref number_float_t. + + @return pointer to the internally stored JSON value if the requested + pointer type @a PointerType fits to the JSON value; `nullptr` otherwise + + @complexity Constant. + + @liveexample{The example below shows how pointers to internal values of a + JSON value can be requested. Note that no type conversions are made and a + `nullptr` is returned if the value and the requested pointer type does not + match.,get__PointerType} + + @sa see @ref get_ptr() for explicit pointer-member access + + @since version 1.0.0 + */ + template::value, int>::type = 0> + auto get() noexcept -> decltype(std::declval().template get_ptr()) + { + // delegate the call to get_ptr + return get_ptr(); + } + + /*! + @brief get a value (explicit) + + Explicit type conversion between the JSON value and a compatible value. + The value is filled into the input parameter by calling the @ref json_serializer + `from_json()` method. + + The function is equivalent to executing + @code {.cpp} + ValueType v; + JSONSerializer::from_json(*this, v); + @endcode + + This overloads is chosen if: + - @a ValueType is not @ref basic_json, + - @ref json_serializer has a `from_json()` method of the form + `void from_json(const basic_json&, ValueType&)`, and + + @tparam ValueType the input parameter type. + + @return the input parameter, allowing chaining calls. + + @throw what @ref json_serializer `from_json()` method throws + + @liveexample{The example below shows several conversions from JSON values + to other types. There a few things to note: (1) Floating-point numbers can + be converted to integers\, (2) A JSON array can be converted to a standard + `std::vector`\, (3) A JSON object can be converted to C++ + associative containers such as `std::unordered_map`.,get_to} + + @since version 3.3.0 + */ + template < typename ValueType, + detail::enable_if_t < + !detail::is_basic_json::value&& + detail::has_from_json::value, + int > = 0 > + ValueType & get_to(ValueType& v) const noexcept(noexcept( + JSONSerializer::from_json(std::declval(), v))) + { + JSONSerializer::from_json(*this, v); + return v; + } + + // specialization to allow to call get_to with a basic_json value + // see https://github.com/nlohmann/json/issues/2175 + template::value, + int> = 0> + ValueType & get_to(ValueType& v) const + { + v = *this; + return v; + } + + template < + typename T, std::size_t N, + typename Array = T (&)[N], // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) + detail::enable_if_t < + detail::has_from_json::value, int > = 0 > + Array get_to(T (&v)[N]) const // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) + noexcept(noexcept(JSONSerializer::from_json( + std::declval(), v))) + { + JSONSerializer::from_json(*this, v); + return v; + } + + /*! + @brief get a reference value (implicit) + + Implicit reference access to the internally stored JSON value. No copies + are made. + + @warning Writing data to the referee of the result yields an undefined + state. + + @tparam ReferenceType reference type; must be a reference to @ref array_t, + @ref object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or + @ref number_float_t. Enforced by static assertion. + + @return reference to the internally stored JSON value if the requested + reference type @a ReferenceType fits to the JSON value; throws + type_error.303 otherwise + + @throw type_error.303 in case passed type @a ReferenceType is incompatible + with the stored JSON value; see example below + + @complexity Constant. + + @liveexample{The example shows several calls to `get_ref()`.,get_ref} + + @since version 1.1.0 + */ + template::value, int>::type = 0> + ReferenceType get_ref() + { + // delegate call to get_ref_impl + return get_ref_impl(*this); + } + + /*! + @brief get a reference value (implicit) + @copydoc get_ref() + */ + template < typename ReferenceType, typename std::enable_if < + std::is_reference::value&& + std::is_const::type>::value, int >::type = 0 > + ReferenceType get_ref() const + { + // delegate call to get_ref_impl + return get_ref_impl(*this); + } + + /*! + @brief get a value (implicit) + + Implicit type conversion between the JSON value and a compatible value. + The call is realized by calling @ref get() const. + + @tparam ValueType non-pointer type compatible to the JSON value, for + instance `int` for JSON integer numbers, `bool` for JSON booleans, or + `std::vector` types for JSON arrays. The character type of @ref string_t + as well as an initializer list of this type is excluded to avoid + ambiguities as these types implicitly convert to `std::string`. + + @return copy of the JSON value, converted to type @a ValueType + + @throw type_error.302 in case passed type @a ValueType is incompatible + to the JSON value type (e.g., the JSON value is of type boolean, but a + string is requested); see example below + + @complexity Linear in the size of the JSON value. + + @liveexample{The example below shows several conversions from JSON values + to other types. There a few things to note: (1) Floating-point numbers can + be converted to integers\, (2) A JSON array can be converted to a standard + `std::vector`\, (3) A JSON object can be converted to C++ + associative containers such as `std::unordered_map`.,operator__ValueType} + + @since version 1.0.0 + */ + template < typename ValueType, typename std::enable_if < + detail::conjunction < + detail::negation>, + detail::negation>>, + detail::negation>, + detail::negation>, + detail::negation>>, + +#if defined(JSON_HAS_CPP_17) && (defined(__GNUC__) || (defined(_MSC_VER) && _MSC_VER >= 1910 && _MSC_VER <= 1914)) + detail::negation>, +#endif + detail::is_detected_lazy + >::value, int >::type = 0 > + JSON_EXPLICIT operator ValueType() const + { + // delegate the call to get<>() const + return get(); + } + + /*! + @return reference to the binary value + + @throw type_error.302 if the value is not binary + + @sa see @ref is_binary() to check if the value is binary + + @since version 3.8.0 + */ + binary_t& get_binary() + { + if (!is_binary()) + { + JSON_THROW(type_error::create(302, "type must be binary, but is " + std::string(type_name()), *this)); + } + + return *get_ptr(); + } + + /// @copydoc get_binary() + const binary_t& get_binary() const + { + if (!is_binary()) + { + JSON_THROW(type_error::create(302, "type must be binary, but is " + std::string(type_name()), *this)); + } + + return *get_ptr(); + } + + /// @} + + + //////////////////// + // element access // + //////////////////// + + /// @name element access + /// Access to the JSON value. + /// @{ + + /*! + @brief access specified array element with bounds checking + + Returns a reference to the element at specified location @a idx, with + bounds checking. + + @param[in] idx index of the element to access + + @return reference to the element at index @a idx + + @throw type_error.304 if the JSON value is not an array; in this case, + calling `at` with an index makes no sense. See example below. + @throw out_of_range.401 if the index @a idx is out of range of the array; + that is, `idx >= size()`. See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + + @since version 1.0.0 + + @liveexample{The example below shows how array elements can be read and + written using `at()`. It also demonstrates the different exceptions that + can be thrown.,at__size_type} + */ + reference at(size_type idx) + { + // at only works for arrays + if (JSON_HEDLEY_LIKELY(is_array())) + { + JSON_TRY + { + return set_parent(m_value.array->at(idx)); + } + JSON_CATCH (std::out_of_range&) + { + // create better exception explanation + JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range", *this)); + } + } + else + { + JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()), *this)); + } + } + + /*! + @brief access specified array element with bounds checking + + Returns a const reference to the element at specified location @a idx, + with bounds checking. + + @param[in] idx index of the element to access + + @return const reference to the element at index @a idx + + @throw type_error.304 if the JSON value is not an array; in this case, + calling `at` with an index makes no sense. See example below. + @throw out_of_range.401 if the index @a idx is out of range of the array; + that is, `idx >= size()`. See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + + @since version 1.0.0 + + @liveexample{The example below shows how array elements can be read using + `at()`. It also demonstrates the different exceptions that can be thrown., + at__size_type_const} + */ + const_reference at(size_type idx) const + { + // at only works for arrays + if (JSON_HEDLEY_LIKELY(is_array())) + { + JSON_TRY + { + return m_value.array->at(idx); + } + JSON_CATCH (std::out_of_range&) + { + // create better exception explanation + JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range", *this)); + } + } + else + { + JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()), *this)); + } + } + + /*! + @brief access specified object element with bounds checking + + Returns a reference to the element at with specified key @a key, with + bounds checking. + + @param[in] key key of the element to access + + @return reference to the element at key @a key + + @throw type_error.304 if the JSON value is not an object; in this case, + calling `at` with a key makes no sense. See example below. + @throw out_of_range.403 if the key @a key is is not stored in the object; + that is, `find(key) == end()`. See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Logarithmic in the size of the container. + + @sa see @ref operator[](const typename object_t::key_type&) for unchecked + access by reference + @sa see @ref value() for access by value with a default value + + @since version 1.0.0 + + @liveexample{The example below shows how object elements can be read and + written using `at()`. It also demonstrates the different exceptions that + can be thrown.,at__object_t_key_type} + */ + reference at(const typename object_t::key_type& key) + { + // at only works for objects + if (JSON_HEDLEY_LIKELY(is_object())) + { + JSON_TRY + { + return set_parent(m_value.object->at(key)); + } + JSON_CATCH (std::out_of_range&) + { + // create better exception explanation + JSON_THROW(out_of_range::create(403, "key '" + key + "' not found", *this)); + } + } + else + { + JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()), *this)); + } + } + + /*! + @brief access specified object element with bounds checking + + Returns a const reference to the element at with specified key @a key, + with bounds checking. + + @param[in] key key of the element to access + + @return const reference to the element at key @a key + + @throw type_error.304 if the JSON value is not an object; in this case, + calling `at` with a key makes no sense. See example below. + @throw out_of_range.403 if the key @a key is is not stored in the object; + that is, `find(key) == end()`. See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Logarithmic in the size of the container. + + @sa see @ref operator[](const typename object_t::key_type&) for unchecked + access by reference + @sa see @ref value() for access by value with a default value + + @since version 1.0.0 + + @liveexample{The example below shows how object elements can be read using + `at()`. It also demonstrates the different exceptions that can be thrown., + at__object_t_key_type_const} + */ + const_reference at(const typename object_t::key_type& key) const + { + // at only works for objects + if (JSON_HEDLEY_LIKELY(is_object())) + { + JSON_TRY + { + return m_value.object->at(key); + } + JSON_CATCH (std::out_of_range&) + { + // create better exception explanation + JSON_THROW(out_of_range::create(403, "key '" + key + "' not found", *this)); + } + } + else + { + JSON_THROW(type_error::create(304, "cannot use at() with " + std::string(type_name()), *this)); + } + } + + /*! + @brief access specified array element + + Returns a reference to the element at specified location @a idx. + + @note If @a idx is beyond the range of the array (i.e., `idx >= size()`), + then the array is silently filled up with `null` values to make `idx` a + valid reference to the last stored element. + + @param[in] idx index of the element to access + + @return reference to the element at index @a idx + + @throw type_error.305 if the JSON value is not an array or null; in that + cases, using the [] operator with an index makes no sense. + + @complexity Constant if @a idx is in the range of the array. Otherwise + linear in `idx - size()`. + + @liveexample{The example below shows how array elements can be read and + written using `[]` operator. Note the addition of `null` + values.,operatorarray__size_type} + + @since version 1.0.0 + */ + reference operator[](size_type idx) + { + // implicitly convert null value to an empty array + if (is_null()) + { + m_type = value_t::array; + m_value.array = create(); + assert_invariant(); + } + + // operator[] only works for arrays + if (JSON_HEDLEY_LIKELY(is_array())) + { + // fill up array with null values if given idx is outside range + if (idx >= m_value.array->size()) + { +#if JSON_DIAGNOSTICS + // remember array size & capacity before resizing + const auto old_size = m_value.array->size(); + const auto old_capacity = m_value.array->capacity(); +#endif + m_value.array->resize(idx + 1); + +#if JSON_DIAGNOSTICS + if (JSON_HEDLEY_UNLIKELY(m_value.array->capacity() != old_capacity)) + { + // capacity has changed: update all parents + set_parents(); + } + else + { + // set parent for values added above + set_parents(begin() + static_cast(old_size), static_cast(idx + 1 - old_size)); + } +#endif + assert_invariant(); + } + + return m_value.array->operator[](idx); + } + + JSON_THROW(type_error::create(305, "cannot use operator[] with a numeric argument with " + std::string(type_name()), *this)); + } + + /*! + @brief access specified array element + + Returns a const reference to the element at specified location @a idx. + + @param[in] idx index of the element to access + + @return const reference to the element at index @a idx + + @throw type_error.305 if the JSON value is not an array; in that case, + using the [] operator with an index makes no sense. + + @complexity Constant. + + @liveexample{The example below shows how array elements can be read using + the `[]` operator.,operatorarray__size_type_const} + + @since version 1.0.0 + */ + const_reference operator[](size_type idx) const + { + // const operator[] only works for arrays + if (JSON_HEDLEY_LIKELY(is_array())) + { + return m_value.array->operator[](idx); + } + + JSON_THROW(type_error::create(305, "cannot use operator[] with a numeric argument with " + std::string(type_name()), *this)); + } + + /*! + @brief access specified object element + + Returns a reference to the element at with specified key @a key. + + @note If @a key is not found in the object, then it is silently added to + the object and filled with a `null` value to make `key` a valid reference. + In case the value was `null` before, it is converted to an object. + + @param[in] key key of the element to access + + @return reference to the element at key @a key + + @throw type_error.305 if the JSON value is not an object or null; in that + cases, using the [] operator with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read and + written using the `[]` operator.,operatorarray__key_type} + + @sa see @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa see @ref value() for access by value with a default value + + @since version 1.0.0 + */ + reference operator[](const typename object_t::key_type& key) + { + // implicitly convert null value to an empty object + if (is_null()) + { + m_type = value_t::object; + m_value.object = create(); + assert_invariant(); + } + + // operator[] only works for objects + if (JSON_HEDLEY_LIKELY(is_object())) + { + return set_parent(m_value.object->operator[](key)); + } + + JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()), *this)); + } + + /*! + @brief read-only access specified object element + + Returns a const reference to the element at with specified key @a key. No + bounds checking is performed. + + @warning If the element with key @a key does not exist, the behavior is + undefined. + + @param[in] key key of the element to access + + @return const reference to the element at key @a key + + @pre The element with key @a key must exist. **This precondition is + enforced with an assertion.** + + @throw type_error.305 if the JSON value is not an object; in that case, + using the [] operator with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read using + the `[]` operator.,operatorarray__key_type_const} + + @sa see @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa see @ref value() for access by value with a default value + + @since version 1.0.0 + */ + const_reference operator[](const typename object_t::key_type& key) const + { + // const operator[] only works for objects + if (JSON_HEDLEY_LIKELY(is_object())) + { + JSON_ASSERT(m_value.object->find(key) != m_value.object->end()); + return m_value.object->find(key)->second; + } + + JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()), *this)); + } + + /*! + @brief access specified object element + + Returns a reference to the element at with specified key @a key. + + @note If @a key is not found in the object, then it is silently added to + the object and filled with a `null` value to make `key` a valid reference. + In case the value was `null` before, it is converted to an object. + + @param[in] key key of the element to access + + @return reference to the element at key @a key + + @throw type_error.305 if the JSON value is not an object or null; in that + cases, using the [] operator with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read and + written using the `[]` operator.,operatorarray__key_type} + + @sa see @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa see @ref value() for access by value with a default value + + @since version 1.1.0 + */ + template + JSON_HEDLEY_NON_NULL(2) + reference operator[](T* key) + { + // implicitly convert null to object + if (is_null()) + { + m_type = value_t::object; + m_value = value_t::object; + assert_invariant(); + } + + // at only works for objects + if (JSON_HEDLEY_LIKELY(is_object())) + { + return set_parent(m_value.object->operator[](key)); + } + + JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()), *this)); + } + + /*! + @brief read-only access specified object element + + Returns a const reference to the element at with specified key @a key. No + bounds checking is performed. + + @warning If the element with key @a key does not exist, the behavior is + undefined. + + @param[in] key key of the element to access + + @return const reference to the element at key @a key + + @pre The element with key @a key must exist. **This precondition is + enforced with an assertion.** + + @throw type_error.305 if the JSON value is not an object; in that case, + using the [] operator with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be read using + the `[]` operator.,operatorarray__key_type_const} + + @sa see @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa see @ref value() for access by value with a default value + + @since version 1.1.0 + */ + template + JSON_HEDLEY_NON_NULL(2) + const_reference operator[](T* key) const + { + // at only works for objects + if (JSON_HEDLEY_LIKELY(is_object())) + { + JSON_ASSERT(m_value.object->find(key) != m_value.object->end()); + return m_value.object->find(key)->second; + } + + JSON_THROW(type_error::create(305, "cannot use operator[] with a string argument with " + std::string(type_name()), *this)); + } + + /*! + @brief access specified object element with default value + + Returns either a copy of an object's element at the specified key @a key + or a given default value if no element with key @a key exists. + + The function is basically equivalent to executing + @code {.cpp} + try { + return at(key); + } catch(out_of_range) { + return default_value; + } + @endcode + + @note Unlike @ref at(const typename object_t::key_type&), this function + does not throw if the given key @a key was not found. + + @note Unlike @ref operator[](const typename object_t::key_type& key), this + function does not implicitly add an element to the position defined by @a + key. This function is furthermore also applicable to const objects. + + @param[in] key key of the element to access + @param[in] default_value the value to return if @a key is not found + + @tparam ValueType type compatible to JSON values, for instance `int` for + JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for + JSON arrays. Note the type of the expected value at @a key and the default + value @a default_value must be compatible. + + @return copy of the element at key @a key or @a default_value if @a key + is not found + + @throw type_error.302 if @a default_value does not match the type of the + value at @a key + @throw type_error.306 if the JSON value is not an object; in that case, + using `value()` with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be queried + with a default value.,basic_json__value} + + @sa see @ref at(const typename object_t::key_type&) for access by reference + with range checking + @sa see @ref operator[](const typename object_t::key_type&) for unchecked + access by reference + + @since version 1.0.0 + */ + // using std::is_convertible in a std::enable_if will fail when using explicit conversions + template < class ValueType, typename std::enable_if < + detail::is_getable::value + && !std::is_same::value, int >::type = 0 > + ValueType value(const typename object_t::key_type& key, const ValueType& default_value) const + { + // at only works for objects + if (JSON_HEDLEY_LIKELY(is_object())) + { + // if key is found, return value and given default value otherwise + const auto it = find(key); + if (it != end()) + { + return it->template get(); + } + + return default_value; + } + + JSON_THROW(type_error::create(306, "cannot use value() with " + std::string(type_name()), *this)); + } + + /*! + @brief overload for a default value of type const char* + @copydoc basic_json::value(const typename object_t::key_type&, const ValueType&) const + */ + string_t value(const typename object_t::key_type& key, const char* default_value) const + { + return value(key, string_t(default_value)); + } + + /*! + @brief access specified object element via JSON Pointer with default value + + Returns either a copy of an object's element at the specified key @a key + or a given default value if no element with key @a key exists. + + The function is basically equivalent to executing + @code {.cpp} + try { + return at(ptr); + } catch(out_of_range) { + return default_value; + } + @endcode + + @note Unlike @ref at(const json_pointer&), this function does not throw + if the given key @a key was not found. + + @param[in] ptr a JSON pointer to the element to access + @param[in] default_value the value to return if @a ptr found no value + + @tparam ValueType type compatible to JSON values, for instance `int` for + JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for + JSON arrays. Note the type of the expected value at @a key and the default + value @a default_value must be compatible. + + @return copy of the element at key @a key or @a default_value if @a key + is not found + + @throw type_error.302 if @a default_value does not match the type of the + value at @a ptr + @throw type_error.306 if the JSON value is not an object; in that case, + using `value()` with a key makes no sense. + + @complexity Logarithmic in the size of the container. + + @liveexample{The example below shows how object elements can be queried + with a default value.,basic_json__value_ptr} + + @sa see @ref operator[](const json_pointer&) for unchecked access by reference + + @since version 2.0.2 + */ + template::value, int>::type = 0> + ValueType value(const json_pointer& ptr, const ValueType& default_value) const + { + // at only works for objects + if (JSON_HEDLEY_LIKELY(is_object())) + { + // if pointer resolves a value, return it or use default value + JSON_TRY + { + return ptr.get_checked(this).template get(); + } + JSON_INTERNAL_CATCH (out_of_range&) + { + return default_value; + } + } + + JSON_THROW(type_error::create(306, "cannot use value() with " + std::string(type_name()), *this)); + } + + /*! + @brief overload for a default value of type const char* + @copydoc basic_json::value(const json_pointer&, ValueType) const + */ + JSON_HEDLEY_NON_NULL(3) + string_t value(const json_pointer& ptr, const char* default_value) const + { + return value(ptr, string_t(default_value)); + } + + /*! + @brief access the first element + + Returns a reference to the first element in the container. For a JSON + container `c`, the expression `c.front()` is equivalent to `*c.begin()`. + + @return In case of a structured type (array or object), a reference to the + first element is returned. In case of number, string, boolean, or binary + values, a reference to the value is returned. + + @complexity Constant. + + @pre The JSON value must not be `null` (would throw `std::out_of_range`) + or an empty array or object (undefined behavior, **guarded by + assertions**). + @post The JSON value remains unchanged. + + @throw invalid_iterator.214 when called on `null` value + + @liveexample{The following code shows an example for `front()`.,front} + + @sa see @ref back() -- access the last element + + @since version 1.0.0 + */ + reference front() + { + return *begin(); + } + + /*! + @copydoc basic_json::front() + */ + const_reference front() const + { + return *cbegin(); + } + + /*! + @brief access the last element + + Returns a reference to the last element in the container. For a JSON + container `c`, the expression `c.back()` is equivalent to + @code {.cpp} + auto tmp = c.end(); + --tmp; + return *tmp; + @endcode + + @return In case of a structured type (array or object), a reference to the + last element is returned. In case of number, string, boolean, or binary + values, a reference to the value is returned. + + @complexity Constant. + + @pre The JSON value must not be `null` (would throw `std::out_of_range`) + or an empty array or object (undefined behavior, **guarded by + assertions**). + @post The JSON value remains unchanged. + + @throw invalid_iterator.214 when called on a `null` value. See example + below. + + @liveexample{The following code shows an example for `back()`.,back} + + @sa see @ref front() -- access the first element + + @since version 1.0.0 + */ + reference back() + { + auto tmp = end(); + --tmp; + return *tmp; + } + + /*! + @copydoc basic_json::back() + */ + const_reference back() const + { + auto tmp = cend(); + --tmp; + return *tmp; + } + + /*! + @brief remove element given an iterator + + Removes the element specified by iterator @a pos. The iterator @a pos must + be valid and dereferenceable. Thus the `end()` iterator (which is valid, + but is not dereferenceable) cannot be used as a value for @a pos. + + If called on a primitive type other than `null`, the resulting JSON value + will be `null`. + + @param[in] pos iterator to the element to remove + @return Iterator following the last removed element. If the iterator @a + pos refers to the last element, the `end()` iterator is returned. + + @tparam IteratorType an @ref iterator or @ref const_iterator + + @post Invalidates iterators and references at or after the point of the + erase, including the `end()` iterator. + + @throw type_error.307 if called on a `null` value; example: `"cannot use + erase() with null"` + @throw invalid_iterator.202 if called on an iterator which does not belong + to the current JSON value; example: `"iterator does not fit current + value"` + @throw invalid_iterator.205 if called on a primitive type with invalid + iterator (i.e., any iterator which is not `begin()`); example: `"iterator + out of range"` + + @complexity The complexity depends on the type: + - objects: amortized constant + - arrays: linear in distance between @a pos and the end of the container + - strings and binary: linear in the length of the member + - other types: constant + + @liveexample{The example shows the result of `erase()` for different JSON + types.,erase__IteratorType} + + @sa see @ref erase(IteratorType, IteratorType) -- removes the elements in + the given range + @sa see @ref erase(const typename object_t::key_type&) -- removes the element + from an object at the given key + @sa see @ref erase(const size_type) -- removes the element from an array at + the given index + + @since version 1.0.0 + */ + template < class IteratorType, typename std::enable_if < + std::is_same::value || + std::is_same::value, int >::type + = 0 > + IteratorType erase(IteratorType pos) + { + // make sure iterator fits the current value + if (JSON_HEDLEY_UNLIKELY(this != pos.m_object)) + { + JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", *this)); + } + + IteratorType result = end(); + + switch (m_type) + { + case value_t::boolean: + case value_t::number_float: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::string: + case value_t::binary: + { + if (JSON_HEDLEY_UNLIKELY(!pos.m_it.primitive_iterator.is_begin())) + { + JSON_THROW(invalid_iterator::create(205, "iterator out of range", *this)); + } + + if (is_string()) + { + AllocatorType alloc; + std::allocator_traits::destroy(alloc, m_value.string); + std::allocator_traits::deallocate(alloc, m_value.string, 1); + m_value.string = nullptr; + } + else if (is_binary()) + { + AllocatorType alloc; + std::allocator_traits::destroy(alloc, m_value.binary); + std::allocator_traits::deallocate(alloc, m_value.binary, 1); + m_value.binary = nullptr; + } + + m_type = value_t::null; + assert_invariant(); + break; + } + + case value_t::object: + { + result.m_it.object_iterator = m_value.object->erase(pos.m_it.object_iterator); + break; + } + + case value_t::array: + { + result.m_it.array_iterator = m_value.array->erase(pos.m_it.array_iterator); + break; + } + + case value_t::null: + case value_t::discarded: + default: + JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()), *this)); + } + + return result; + } + + /*! + @brief remove elements given an iterator range + + Removes the element specified by the range `[first; last)`. The iterator + @a first does not need to be dereferenceable if `first == last`: erasing + an empty range is a no-op. + + If called on a primitive type other than `null`, the resulting JSON value + will be `null`. + + @param[in] first iterator to the beginning of the range to remove + @param[in] last iterator past the end of the range to remove + @return Iterator following the last removed element. If the iterator @a + second refers to the last element, the `end()` iterator is returned. + + @tparam IteratorType an @ref iterator or @ref const_iterator + + @post Invalidates iterators and references at or after the point of the + erase, including the `end()` iterator. + + @throw type_error.307 if called on a `null` value; example: `"cannot use + erase() with null"` + @throw invalid_iterator.203 if called on iterators which does not belong + to the current JSON value; example: `"iterators do not fit current value"` + @throw invalid_iterator.204 if called on a primitive type with invalid + iterators (i.e., if `first != begin()` and `last != end()`); example: + `"iterators out of range"` + + @complexity The complexity depends on the type: + - objects: `log(size()) + std::distance(first, last)` + - arrays: linear in the distance between @a first and @a last, plus linear + in the distance between @a last and end of the container + - strings and binary: linear in the length of the member + - other types: constant + + @liveexample{The example shows the result of `erase()` for different JSON + types.,erase__IteratorType_IteratorType} + + @sa see @ref erase(IteratorType) -- removes the element at a given position + @sa see @ref erase(const typename object_t::key_type&) -- removes the element + from an object at the given key + @sa see @ref erase(const size_type) -- removes the element from an array at + the given index + + @since version 1.0.0 + */ + template < class IteratorType, typename std::enable_if < + std::is_same::value || + std::is_same::value, int >::type + = 0 > + IteratorType erase(IteratorType first, IteratorType last) + { + // make sure iterator fits the current value + if (JSON_HEDLEY_UNLIKELY(this != first.m_object || this != last.m_object)) + { + JSON_THROW(invalid_iterator::create(203, "iterators do not fit current value", *this)); + } + + IteratorType result = end(); + + switch (m_type) + { + case value_t::boolean: + case value_t::number_float: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::string: + case value_t::binary: + { + if (JSON_HEDLEY_LIKELY(!first.m_it.primitive_iterator.is_begin() + || !last.m_it.primitive_iterator.is_end())) + { + JSON_THROW(invalid_iterator::create(204, "iterators out of range", *this)); + } + + if (is_string()) + { + AllocatorType alloc; + std::allocator_traits::destroy(alloc, m_value.string); + std::allocator_traits::deallocate(alloc, m_value.string, 1); + m_value.string = nullptr; + } + else if (is_binary()) + { + AllocatorType alloc; + std::allocator_traits::destroy(alloc, m_value.binary); + std::allocator_traits::deallocate(alloc, m_value.binary, 1); + m_value.binary = nullptr; + } + + m_type = value_t::null; + assert_invariant(); + break; + } + + case value_t::object: + { + result.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator, + last.m_it.object_iterator); + break; + } + + case value_t::array: + { + result.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator, + last.m_it.array_iterator); + break; + } + + case value_t::null: + case value_t::discarded: + default: + JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()), *this)); + } + + return result; + } + + /*! + @brief remove element from a JSON object given a key + + Removes elements from a JSON object with the key value @a key. + + @param[in] key value of the elements to remove + + @return Number of elements removed. If @a ObjectType is the default + `std::map` type, the return value will always be `0` (@a key was not + found) or `1` (@a key was found). + + @post References and iterators to the erased elements are invalidated. + Other references and iterators are not affected. + + @throw type_error.307 when called on a type other than JSON object; + example: `"cannot use erase() with null"` + + @complexity `log(size()) + count(key)` + + @liveexample{The example shows the effect of `erase()`.,erase__key_type} + + @sa see @ref erase(IteratorType) -- removes the element at a given position + @sa see @ref erase(IteratorType, IteratorType) -- removes the elements in + the given range + @sa see @ref erase(const size_type) -- removes the element from an array at + the given index + + @since version 1.0.0 + */ + size_type erase(const typename object_t::key_type& key) + { + // this erase only works for objects + if (JSON_HEDLEY_LIKELY(is_object())) + { + return m_value.object->erase(key); + } + + JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()), *this)); + } + + /*! + @brief remove element from a JSON array given an index + + Removes element from a JSON array at the index @a idx. + + @param[in] idx index of the element to remove + + @throw type_error.307 when called on a type other than JSON object; + example: `"cannot use erase() with null"` + @throw out_of_range.401 when `idx >= size()`; example: `"array index 17 + is out of range"` + + @complexity Linear in distance between @a idx and the end of the container. + + @liveexample{The example shows the effect of `erase()`.,erase__size_type} + + @sa see @ref erase(IteratorType) -- removes the element at a given position + @sa see @ref erase(IteratorType, IteratorType) -- removes the elements in + the given range + @sa see @ref erase(const typename object_t::key_type&) -- removes the element + from an object at the given key + + @since version 1.0.0 + */ + void erase(const size_type idx) + { + // this erase only works for arrays + if (JSON_HEDLEY_LIKELY(is_array())) + { + if (JSON_HEDLEY_UNLIKELY(idx >= size())) + { + JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range", *this)); + } + + m_value.array->erase(m_value.array->begin() + static_cast(idx)); + } + else + { + JSON_THROW(type_error::create(307, "cannot use erase() with " + std::string(type_name()), *this)); + } + } + + /// @} + + + //////////// + // lookup // + //////////// + + /// @name lookup + /// @{ + + /*! + @brief find an element in a JSON object + + Finds an element in a JSON object with key equivalent to @a key. If the + element is not found or the JSON value is not an object, end() is + returned. + + @note This method always returns @ref end() when executed on a JSON type + that is not an object. + + @param[in] key key value of the element to search for. + + @return Iterator to an element with key equivalent to @a key. If no such + element is found or the JSON value is not an object, past-the-end (see + @ref end()) iterator is returned. + + @complexity Logarithmic in the size of the JSON object. + + @liveexample{The example shows how `find()` is used.,find__key_type} + + @sa see @ref contains(KeyT&&) const -- checks whether a key exists + + @since version 1.0.0 + */ + template + iterator find(KeyT&& key) + { + auto result = end(); + + if (is_object()) + { + result.m_it.object_iterator = m_value.object->find(std::forward(key)); + } + + return result; + } + + /*! + @brief find an element in a JSON object + @copydoc find(KeyT&&) + */ + template + const_iterator find(KeyT&& key) const + { + auto result = cend(); + + if (is_object()) + { + result.m_it.object_iterator = m_value.object->find(std::forward(key)); + } + + return result; + } + + /*! + @brief returns the number of occurrences of a key in a JSON object + + Returns the number of elements with key @a key. If ObjectType is the + default `std::map` type, the return value will always be `0` (@a key was + not found) or `1` (@a key was found). + + @note This method always returns `0` when executed on a JSON type that is + not an object. + + @param[in] key key value of the element to count + + @return Number of elements with key @a key. If the JSON value is not an + object, the return value will be `0`. + + @complexity Logarithmic in the size of the JSON object. + + @liveexample{The example shows how `count()` is used.,count} + + @since version 1.0.0 + */ + template + size_type count(KeyT&& key) const + { + // return 0 for all nonobject types + return is_object() ? m_value.object->count(std::forward(key)) : 0; + } + + /*! + @brief check the existence of an element in a JSON object + + Check whether an element exists in a JSON object with key equivalent to + @a key. If the element is not found or the JSON value is not an object, + false is returned. + + @note This method always returns false when executed on a JSON type + that is not an object. + + @param[in] key key value to check its existence. + + @return true if an element with specified @a key exists. If no such + element with such key is found or the JSON value is not an object, + false is returned. + + @complexity Logarithmic in the size of the JSON object. + + @liveexample{The following code shows an example for `contains()`.,contains} + + @sa see @ref find(KeyT&&) -- returns an iterator to an object element + @sa see @ref contains(const json_pointer&) const -- checks the existence for a JSON pointer + + @since version 3.6.0 + */ + template < typename KeyT, typename std::enable_if < + !std::is_same::type, json_pointer>::value, int >::type = 0 > + bool contains(KeyT && key) const + { + return is_object() && m_value.object->find(std::forward(key)) != m_value.object->end(); + } + + /*! + @brief check the existence of an element in a JSON object given a JSON pointer + + Check whether the given JSON pointer @a ptr can be resolved in the current + JSON value. + + @note This method can be executed on any JSON value type. + + @param[in] ptr JSON pointer to check its existence. + + @return true if the JSON pointer can be resolved to a stored value, false + otherwise. + + @post If `j.contains(ptr)` returns true, it is safe to call `j[ptr]`. + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + + @complexity Logarithmic in the size of the JSON object. + + @liveexample{The following code shows an example for `contains()`.,contains_json_pointer} + + @sa see @ref contains(KeyT &&) const -- checks the existence of a key + + @since version 3.7.0 + */ + bool contains(const json_pointer& ptr) const + { + return ptr.contains(this); + } + + /// @} + + + /////////////// + // iterators // + /////////////// + + /// @name iterators + /// @{ + + /*! + @brief returns an iterator to the first element + + Returns an iterator to the first element. + + @image html range-begin-end.svg "Illustration from cppreference.com" + + @return iterator to the first element + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](https://en.cppreference.com/w/cpp/named_req/Container) + requirements: + - The complexity is constant. + + @liveexample{The following code shows an example for `begin()`.,begin} + + @sa see @ref cbegin() -- returns a const iterator to the beginning + @sa see @ref end() -- returns an iterator to the end + @sa see @ref cend() -- returns a const iterator to the end + + @since version 1.0.0 + */ + iterator begin() noexcept + { + iterator result(this); + result.set_begin(); + return result; + } + + /*! + @copydoc basic_json::cbegin() + */ + const_iterator begin() const noexcept + { + return cbegin(); + } + + /*! + @brief returns a const iterator to the first element + + Returns a const iterator to the first element. + + @image html range-begin-end.svg "Illustration from cppreference.com" + + @return const iterator to the first element + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](https://en.cppreference.com/w/cpp/named_req/Container) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).begin()`. + + @liveexample{The following code shows an example for `cbegin()`.,cbegin} + + @sa see @ref begin() -- returns an iterator to the beginning + @sa see @ref end() -- returns an iterator to the end + @sa see @ref cend() -- returns a const iterator to the end + + @since version 1.0.0 + */ + const_iterator cbegin() const noexcept + { + const_iterator result(this); + result.set_begin(); + return result; + } + + /*! + @brief returns an iterator to one past the last element + + Returns an iterator to one past the last element. + + @image html range-begin-end.svg "Illustration from cppreference.com" + + @return iterator one past the last element + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](https://en.cppreference.com/w/cpp/named_req/Container) + requirements: + - The complexity is constant. + + @liveexample{The following code shows an example for `end()`.,end} + + @sa see @ref cend() -- returns a const iterator to the end + @sa see @ref begin() -- returns an iterator to the beginning + @sa see @ref cbegin() -- returns a const iterator to the beginning + + @since version 1.0.0 + */ + iterator end() noexcept + { + iterator result(this); + result.set_end(); + return result; + } + + /*! + @copydoc basic_json::cend() + */ + const_iterator end() const noexcept + { + return cend(); + } + + /*! + @brief returns a const iterator to one past the last element + + Returns a const iterator to one past the last element. + + @image html range-begin-end.svg "Illustration from cppreference.com" + + @return const iterator one past the last element + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [Container](https://en.cppreference.com/w/cpp/named_req/Container) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).end()`. + + @liveexample{The following code shows an example for `cend()`.,cend} + + @sa see @ref end() -- returns an iterator to the end + @sa see @ref begin() -- returns an iterator to the beginning + @sa see @ref cbegin() -- returns a const iterator to the beginning + + @since version 1.0.0 + */ + const_iterator cend() const noexcept + { + const_iterator result(this); + result.set_end(); + return result; + } + + /*! + @brief returns an iterator to the reverse-beginning + + Returns an iterator to the reverse-beginning; that is, the last element. + + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `reverse_iterator(end())`. + + @liveexample{The following code shows an example for `rbegin()`.,rbegin} + + @sa see @ref crbegin() -- returns a const reverse iterator to the beginning + @sa see @ref rend() -- returns a reverse iterator to the end + @sa see @ref crend() -- returns a const reverse iterator to the end + + @since version 1.0.0 + */ + reverse_iterator rbegin() noexcept + { + return reverse_iterator(end()); + } + + /*! + @copydoc basic_json::crbegin() + */ + const_reverse_iterator rbegin() const noexcept + { + return crbegin(); + } + + /*! + @brief returns an iterator to the reverse-end + + Returns an iterator to the reverse-end; that is, one before the first + element. + + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `reverse_iterator(begin())`. + + @liveexample{The following code shows an example for `rend()`.,rend} + + @sa see @ref crend() -- returns a const reverse iterator to the end + @sa see @ref rbegin() -- returns a reverse iterator to the beginning + @sa see @ref crbegin() -- returns a const reverse iterator to the beginning + + @since version 1.0.0 + */ + reverse_iterator rend() noexcept + { + return reverse_iterator(begin()); + } + + /*! + @copydoc basic_json::crend() + */ + const_reverse_iterator rend() const noexcept + { + return crend(); + } + + /*! + @brief returns a const reverse iterator to the last element + + Returns a const iterator to the reverse-beginning; that is, the last + element. + + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).rbegin()`. + + @liveexample{The following code shows an example for `crbegin()`.,crbegin} + + @sa see @ref rbegin() -- returns a reverse iterator to the beginning + @sa see @ref rend() -- returns a reverse iterator to the end + @sa see @ref crend() -- returns a const reverse iterator to the end + + @since version 1.0.0 + */ + const_reverse_iterator crbegin() const noexcept + { + return const_reverse_iterator(cend()); + } + + /*! + @brief returns a const reverse iterator to one before the first + + Returns a const reverse iterator to the reverse-end; that is, one before + the first element. + + @image html range-rbegin-rend.svg "Illustration from cppreference.com" + + @complexity Constant. + + @requirement This function helps `basic_json` satisfying the + [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer) + requirements: + - The complexity is constant. + - Has the semantics of `const_cast(*this).rend()`. + + @liveexample{The following code shows an example for `crend()`.,crend} + + @sa see @ref rend() -- returns a reverse iterator to the end + @sa see @ref rbegin() -- returns a reverse iterator to the beginning + @sa see @ref crbegin() -- returns a const reverse iterator to the beginning + + @since version 1.0.0 + */ + const_reverse_iterator crend() const noexcept + { + return const_reverse_iterator(cbegin()); + } + + public: + /*! + @brief wrapper to access iterator member functions in range-based for + + This function allows to access @ref iterator::key() and @ref + iterator::value() during range-based for loops. In these loops, a + reference to the JSON values is returned, so there is no access to the + underlying iterator. + + For loop without iterator_wrapper: + + @code{cpp} + for (auto it = j_object.begin(); it != j_object.end(); ++it) + { + std::cout << "key: " << it.key() << ", value:" << it.value() << '\n'; + } + @endcode + + Range-based for loop without iterator proxy: + + @code{cpp} + for (auto it : j_object) + { + // "it" is of type json::reference and has no key() member + std::cout << "value: " << it << '\n'; + } + @endcode + + Range-based for loop with iterator proxy: + + @code{cpp} + for (auto it : json::iterator_wrapper(j_object)) + { + std::cout << "key: " << it.key() << ", value:" << it.value() << '\n'; + } + @endcode + + @note When iterating over an array, `key()` will return the index of the + element as string (see example). + + @param[in] ref reference to a JSON value + @return iteration proxy object wrapping @a ref with an interface to use in + range-based for loops + + @liveexample{The following code shows how the wrapper is used,iterator_wrapper} + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + + @note The name of this function is not yet final and may change in the + future. + + @deprecated This stream operator is deprecated and will be removed in + future 4.0.0 of the library. Please use @ref items() instead; + that is, replace `json::iterator_wrapper(j)` with `j.items()`. + */ + JSON_HEDLEY_DEPRECATED_FOR(3.1.0, items()) + static iteration_proxy iterator_wrapper(reference ref) noexcept + { + return ref.items(); + } + + /*! + @copydoc iterator_wrapper(reference) + */ + JSON_HEDLEY_DEPRECATED_FOR(3.1.0, items()) + static iteration_proxy iterator_wrapper(const_reference ref) noexcept + { + return ref.items(); + } + + /*! + @brief helper to access iterator member functions in range-based for + + This function allows to access @ref iterator::key() and @ref + iterator::value() during range-based for loops. In these loops, a + reference to the JSON values is returned, so there is no access to the + underlying iterator. + + For loop without `items()` function: + + @code{cpp} + for (auto it = j_object.begin(); it != j_object.end(); ++it) + { + std::cout << "key: " << it.key() << ", value:" << it.value() << '\n'; + } + @endcode + + Range-based for loop without `items()` function: + + @code{cpp} + for (auto it : j_object) + { + // "it" is of type json::reference and has no key() member + std::cout << "value: " << it << '\n'; + } + @endcode + + Range-based for loop with `items()` function: + + @code{cpp} + for (auto& el : j_object.items()) + { + std::cout << "key: " << el.key() << ", value:" << el.value() << '\n'; + } + @endcode + + The `items()` function also allows to use + [structured bindings](https://en.cppreference.com/w/cpp/language/structured_binding) + (C++17): + + @code{cpp} + for (auto& [key, val] : j_object.items()) + { + std::cout << "key: " << key << ", value:" << val << '\n'; + } + @endcode + + @note When iterating over an array, `key()` will return the index of the + element as string (see example). For primitive types (e.g., numbers), + `key()` returns an empty string. + + @warning Using `items()` on temporary objects is dangerous. Make sure the + object's lifetime exeeds the iteration. See + for more + information. + + @return iteration proxy object wrapping @a ref with an interface to use in + range-based for loops + + @liveexample{The following code shows how the function is used.,items} + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + + @since version 3.1.0, structured bindings support since 3.5.0. + */ + iteration_proxy items() noexcept + { + return iteration_proxy(*this); + } + + /*! + @copydoc items() + */ + iteration_proxy items() const noexcept + { + return iteration_proxy(*this); + } + + /// @} + + + ////////////// + // capacity // + ////////////// + + /// @name capacity + /// @{ + + /*! + @brief checks whether the container is empty. + + Checks if a JSON value has no elements (i.e. whether its @ref size is `0`). + + @return The return value depends on the different types and is + defined as follows: + Value type | return value + ----------- | ------------- + null | `true` + boolean | `false` + string | `false` + number | `false` + binary | `false` + object | result of function `object_t::empty()` + array | result of function `array_t::empty()` + + @liveexample{The following code uses `empty()` to check if a JSON + object contains any elements.,empty} + + @complexity Constant, as long as @ref array_t and @ref object_t satisfy + the Container concept; that is, their `empty()` functions have constant + complexity. + + @iterators No changes. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @note This function does not return whether a string stored as JSON value + is empty - it returns whether the JSON container itself is empty which is + false in the case of a string. + + @requirement This function helps `basic_json` satisfying the + [Container](https://en.cppreference.com/w/cpp/named_req/Container) + requirements: + - The complexity is constant. + - Has the semantics of `begin() == end()`. + + @sa see @ref size() -- returns the number of elements + + @since version 1.0.0 + */ + bool empty() const noexcept + { + switch (m_type) + { + case value_t::null: + { + // null values are empty + return true; + } + + case value_t::array: + { + // delegate call to array_t::empty() + return m_value.array->empty(); + } + + case value_t::object: + { + // delegate call to object_t::empty() + return m_value.object->empty(); + } + + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + { + // all other types are nonempty + return false; + } + } + } + + /*! + @brief returns the number of elements + + Returns the number of elements in a JSON value. + + @return The return value depends on the different types and is + defined as follows: + Value type | return value + ----------- | ------------- + null | `0` + boolean | `1` + string | `1` + number | `1` + binary | `1` + object | result of function object_t::size() + array | result of function array_t::size() + + @liveexample{The following code calls `size()` on the different value + types.,size} + + @complexity Constant, as long as @ref array_t and @ref object_t satisfy + the Container concept; that is, their size() functions have constant + complexity. + + @iterators No changes. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @note This function does not return the length of a string stored as JSON + value - it returns the number of elements in the JSON value which is 1 in + the case of a string. + + @requirement This function helps `basic_json` satisfying the + [Container](https://en.cppreference.com/w/cpp/named_req/Container) + requirements: + - The complexity is constant. + - Has the semantics of `std::distance(begin(), end())`. + + @sa see @ref empty() -- checks whether the container is empty + @sa see @ref max_size() -- returns the maximal number of elements + + @since version 1.0.0 + */ + size_type size() const noexcept + { + switch (m_type) + { + case value_t::null: + { + // null values are empty + return 0; + } + + case value_t::array: + { + // delegate call to array_t::size() + return m_value.array->size(); + } + + case value_t::object: + { + // delegate call to object_t::size() + return m_value.object->size(); + } + + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + { + // all other types have size 1 + return 1; + } + } + } + + /*! + @brief returns the maximum possible number of elements + + Returns the maximum number of elements a JSON value is able to hold due to + system or library implementation limitations, i.e. `std::distance(begin(), + end())` for the JSON value. + + @return The return value depends on the different types and is + defined as follows: + Value type | return value + ----------- | ------------- + null | `0` (same as `size()`) + boolean | `1` (same as `size()`) + string | `1` (same as `size()`) + number | `1` (same as `size()`) + binary | `1` (same as `size()`) + object | result of function `object_t::max_size()` + array | result of function `array_t::max_size()` + + @liveexample{The following code calls `max_size()` on the different value + types. Note the output is implementation specific.,max_size} + + @complexity Constant, as long as @ref array_t and @ref object_t satisfy + the Container concept; that is, their `max_size()` functions have constant + complexity. + + @iterators No changes. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @requirement This function helps `basic_json` satisfying the + [Container](https://en.cppreference.com/w/cpp/named_req/Container) + requirements: + - The complexity is constant. + - Has the semantics of returning `b.size()` where `b` is the largest + possible JSON value. + + @sa see @ref size() -- returns the number of elements + + @since version 1.0.0 + */ + size_type max_size() const noexcept + { + switch (m_type) + { + case value_t::array: + { + // delegate call to array_t::max_size() + return m_value.array->max_size(); + } + + case value_t::object: + { + // delegate call to object_t::max_size() + return m_value.object->max_size(); + } + + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + { + // all other types have max_size() == size() + return size(); + } + } + } + + /// @} + + + /////////////// + // modifiers // + /////////////// + + /// @name modifiers + /// @{ + + /*! + @brief clears the contents + + Clears the content of a JSON value and resets it to the default value as + if @ref basic_json(value_t) would have been called with the current value + type from @ref type(): + + Value type | initial value + ----------- | ------------- + null | `null` + boolean | `false` + string | `""` + number | `0` + binary | An empty byte vector + object | `{}` + array | `[]` + + @post Has the same effect as calling + @code {.cpp} + *this = basic_json(type()); + @endcode + + @liveexample{The example below shows the effect of `clear()` to different + JSON types.,clear} + + @complexity Linear in the size of the JSON value. + + @iterators All iterators, pointers and references related to this container + are invalidated. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @sa see @ref basic_json(value_t) -- constructor that creates an object with the + same value than calling `clear()` + + @since version 1.0.0 + */ + void clear() noexcept + { + switch (m_type) + { + case value_t::number_integer: + { + m_value.number_integer = 0; + break; + } + + case value_t::number_unsigned: + { + m_value.number_unsigned = 0; + break; + } + + case value_t::number_float: + { + m_value.number_float = 0.0; + break; + } + + case value_t::boolean: + { + m_value.boolean = false; + break; + } + + case value_t::string: + { + m_value.string->clear(); + break; + } + + case value_t::binary: + { + m_value.binary->clear(); + break; + } + + case value_t::array: + { + m_value.array->clear(); + break; + } + + case value_t::object: + { + m_value.object->clear(); + break; + } + + case value_t::null: + case value_t::discarded: + default: + break; + } + } + + /*! + @brief add an object to an array + + Appends the given element @a val to the end of the JSON value. If the + function is called on a JSON null value, an empty array is created before + appending @a val. + + @param[in] val the value to add to the JSON array + + @throw type_error.308 when called on a type other than JSON array or + null; example: `"cannot use push_back() with number"` + + @complexity Amortized constant. + + @liveexample{The example shows how `push_back()` and `+=` can be used to + add elements to a JSON array. Note how the `null` value was silently + converted to a JSON array.,push_back} + + @since version 1.0.0 + */ + void push_back(basic_json&& val) + { + // push_back only works for null objects or arrays + if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array()))) + { + JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name()), *this)); + } + + // transform null object into an array + if (is_null()) + { + m_type = value_t::array; + m_value = value_t::array; + assert_invariant(); + } + + // add element to array (move semantics) + const auto old_capacity = m_value.array->capacity(); + m_value.array->push_back(std::move(val)); + set_parent(m_value.array->back(), old_capacity); + // if val is moved from, basic_json move constructor marks it null so we do not call the destructor + } + + /*! + @brief add an object to an array + @copydoc push_back(basic_json&&) + */ + reference operator+=(basic_json&& val) + { + push_back(std::move(val)); + return *this; + } + + /*! + @brief add an object to an array + @copydoc push_back(basic_json&&) + */ + void push_back(const basic_json& val) + { + // push_back only works for null objects or arrays + if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array()))) + { + JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name()), *this)); + } + + // transform null object into an array + if (is_null()) + { + m_type = value_t::array; + m_value = value_t::array; + assert_invariant(); + } + + // add element to array + const auto old_capacity = m_value.array->capacity(); + m_value.array->push_back(val); + set_parent(m_value.array->back(), old_capacity); + } + + /*! + @brief add an object to an array + @copydoc push_back(basic_json&&) + */ + reference operator+=(const basic_json& val) + { + push_back(val); + return *this; + } + + /*! + @brief add an object to an object + + Inserts the given element @a val to the JSON object. If the function is + called on a JSON null value, an empty object is created before inserting + @a val. + + @param[in] val the value to add to the JSON object + + @throw type_error.308 when called on a type other than JSON object or + null; example: `"cannot use push_back() with number"` + + @complexity Logarithmic in the size of the container, O(log(`size()`)). + + @liveexample{The example shows how `push_back()` and `+=` can be used to + add elements to a JSON object. Note how the `null` value was silently + converted to a JSON object.,push_back__object_t__value} + + @since version 1.0.0 + */ + void push_back(const typename object_t::value_type& val) + { + // push_back only works for null objects or objects + if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object()))) + { + JSON_THROW(type_error::create(308, "cannot use push_back() with " + std::string(type_name()), *this)); + } + + // transform null object into an object + if (is_null()) + { + m_type = value_t::object; + m_value = value_t::object; + assert_invariant(); + } + + // add element to object + auto res = m_value.object->insert(val); + set_parent(res.first->second); + } + + /*! + @brief add an object to an object + @copydoc push_back(const typename object_t::value_type&) + */ + reference operator+=(const typename object_t::value_type& val) + { + push_back(val); + return *this; + } + + /*! + @brief add an object to an object + + This function allows to use `push_back` with an initializer list. In case + + 1. the current value is an object, + 2. the initializer list @a init contains only two elements, and + 3. the first element of @a init is a string, + + @a init is converted into an object element and added using + @ref push_back(const typename object_t::value_type&). Otherwise, @a init + is converted to a JSON value and added using @ref push_back(basic_json&&). + + @param[in] init an initializer list + + @complexity Linear in the size of the initializer list @a init. + + @note This function is required to resolve an ambiguous overload error, + because pairs like `{"key", "value"}` can be both interpreted as + `object_t::value_type` or `std::initializer_list`, see + https://github.com/nlohmann/json/issues/235 for more information. + + @liveexample{The example shows how initializer lists are treated as + objects when possible.,push_back__initializer_list} + */ + void push_back(initializer_list_t init) + { + if (is_object() && init.size() == 2 && (*init.begin())->is_string()) + { + basic_json&& key = init.begin()->moved_or_copied(); + push_back(typename object_t::value_type( + std::move(key.get_ref()), (init.begin() + 1)->moved_or_copied())); + } + else + { + push_back(basic_json(init)); + } + } + + /*! + @brief add an object to an object + @copydoc push_back(initializer_list_t) + */ + reference operator+=(initializer_list_t init) + { + push_back(init); + return *this; + } + + /*! + @brief add an object to an array + + Creates a JSON value from the passed parameters @a args to the end of the + JSON value. If the function is called on a JSON null value, an empty array + is created before appending the value created from @a args. + + @param[in] args arguments to forward to a constructor of @ref basic_json + @tparam Args compatible types to create a @ref basic_json object + + @return reference to the inserted element + + @throw type_error.311 when called on a type other than JSON array or + null; example: `"cannot use emplace_back() with number"` + + @complexity Amortized constant. + + @liveexample{The example shows how `push_back()` can be used to add + elements to a JSON array. Note how the `null` value was silently converted + to a JSON array.,emplace_back} + + @since version 2.0.8, returns reference since 3.7.0 + */ + template + reference emplace_back(Args&& ... args) + { + // emplace_back only works for null objects or arrays + if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array()))) + { + JSON_THROW(type_error::create(311, "cannot use emplace_back() with " + std::string(type_name()), *this)); + } + + // transform null object into an array + if (is_null()) + { + m_type = value_t::array; + m_value = value_t::array; + assert_invariant(); + } + + // add element to array (perfect forwarding) + const auto old_capacity = m_value.array->capacity(); + m_value.array->emplace_back(std::forward(args)...); + return set_parent(m_value.array->back(), old_capacity); + } + + /*! + @brief add an object to an object if key does not exist + + Inserts a new element into a JSON object constructed in-place with the + given @a args if there is no element with the key in the container. If the + function is called on a JSON null value, an empty object is created before + appending the value created from @a args. + + @param[in] args arguments to forward to a constructor of @ref basic_json + @tparam Args compatible types to create a @ref basic_json object + + @return a pair consisting of an iterator to the inserted element, or the + already-existing element if no insertion happened, and a bool + denoting whether the insertion took place. + + @throw type_error.311 when called on a type other than JSON object or + null; example: `"cannot use emplace() with number"` + + @complexity Logarithmic in the size of the container, O(log(`size()`)). + + @liveexample{The example shows how `emplace()` can be used to add elements + to a JSON object. Note how the `null` value was silently converted to a + JSON object. Further note how no value is added if there was already one + value stored with the same key.,emplace} + + @since version 2.0.8 + */ + template + std::pair emplace(Args&& ... args) + { + // emplace only works for null objects or arrays + if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object()))) + { + JSON_THROW(type_error::create(311, "cannot use emplace() with " + std::string(type_name()), *this)); + } + + // transform null object into an object + if (is_null()) + { + m_type = value_t::object; + m_value = value_t::object; + assert_invariant(); + } + + // add element to array (perfect forwarding) + auto res = m_value.object->emplace(std::forward(args)...); + set_parent(res.first->second); + + // create result iterator and set iterator to the result of emplace + auto it = begin(); + it.m_it.object_iterator = res.first; + + // return pair of iterator and boolean + return {it, res.second}; + } + + /// Helper for insertion of an iterator + /// @note: This uses std::distance to support GCC 4.8, + /// see https://github.com/nlohmann/json/pull/1257 + template + iterator insert_iterator(const_iterator pos, Args&& ... args) + { + iterator result(this); + JSON_ASSERT(m_value.array != nullptr); + + auto insert_pos = std::distance(m_value.array->begin(), pos.m_it.array_iterator); + m_value.array->insert(pos.m_it.array_iterator, std::forward(args)...); + result.m_it.array_iterator = m_value.array->begin() + insert_pos; + + // This could have been written as: + // result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val); + // but the return value of insert is missing in GCC 4.8, so it is written this way instead. + + set_parents(); + return result; + } + + /*! + @brief inserts element + + Inserts element @a val before iterator @a pos. + + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] val element to insert + @return iterator pointing to the inserted @a val. + + @throw type_error.309 if called on JSON values other than arrays; + example: `"cannot use insert() with string"` + @throw invalid_iterator.202 if @a pos is not an iterator of *this; + example: `"iterator does not fit current value"` + + @complexity Constant plus linear in the distance between @a pos and end of + the container. + + @liveexample{The example shows how `insert()` is used.,insert} + + @since version 1.0.0 + */ + iterator insert(const_iterator pos, const basic_json& val) + { + // insert only works for arrays + if (JSON_HEDLEY_LIKELY(is_array())) + { + // check if iterator pos fits to this JSON value + if (JSON_HEDLEY_UNLIKELY(pos.m_object != this)) + { + JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", *this)); + } + + // insert to array and return iterator + return insert_iterator(pos, val); + } + + JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()), *this)); + } + + /*! + @brief inserts element + @copydoc insert(const_iterator, const basic_json&) + */ + iterator insert(const_iterator pos, basic_json&& val) + { + return insert(pos, val); + } + + /*! + @brief inserts elements + + Inserts @a cnt copies of @a val before iterator @a pos. + + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] cnt number of copies of @a val to insert + @param[in] val element to insert + @return iterator pointing to the first element inserted, or @a pos if + `cnt==0` + + @throw type_error.309 if called on JSON values other than arrays; example: + `"cannot use insert() with string"` + @throw invalid_iterator.202 if @a pos is not an iterator of *this; + example: `"iterator does not fit current value"` + + @complexity Linear in @a cnt plus linear in the distance between @a pos + and end of the container. + + @liveexample{The example shows how `insert()` is used.,insert__count} + + @since version 1.0.0 + */ + iterator insert(const_iterator pos, size_type cnt, const basic_json& val) + { + // insert only works for arrays + if (JSON_HEDLEY_LIKELY(is_array())) + { + // check if iterator pos fits to this JSON value + if (JSON_HEDLEY_UNLIKELY(pos.m_object != this)) + { + JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", *this)); + } + + // insert to array and return iterator + return insert_iterator(pos, cnt, val); + } + + JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()), *this)); + } + + /*! + @brief inserts elements + + Inserts elements from range `[first, last)` before iterator @a pos. + + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] first begin of the range of elements to insert + @param[in] last end of the range of elements to insert + + @throw type_error.309 if called on JSON values other than arrays; example: + `"cannot use insert() with string"` + @throw invalid_iterator.202 if @a pos is not an iterator of *this; + example: `"iterator does not fit current value"` + @throw invalid_iterator.210 if @a first and @a last do not belong to the + same JSON value; example: `"iterators do not fit"` + @throw invalid_iterator.211 if @a first or @a last are iterators into + container for which insert is called; example: `"passed iterators may not + belong to container"` + + @return iterator pointing to the first element inserted, or @a pos if + `first==last` + + @complexity Linear in `std::distance(first, last)` plus linear in the + distance between @a pos and end of the container. + + @liveexample{The example shows how `insert()` is used.,insert__range} + + @since version 1.0.0 + */ + iterator insert(const_iterator pos, const_iterator first, const_iterator last) + { + // insert only works for arrays + if (JSON_HEDLEY_UNLIKELY(!is_array())) + { + JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()), *this)); + } + + // check if iterator pos fits to this JSON value + if (JSON_HEDLEY_UNLIKELY(pos.m_object != this)) + { + JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", *this)); + } + + // check if range iterators belong to the same JSON object + if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object)) + { + JSON_THROW(invalid_iterator::create(210, "iterators do not fit", *this)); + } + + if (JSON_HEDLEY_UNLIKELY(first.m_object == this)) + { + JSON_THROW(invalid_iterator::create(211, "passed iterators may not belong to container", *this)); + } + + // insert to array and return iterator + return insert_iterator(pos, first.m_it.array_iterator, last.m_it.array_iterator); + } + + /*! + @brief inserts elements + + Inserts elements from initializer list @a ilist before iterator @a pos. + + @param[in] pos iterator before which the content will be inserted; may be + the end() iterator + @param[in] ilist initializer list to insert the values from + + @throw type_error.309 if called on JSON values other than arrays; example: + `"cannot use insert() with string"` + @throw invalid_iterator.202 if @a pos is not an iterator of *this; + example: `"iterator does not fit current value"` + + @return iterator pointing to the first element inserted, or @a pos if + `ilist` is empty + + @complexity Linear in `ilist.size()` plus linear in the distance between + @a pos and end of the container. + + @liveexample{The example shows how `insert()` is used.,insert__ilist} + + @since version 1.0.0 + */ + iterator insert(const_iterator pos, initializer_list_t ilist) + { + // insert only works for arrays + if (JSON_HEDLEY_UNLIKELY(!is_array())) + { + JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()), *this)); + } + + // check if iterator pos fits to this JSON value + if (JSON_HEDLEY_UNLIKELY(pos.m_object != this)) + { + JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", *this)); + } + + // insert to array and return iterator + return insert_iterator(pos, ilist.begin(), ilist.end()); + } + + /*! + @brief inserts elements + + Inserts elements from range `[first, last)`. + + @param[in] first begin of the range of elements to insert + @param[in] last end of the range of elements to insert + + @throw type_error.309 if called on JSON values other than objects; example: + `"cannot use insert() with string"` + @throw invalid_iterator.202 if iterator @a first or @a last does does not + point to an object; example: `"iterators first and last must point to + objects"` + @throw invalid_iterator.210 if @a first and @a last do not belong to the + same JSON value; example: `"iterators do not fit"` + + @complexity Logarithmic: `O(N*log(size() + N))`, where `N` is the number + of elements to insert. + + @liveexample{The example shows how `insert()` is used.,insert__range_object} + + @since version 3.0.0 + */ + void insert(const_iterator first, const_iterator last) + { + // insert only works for objects + if (JSON_HEDLEY_UNLIKELY(!is_object())) + { + JSON_THROW(type_error::create(309, "cannot use insert() with " + std::string(type_name()), *this)); + } + + // check if range iterators belong to the same JSON object + if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object)) + { + JSON_THROW(invalid_iterator::create(210, "iterators do not fit", *this)); + } + + // passed iterators must belong to objects + if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object())) + { + JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects", *this)); + } + + m_value.object->insert(first.m_it.object_iterator, last.m_it.object_iterator); + } + + /*! + @brief updates a JSON object from another object, overwriting existing keys + + Inserts all values from JSON object @a j and overwrites existing keys. + + @param[in] j JSON object to read values from + + @throw type_error.312 if called on JSON values other than objects; example: + `"cannot use update() with string"` + + @complexity O(N*log(size() + N)), where N is the number of elements to + insert. + + @liveexample{The example shows how `update()` is used.,update} + + @sa https://docs.python.org/3.6/library/stdtypes.html#dict.update + + @since version 3.0.0 + */ + void update(const_reference j) + { + // implicitly convert null value to an empty object + if (is_null()) + { + m_type = value_t::object; + m_value.object = create(); + assert_invariant(); + } + + if (JSON_HEDLEY_UNLIKELY(!is_object())) + { + JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(type_name()), *this)); + } + if (JSON_HEDLEY_UNLIKELY(!j.is_object())) + { + JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(j.type_name()), *this)); + } + + for (auto it = j.cbegin(); it != j.cend(); ++it) + { + m_value.object->operator[](it.key()) = it.value(); +#if JSON_DIAGNOSTICS + m_value.object->operator[](it.key()).m_parent = this; +#endif + } + } + + /*! + @brief updates a JSON object from another object, overwriting existing keys + + Inserts all values from from range `[first, last)` and overwrites existing + keys. + + @param[in] first begin of the range of elements to insert + @param[in] last end of the range of elements to insert + + @throw type_error.312 if called on JSON values other than objects; example: + `"cannot use update() with string"` + @throw invalid_iterator.202 if iterator @a first or @a last does does not + point to an object; example: `"iterators first and last must point to + objects"` + @throw invalid_iterator.210 if @a first and @a last do not belong to the + same JSON value; example: `"iterators do not fit"` + + @complexity O(N*log(size() + N)), where N is the number of elements to + insert. + + @liveexample{The example shows how `update()` is used__range.,update} + + @sa https://docs.python.org/3.6/library/stdtypes.html#dict.update + + @since version 3.0.0 + */ + void update(const_iterator first, const_iterator last) + { + // implicitly convert null value to an empty object + if (is_null()) + { + m_type = value_t::object; + m_value.object = create(); + assert_invariant(); + } + + if (JSON_HEDLEY_UNLIKELY(!is_object())) + { + JSON_THROW(type_error::create(312, "cannot use update() with " + std::string(type_name()), *this)); + } + + // check if range iterators belong to the same JSON object + if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object)) + { + JSON_THROW(invalid_iterator::create(210, "iterators do not fit", *this)); + } + + // passed iterators must belong to objects + if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object() + || !last.m_object->is_object())) + { + JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects", *this)); + } + + for (auto it = first; it != last; ++it) + { + m_value.object->operator[](it.key()) = it.value(); +#if JSON_DIAGNOSTICS + m_value.object->operator[](it.key()).m_parent = this; +#endif + } + } + + /*! + @brief exchanges the values + + Exchanges the contents of the JSON value with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other JSON value to exchange the contents with + + @complexity Constant. + + @liveexample{The example below shows how JSON values can be swapped with + `swap()`.,swap__reference} + + @since version 1.0.0 + */ + void swap(reference other) noexcept ( + std::is_nothrow_move_constructible::value&& + std::is_nothrow_move_assignable::value&& + std::is_nothrow_move_constructible::value&& + std::is_nothrow_move_assignable::value + ) + { + std::swap(m_type, other.m_type); + std::swap(m_value, other.m_value); + + set_parents(); + other.set_parents(); + assert_invariant(); + } + + /*! + @brief exchanges the values + + Exchanges the contents of the JSON value from @a left with those of @a right. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. implemented as a friend function callable via ADL. + + @param[in,out] left JSON value to exchange the contents with + @param[in,out] right JSON value to exchange the contents with + + @complexity Constant. + + @liveexample{The example below shows how JSON values can be swapped with + `swap()`.,swap__reference} + + @since version 1.0.0 + */ + friend void swap(reference left, reference right) noexcept ( + std::is_nothrow_move_constructible::value&& + std::is_nothrow_move_assignable::value&& + std::is_nothrow_move_constructible::value&& + std::is_nothrow_move_assignable::value + ) + { + left.swap(right); + } + + /*! + @brief exchanges the values + + Exchanges the contents of a JSON array with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other array to exchange the contents with + + @throw type_error.310 when JSON value is not an array; example: `"cannot + use swap() with string"` + + @complexity Constant. + + @liveexample{The example below shows how arrays can be swapped with + `swap()`.,swap__array_t} + + @since version 1.0.0 + */ + void swap(array_t& other) // NOLINT(bugprone-exception-escape) + { + // swap only works for arrays + if (JSON_HEDLEY_LIKELY(is_array())) + { + std::swap(*(m_value.array), other); + } + else + { + JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()), *this)); + } + } + + /*! + @brief exchanges the values + + Exchanges the contents of a JSON object with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other object to exchange the contents with + + @throw type_error.310 when JSON value is not an object; example: + `"cannot use swap() with string"` + + @complexity Constant. + + @liveexample{The example below shows how objects can be swapped with + `swap()`.,swap__object_t} + + @since version 1.0.0 + */ + void swap(object_t& other) // NOLINT(bugprone-exception-escape) + { + // swap only works for objects + if (JSON_HEDLEY_LIKELY(is_object())) + { + std::swap(*(m_value.object), other); + } + else + { + JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()), *this)); + } + } + + /*! + @brief exchanges the values + + Exchanges the contents of a JSON string with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other string to exchange the contents with + + @throw type_error.310 when JSON value is not a string; example: `"cannot + use swap() with boolean"` + + @complexity Constant. + + @liveexample{The example below shows how strings can be swapped with + `swap()`.,swap__string_t} + + @since version 1.0.0 + */ + void swap(string_t& other) // NOLINT(bugprone-exception-escape) + { + // swap only works for strings + if (JSON_HEDLEY_LIKELY(is_string())) + { + std::swap(*(m_value.string), other); + } + else + { + JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()), *this)); + } + } + + /*! + @brief exchanges the values + + Exchanges the contents of a JSON string with those of @a other. Does not + invoke any move, copy, or swap operations on individual elements. All + iterators and references remain valid. The past-the-end iterator is + invalidated. + + @param[in,out] other binary to exchange the contents with + + @throw type_error.310 when JSON value is not a string; example: `"cannot + use swap() with boolean"` + + @complexity Constant. + + @liveexample{The example below shows how strings can be swapped with + `swap()`.,swap__binary_t} + + @since version 3.8.0 + */ + void swap(binary_t& other) // NOLINT(bugprone-exception-escape) + { + // swap only works for strings + if (JSON_HEDLEY_LIKELY(is_binary())) + { + std::swap(*(m_value.binary), other); + } + else + { + JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()), *this)); + } + } + + /// @copydoc swap(binary_t&) + void swap(typename binary_t::container_type& other) // NOLINT(bugprone-exception-escape) + { + // swap only works for strings + if (JSON_HEDLEY_LIKELY(is_binary())) + { + std::swap(*(m_value.binary), other); + } + else + { + JSON_THROW(type_error::create(310, "cannot use swap() with " + std::string(type_name()), *this)); + } + } + + /// @} + + public: + ////////////////////////////////////////// + // lexicographical comparison operators // + ////////////////////////////////////////// + + /// @name lexicographical comparison operators + /// @{ + + /*! + @brief comparison: equal + + Compares two JSON values for equality according to the following rules: + - Two JSON values are equal if (1) they are from the same type and (2) + their stored values are the same according to their respective + `operator==`. + - Integer and floating-point numbers are automatically converted before + comparison. Note that two NaN values are always treated as unequal. + - Two JSON null values are equal. + + @note Floating-point inside JSON values numbers are compared with + `json::number_float_t::operator==` which is `double::operator==` by + default. To compare floating-point while respecting an epsilon, an alternative + [comparison function](https://github.com/mariokonrad/marnav/blob/master/include/marnav/math/floatingpoint.hpp#L34-#L39) + could be used, for instance + @code {.cpp} + template::value, T>::type> + inline bool is_same(T a, T b, T epsilon = std::numeric_limits::epsilon()) noexcept + { + return std::abs(a - b) <= epsilon; + } + @endcode + Or you can self-defined operator equal function like this: + @code {.cpp} + bool my_equal(const_reference lhs, const_reference rhs) { + const auto lhs_type lhs.type(); + const auto rhs_type rhs.type(); + if (lhs_type == rhs_type) { + switch(lhs_type) + // self_defined case + case value_t::number_float: + return std::abs(lhs - rhs) <= std::numeric_limits::epsilon(); + // other cases remain the same with the original + ... + } + ... + } + @endcode + + @note NaN values never compare equal to themselves or to other NaN values. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether the values @a lhs and @a rhs are equal + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @complexity Linear. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__equal} + + @since version 1.0.0 + */ + friend bool operator==(const_reference lhs, const_reference rhs) noexcept + { +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wfloat-equal" +#endif + const auto lhs_type = lhs.type(); + const auto rhs_type = rhs.type(); + + if (lhs_type == rhs_type) + { + switch (lhs_type) + { + case value_t::array: + return *lhs.m_value.array == *rhs.m_value.array; + + case value_t::object: + return *lhs.m_value.object == *rhs.m_value.object; + + case value_t::null: + return true; + + case value_t::string: + return *lhs.m_value.string == *rhs.m_value.string; + + case value_t::boolean: + return lhs.m_value.boolean == rhs.m_value.boolean; + + case value_t::number_integer: + return lhs.m_value.number_integer == rhs.m_value.number_integer; + + case value_t::number_unsigned: + return lhs.m_value.number_unsigned == rhs.m_value.number_unsigned; + + case value_t::number_float: + return lhs.m_value.number_float == rhs.m_value.number_float; + + case value_t::binary: + return *lhs.m_value.binary == *rhs.m_value.binary; + + case value_t::discarded: + default: + return false; + } + } + else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_float) + { + return static_cast(lhs.m_value.number_integer) == rhs.m_value.number_float; + } + else if (lhs_type == value_t::number_float && rhs_type == value_t::number_integer) + { + return lhs.m_value.number_float == static_cast(rhs.m_value.number_integer); + } + else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_float) + { + return static_cast(lhs.m_value.number_unsigned) == rhs.m_value.number_float; + } + else if (lhs_type == value_t::number_float && rhs_type == value_t::number_unsigned) + { + return lhs.m_value.number_float == static_cast(rhs.m_value.number_unsigned); + } + else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_integer) + { + return static_cast(lhs.m_value.number_unsigned) == rhs.m_value.number_integer; + } + else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_unsigned) + { + return lhs.m_value.number_integer == static_cast(rhs.m_value.number_unsigned); + } + + return false; +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + } + + /*! + @brief comparison: equal + @copydoc operator==(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator==(const_reference lhs, ScalarType rhs) noexcept + { + return lhs == basic_json(rhs); + } + + /*! + @brief comparison: equal + @copydoc operator==(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator==(ScalarType lhs, const_reference rhs) noexcept + { + return basic_json(lhs) == rhs; + } + + /*! + @brief comparison: not equal + + Compares two JSON values for inequality by calculating `not (lhs == rhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether the values @a lhs and @a rhs are not equal + + @complexity Linear. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__notequal} + + @since version 1.0.0 + */ + friend bool operator!=(const_reference lhs, const_reference rhs) noexcept + { + return !(lhs == rhs); + } + + /*! + @brief comparison: not equal + @copydoc operator!=(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator!=(const_reference lhs, ScalarType rhs) noexcept + { + return lhs != basic_json(rhs); + } + + /*! + @brief comparison: not equal + @copydoc operator!=(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator!=(ScalarType lhs, const_reference rhs) noexcept + { + return basic_json(lhs) != rhs; + } + + /*! + @brief comparison: less than + + Compares whether one JSON value @a lhs is less than another JSON value @a + rhs according to the following rules: + - If @a lhs and @a rhs have the same type, the values are compared using + the default `<` operator. + - Integer and floating-point numbers are automatically converted before + comparison + - In case @a lhs and @a rhs have different types, the values are ignored + and the order of the types is considered, see + @ref operator<(const value_t, const value_t). + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is less than @a rhs + + @complexity Linear. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__less} + + @since version 1.0.0 + */ + friend bool operator<(const_reference lhs, const_reference rhs) noexcept + { + const auto lhs_type = lhs.type(); + const auto rhs_type = rhs.type(); + + if (lhs_type == rhs_type) + { + switch (lhs_type) + { + case value_t::array: + // note parentheses are necessary, see + // https://github.com/nlohmann/json/issues/1530 + return (*lhs.m_value.array) < (*rhs.m_value.array); + + case value_t::object: + return (*lhs.m_value.object) < (*rhs.m_value.object); + + case value_t::null: + return false; + + case value_t::string: + return (*lhs.m_value.string) < (*rhs.m_value.string); + + case value_t::boolean: + return (lhs.m_value.boolean) < (rhs.m_value.boolean); + + case value_t::number_integer: + return (lhs.m_value.number_integer) < (rhs.m_value.number_integer); + + case value_t::number_unsigned: + return (lhs.m_value.number_unsigned) < (rhs.m_value.number_unsigned); + + case value_t::number_float: + return (lhs.m_value.number_float) < (rhs.m_value.number_float); + + case value_t::binary: + return (*lhs.m_value.binary) < (*rhs.m_value.binary); + + case value_t::discarded: + default: + return false; + } + } + else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_float) + { + return static_cast(lhs.m_value.number_integer) < rhs.m_value.number_float; + } + else if (lhs_type == value_t::number_float && rhs_type == value_t::number_integer) + { + return lhs.m_value.number_float < static_cast(rhs.m_value.number_integer); + } + else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_float) + { + return static_cast(lhs.m_value.number_unsigned) < rhs.m_value.number_float; + } + else if (lhs_type == value_t::number_float && rhs_type == value_t::number_unsigned) + { + return lhs.m_value.number_float < static_cast(rhs.m_value.number_unsigned); + } + else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_unsigned) + { + return lhs.m_value.number_integer < static_cast(rhs.m_value.number_unsigned); + } + else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_integer) + { + return static_cast(lhs.m_value.number_unsigned) < rhs.m_value.number_integer; + } + + // We only reach this line if we cannot compare values. In that case, + // we compare types. Note we have to call the operator explicitly, + // because MSVC has problems otherwise. + return operator<(lhs_type, rhs_type); + } + + /*! + @brief comparison: less than + @copydoc operator<(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator<(const_reference lhs, ScalarType rhs) noexcept + { + return lhs < basic_json(rhs); + } + + /*! + @brief comparison: less than + @copydoc operator<(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator<(ScalarType lhs, const_reference rhs) noexcept + { + return basic_json(lhs) < rhs; + } + + /*! + @brief comparison: less than or equal + + Compares whether one JSON value @a lhs is less than or equal to another + JSON value by calculating `not (rhs < lhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is less than or equal to @a rhs + + @complexity Linear. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__greater} + + @since version 1.0.0 + */ + friend bool operator<=(const_reference lhs, const_reference rhs) noexcept + { + return !(rhs < lhs); + } + + /*! + @brief comparison: less than or equal + @copydoc operator<=(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator<=(const_reference lhs, ScalarType rhs) noexcept + { + return lhs <= basic_json(rhs); + } + + /*! + @brief comparison: less than or equal + @copydoc operator<=(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept + { + return basic_json(lhs) <= rhs; + } + + /*! + @brief comparison: greater than + + Compares whether one JSON value @a lhs is greater than another + JSON value by calculating `not (lhs <= rhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is greater than to @a rhs + + @complexity Linear. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__lessequal} + + @since version 1.0.0 + */ + friend bool operator>(const_reference lhs, const_reference rhs) noexcept + { + return !(lhs <= rhs); + } + + /*! + @brief comparison: greater than + @copydoc operator>(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator>(const_reference lhs, ScalarType rhs) noexcept + { + return lhs > basic_json(rhs); + } + + /*! + @brief comparison: greater than + @copydoc operator>(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator>(ScalarType lhs, const_reference rhs) noexcept + { + return basic_json(lhs) > rhs; + } + + /*! + @brief comparison: greater than or equal + + Compares whether one JSON value @a lhs is greater than or equal to another + JSON value by calculating `not (lhs < rhs)`. + + @param[in] lhs first JSON value to consider + @param[in] rhs second JSON value to consider + @return whether @a lhs is greater than or equal to @a rhs + + @complexity Linear. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @liveexample{The example demonstrates comparing several JSON + types.,operator__greaterequal} + + @since version 1.0.0 + */ + friend bool operator>=(const_reference lhs, const_reference rhs) noexcept + { + return !(lhs < rhs); + } + + /*! + @brief comparison: greater than or equal + @copydoc operator>=(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator>=(const_reference lhs, ScalarType rhs) noexcept + { + return lhs >= basic_json(rhs); + } + + /*! + @brief comparison: greater than or equal + @copydoc operator>=(const_reference, const_reference) + */ + template::value, int>::type = 0> + friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept + { + return basic_json(lhs) >= rhs; + } + + /// @} + + /////////////////// + // serialization // + /////////////////// + + /// @name serialization + /// @{ +#ifndef JSON_NO_IO + /*! + @brief serialize to stream + + Serialize the given JSON value @a j to the output stream @a o. The JSON + value will be serialized using the @ref dump member function. + + - The indentation of the output can be controlled with the member variable + `width` of the output stream @a o. For instance, using the manipulator + `std::setw(4)` on @a o sets the indentation level to `4` and the + serialization result is the same as calling `dump(4)`. + + - The indentation character can be controlled with the member variable + `fill` of the output stream @a o. For instance, the manipulator + `std::setfill('\\t')` sets indentation to use a tab character rather than + the default space character. + + @param[in,out] o stream to serialize to + @param[in] j JSON value to serialize + + @return the stream @a o + + @throw type_error.316 if a string stored inside the JSON value is not + UTF-8 encoded + + @complexity Linear. + + @liveexample{The example below shows the serialization with different + parameters to `width` to adjust the indentation level.,operator_serialize} + + @since version 1.0.0; indentation character added in version 3.0.0 + */ + friend std::ostream& operator<<(std::ostream& o, const basic_json& j) + { + // read width member and use it as indentation parameter if nonzero + const bool pretty_print = o.width() > 0; + const auto indentation = pretty_print ? o.width() : 0; + + // reset width to 0 for subsequent calls to this stream + o.width(0); + + // do the actual serialization + serializer s(detail::output_adapter(o), o.fill()); + s.dump(j, pretty_print, false, static_cast(indentation)); + return o; + } + + /*! + @brief serialize to stream + @deprecated This stream operator is deprecated and will be removed in + future 4.0.0 of the library. Please use + @ref operator<<(std::ostream&, const basic_json&) + instead; that is, replace calls like `j >> o;` with `o << j;`. + @since version 1.0.0; deprecated since version 3.0.0 + */ + JSON_HEDLEY_DEPRECATED_FOR(3.0.0, operator<<(std::ostream&, const basic_json&)) + friend std::ostream& operator>>(const basic_json& j, std::ostream& o) + { + return o << j; + } +#endif // JSON_NO_IO + /// @} + + + ///////////////////// + // deserialization // + ///////////////////// + + /// @name deserialization + /// @{ + + /*! + @brief deserialize from a compatible input + + @tparam InputType A compatible input, for instance + - an std::istream object + - a FILE pointer + - a C-style array of characters + - a pointer to a null-terminated string of single byte characters + - an object obj for which begin(obj) and end(obj) produces a valid pair of + iterators. + + @param[in] i input to read from + @param[in] cb a parser callback function of type @ref parser_callback_t + which is used to control the deserialization by filtering unwanted values + (optional) + @param[in] allow_exceptions whether to throw exceptions in case of a + parse error (optional, true by default) + @param[in] ignore_comments whether comments should be ignored and treated + like whitespace (true) or yield a parse error (true); (optional, false by + default) + + @return deserialized JSON value; in case of a parse error and + @a allow_exceptions set to `false`, the return value will be + value_t::discarded. + + @throw parse_error.101 if a parse error occurs; example: `""unexpected end + of input; expected string literal""` + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. The complexity can be higher if the parser callback function + @a cb or reading from the input @a i has a super-linear complexity. + + @note A UTF-8 byte order mark is silently ignored. + + @liveexample{The example below demonstrates the `parse()` function reading + from an array.,parse__array__parser_callback_t} + + @liveexample{The example below demonstrates the `parse()` function with + and without callback function.,parse__string__parser_callback_t} + + @liveexample{The example below demonstrates the `parse()` function with + and without callback function.,parse__istream__parser_callback_t} + + @liveexample{The example below demonstrates the `parse()` function reading + from a contiguous container.,parse__contiguouscontainer__parser_callback_t} + + @since version 2.0.3 (contiguous containers); version 3.9.0 allowed to + ignore comments. + */ + template + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json parse(InputType&& i, + const parser_callback_t cb = nullptr, + const bool allow_exceptions = true, + const bool ignore_comments = false) + { + basic_json result; + parser(detail::input_adapter(std::forward(i)), cb, allow_exceptions, ignore_comments).parse(true, result); + return result; + } + + /*! + @brief deserialize from a pair of character iterators + + The value_type of the iterator must be a integral type with size of 1, 2 or + 4 bytes, which will be interpreted respectively as UTF-8, UTF-16 and UTF-32. + + @param[in] first iterator to start of character range + @param[in] last iterator to end of character range + @param[in] cb a parser callback function of type @ref parser_callback_t + which is used to control the deserialization by filtering unwanted values + (optional) + @param[in] allow_exceptions whether to throw exceptions in case of a + parse error (optional, true by default) + @param[in] ignore_comments whether comments should be ignored and treated + like whitespace (true) or yield a parse error (true); (optional, false by + default) + + @return deserialized JSON value; in case of a parse error and + @a allow_exceptions set to `false`, the return value will be + value_t::discarded. + + @throw parse_error.101 if a parse error occurs; example: `""unexpected end + of input; expected string literal""` + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + */ + template + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json parse(IteratorType first, + IteratorType last, + const parser_callback_t cb = nullptr, + const bool allow_exceptions = true, + const bool ignore_comments = false) + { + basic_json result; + parser(detail::input_adapter(std::move(first), std::move(last)), cb, allow_exceptions, ignore_comments).parse(true, result); + return result; + } + + JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, parse(ptr, ptr + len)) + static basic_json parse(detail::span_input_adapter&& i, + const parser_callback_t cb = nullptr, + const bool allow_exceptions = true, + const bool ignore_comments = false) + { + basic_json result; + parser(i.get(), cb, allow_exceptions, ignore_comments).parse(true, result); + return result; + } + + /*! + @brief check if the input is valid JSON + + Unlike the @ref parse(InputType&&, const parser_callback_t,const bool) + function, this function neither throws an exception in case of invalid JSON + input (i.e., a parse error) nor creates diagnostic information. + + @tparam InputType A compatible input, for instance + - an std::istream object + - a FILE pointer + - a C-style array of characters + - a pointer to a null-terminated string of single byte characters + - an object obj for which begin(obj) and end(obj) produces a valid pair of + iterators. + + @param[in] i input to read from + @param[in] ignore_comments whether comments should be ignored and treated + like whitespace (true) or yield a parse error (true); (optional, false by + default) + + @return Whether the input read from @a i is valid JSON. + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. + + @note A UTF-8 byte order mark is silently ignored. + + @liveexample{The example below demonstrates the `accept()` function reading + from a string.,accept__string} + */ + template + static bool accept(InputType&& i, + const bool ignore_comments = false) + { + return parser(detail::input_adapter(std::forward(i)), nullptr, false, ignore_comments).accept(true); + } + + template + static bool accept(IteratorType first, IteratorType last, + const bool ignore_comments = false) + { + return parser(detail::input_adapter(std::move(first), std::move(last)), nullptr, false, ignore_comments).accept(true); + } + + JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, accept(ptr, ptr + len)) + static bool accept(detail::span_input_adapter&& i, + const bool ignore_comments = false) + { + return parser(i.get(), nullptr, false, ignore_comments).accept(true); + } + + /*! + @brief generate SAX events + + The SAX event lister must follow the interface of @ref json_sax. + + This function reads from a compatible input. Examples are: + - an std::istream object + - a FILE pointer + - a C-style array of characters + - a pointer to a null-terminated string of single byte characters + - an object obj for which begin(obj) and end(obj) produces a valid pair of + iterators. + + @param[in] i input to read from + @param[in,out] sax SAX event listener + @param[in] format the format to parse (JSON, CBOR, MessagePack, or UBJSON) + @param[in] strict whether the input has to be consumed completely + @param[in] ignore_comments whether comments should be ignored and treated + like whitespace (true) or yield a parse error (true); (optional, false by + default); only applies to the JSON file format. + + @return return value of the last processed SAX event + + @throw parse_error.101 if a parse error occurs; example: `""unexpected end + of input; expected string literal""` + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. The complexity can be higher if the SAX consumer @a sax has + a super-linear complexity. + + @note A UTF-8 byte order mark is silently ignored. + + @liveexample{The example below demonstrates the `sax_parse()` function + reading from string and processing the events with a user-defined SAX + event consumer.,sax_parse} + + @since version 3.2.0 + */ + template + JSON_HEDLEY_NON_NULL(2) + static bool sax_parse(InputType&& i, SAX* sax, + input_format_t format = input_format_t::json, + const bool strict = true, + const bool ignore_comments = false) + { + auto ia = detail::input_adapter(std::forward(i)); + return format == input_format_t::json + ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict) + : detail::binary_reader(std::move(ia)).sax_parse(format, sax, strict); + } + + template + JSON_HEDLEY_NON_NULL(3) + static bool sax_parse(IteratorType first, IteratorType last, SAX* sax, + input_format_t format = input_format_t::json, + const bool strict = true, + const bool ignore_comments = false) + { + auto ia = detail::input_adapter(std::move(first), std::move(last)); + return format == input_format_t::json + ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict) + : detail::binary_reader(std::move(ia)).sax_parse(format, sax, strict); + } + + template + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, sax_parse(ptr, ptr + len, ...)) + JSON_HEDLEY_NON_NULL(2) + static bool sax_parse(detail::span_input_adapter&& i, SAX* sax, + input_format_t format = input_format_t::json, + const bool strict = true, + const bool ignore_comments = false) + { + auto ia = i.get(); + return format == input_format_t::json + // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) + ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict) + // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) + : detail::binary_reader(std::move(ia)).sax_parse(format, sax, strict); + } +#ifndef JSON_NO_IO + /*! + @brief deserialize from stream + @deprecated This stream operator is deprecated and will be removed in + version 4.0.0 of the library. Please use + @ref operator>>(std::istream&, basic_json&) + instead; that is, replace calls like `j << i;` with `i >> j;`. + @since version 1.0.0; deprecated since version 3.0.0 + */ + JSON_HEDLEY_DEPRECATED_FOR(3.0.0, operator>>(std::istream&, basic_json&)) + friend std::istream& operator<<(basic_json& j, std::istream& i) + { + return operator>>(i, j); + } + + /*! + @brief deserialize from stream + + Deserializes an input stream to a JSON value. + + @param[in,out] i input stream to read a serialized JSON value from + @param[in,out] j JSON value to write the deserialized input to + + @throw parse_error.101 in case of an unexpected token + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + + @complexity Linear in the length of the input. The parser is a predictive + LL(1) parser. + + @note A UTF-8 byte order mark is silently ignored. + + @liveexample{The example below shows how a JSON value is constructed by + reading a serialization from a stream.,operator_deserialize} + + @sa parse(std::istream&, const parser_callback_t) for a variant with a + parser callback function to filter values while parsing + + @since version 1.0.0 + */ + friend std::istream& operator>>(std::istream& i, basic_json& j) + { + parser(detail::input_adapter(i)).parse(false, j); + return i; + } +#endif // JSON_NO_IO + /// @} + + /////////////////////////// + // convenience functions // + /////////////////////////// + + /*! + @brief return the type as string + + Returns the type name as string to be used in error messages - usually to + indicate that a function was called on a wrong JSON type. + + @return a string representation of a the @a m_type member: + Value type | return value + ----------- | ------------- + null | `"null"` + boolean | `"boolean"` + string | `"string"` + number | `"number"` (for all number types) + object | `"object"` + array | `"array"` + binary | `"binary"` + discarded | `"discarded"` + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @complexity Constant. + + @liveexample{The following code exemplifies `type_name()` for all JSON + types.,type_name} + + @sa see @ref type() -- return the type of the JSON value + @sa see @ref operator value_t() -- return the type of the JSON value (implicit) + + @since version 1.0.0, public since 2.1.0, `const char*` and `noexcept` + since 3.0.0 + */ + JSON_HEDLEY_RETURNS_NON_NULL + const char* type_name() const noexcept + { + { + switch (m_type) + { + case value_t::null: + return "null"; + case value_t::object: + return "object"; + case value_t::array: + return "array"; + case value_t::string: + return "string"; + case value_t::boolean: + return "boolean"; + case value_t::binary: + return "binary"; + case value_t::discarded: + return "discarded"; + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + default: + return "number"; + } + } + } + + + JSON_PRIVATE_UNLESS_TESTED: + ////////////////////// + // member variables // + ////////////////////// + + /// the type of the current element + value_t m_type = value_t::null; + + /// the value of the current element + json_value m_value = {}; + +#if JSON_DIAGNOSTICS + /// a pointer to a parent value (for debugging purposes) + basic_json* m_parent = nullptr; +#endif + + ////////////////////////////////////////// + // binary serialization/deserialization // + ////////////////////////////////////////// + + /// @name binary serialization/deserialization support + /// @{ + + public: + /*! + @brief create a CBOR serialization of a given JSON value + + Serializes a given JSON value @a j to a byte vector using the CBOR (Concise + Binary Object Representation) serialization format. CBOR is a binary + serialization format which aims to be more compact than JSON itself, yet + more efficient to parse. + + The library uses the following mapping from JSON values types to + CBOR types according to the CBOR specification (RFC 7049): + + JSON value type | value/range | CBOR type | first byte + --------------- | ------------------------------------------ | ---------------------------------- | --------------- + null | `null` | Null | 0xF6 + boolean | `true` | True | 0xF5 + boolean | `false` | False | 0xF4 + number_integer | -9223372036854775808..-2147483649 | Negative integer (8 bytes follow) | 0x3B + number_integer | -2147483648..-32769 | Negative integer (4 bytes follow) | 0x3A + number_integer | -32768..-129 | Negative integer (2 bytes follow) | 0x39 + number_integer | -128..-25 | Negative integer (1 byte follow) | 0x38 + number_integer | -24..-1 | Negative integer | 0x20..0x37 + number_integer | 0..23 | Integer | 0x00..0x17 + number_integer | 24..255 | Unsigned integer (1 byte follow) | 0x18 + number_integer | 256..65535 | Unsigned integer (2 bytes follow) | 0x19 + number_integer | 65536..4294967295 | Unsigned integer (4 bytes follow) | 0x1A + number_integer | 4294967296..18446744073709551615 | Unsigned integer (8 bytes follow) | 0x1B + number_unsigned | 0..23 | Integer | 0x00..0x17 + number_unsigned | 24..255 | Unsigned integer (1 byte follow) | 0x18 + number_unsigned | 256..65535 | Unsigned integer (2 bytes follow) | 0x19 + number_unsigned | 65536..4294967295 | Unsigned integer (4 bytes follow) | 0x1A + number_unsigned | 4294967296..18446744073709551615 | Unsigned integer (8 bytes follow) | 0x1B + number_float | *any value representable by a float* | Single-Precision Float | 0xFA + number_float | *any value NOT representable by a float* | Double-Precision Float | 0xFB + string | *length*: 0..23 | UTF-8 string | 0x60..0x77 + string | *length*: 23..255 | UTF-8 string (1 byte follow) | 0x78 + string | *length*: 256..65535 | UTF-8 string (2 bytes follow) | 0x79 + string | *length*: 65536..4294967295 | UTF-8 string (4 bytes follow) | 0x7A + string | *length*: 4294967296..18446744073709551615 | UTF-8 string (8 bytes follow) | 0x7B + array | *size*: 0..23 | array | 0x80..0x97 + array | *size*: 23..255 | array (1 byte follow) | 0x98 + array | *size*: 256..65535 | array (2 bytes follow) | 0x99 + array | *size*: 65536..4294967295 | array (4 bytes follow) | 0x9A + array | *size*: 4294967296..18446744073709551615 | array (8 bytes follow) | 0x9B + object | *size*: 0..23 | map | 0xA0..0xB7 + object | *size*: 23..255 | map (1 byte follow) | 0xB8 + object | *size*: 256..65535 | map (2 bytes follow) | 0xB9 + object | *size*: 65536..4294967295 | map (4 bytes follow) | 0xBA + object | *size*: 4294967296..18446744073709551615 | map (8 bytes follow) | 0xBB + binary | *size*: 0..23 | byte string | 0x40..0x57 + binary | *size*: 23..255 | byte string (1 byte follow) | 0x58 + binary | *size*: 256..65535 | byte string (2 bytes follow) | 0x59 + binary | *size*: 65536..4294967295 | byte string (4 bytes follow) | 0x5A + binary | *size*: 4294967296..18446744073709551615 | byte string (8 bytes follow) | 0x5B + + Binary values with subtype are mapped to tagged values (0xD8..0xDB) + depending on the subtype, followed by a byte string, see "binary" cells + in the table above. + + @note The mapping is **complete** in the sense that any JSON value type + can be converted to a CBOR value. + + @note If NaN or Infinity are stored inside a JSON number, they are + serialized properly. This behavior differs from the @ref dump() + function which serializes NaN or Infinity to `null`. + + @note The following CBOR types are not used in the conversion: + - UTF-8 strings terminated by "break" (0x7F) + - arrays terminated by "break" (0x9F) + - maps terminated by "break" (0xBF) + - byte strings terminated by "break" (0x5F) + - date/time (0xC0..0xC1) + - bignum (0xC2..0xC3) + - decimal fraction (0xC4) + - bigfloat (0xC5) + - expected conversions (0xD5..0xD7) + - simple values (0xE0..0xF3, 0xF8) + - undefined (0xF7) + - half-precision floats (0xF9) + - break (0xFF) + + @param[in] j JSON value to serialize + @return CBOR serialization as byte vector + + @complexity Linear in the size of the JSON value @a j. + + @liveexample{The example shows the serialization of a JSON value to a byte + vector in CBOR format.,to_cbor} + + @sa http://cbor.io + @sa see @ref from_cbor(InputType&&, const bool, const bool, const cbor_tag_handler_t) for the + analogous deserialization + @sa see @ref to_msgpack(const basic_json&) for the related MessagePack format + @sa see @ref to_ubjson(const basic_json&, const bool, const bool) for the + related UBJSON format + + @since version 2.0.9; compact representation of floating-point numbers + since version 3.8.0 + */ + static std::vector to_cbor(const basic_json& j) + { + std::vector result; + to_cbor(j, result); + return result; + } + + static void to_cbor(const basic_json& j, detail::output_adapter o) + { + binary_writer(o).write_cbor(j); + } + + static void to_cbor(const basic_json& j, detail::output_adapter o) + { + binary_writer(o).write_cbor(j); + } + + /*! + @brief create a MessagePack serialization of a given JSON value + + Serializes a given JSON value @a j to a byte vector using the MessagePack + serialization format. MessagePack is a binary serialization format which + aims to be more compact than JSON itself, yet more efficient to parse. + + The library uses the following mapping from JSON values types to + MessagePack types according to the MessagePack specification: + + JSON value type | value/range | MessagePack type | first byte + --------------- | --------------------------------- | ---------------- | ---------- + null | `null` | nil | 0xC0 + boolean | `true` | true | 0xC3 + boolean | `false` | false | 0xC2 + number_integer | -9223372036854775808..-2147483649 | int64 | 0xD3 + number_integer | -2147483648..-32769 | int32 | 0xD2 + number_integer | -32768..-129 | int16 | 0xD1 + number_integer | -128..-33 | int8 | 0xD0 + number_integer | -32..-1 | negative fixint | 0xE0..0xFF + number_integer | 0..127 | positive fixint | 0x00..0x7F + number_integer | 128..255 | uint 8 | 0xCC + number_integer | 256..65535 | uint 16 | 0xCD + number_integer | 65536..4294967295 | uint 32 | 0xCE + number_integer | 4294967296..18446744073709551615 | uint 64 | 0xCF + number_unsigned | 0..127 | positive fixint | 0x00..0x7F + number_unsigned | 128..255 | uint 8 | 0xCC + number_unsigned | 256..65535 | uint 16 | 0xCD + number_unsigned | 65536..4294967295 | uint 32 | 0xCE + number_unsigned | 4294967296..18446744073709551615 | uint 64 | 0xCF + number_float | *any value representable by a float* | float 32 | 0xCA + number_float | *any value NOT representable by a float* | float 64 | 0xCB + string | *length*: 0..31 | fixstr | 0xA0..0xBF + string | *length*: 32..255 | str 8 | 0xD9 + string | *length*: 256..65535 | str 16 | 0xDA + string | *length*: 65536..4294967295 | str 32 | 0xDB + array | *size*: 0..15 | fixarray | 0x90..0x9F + array | *size*: 16..65535 | array 16 | 0xDC + array | *size*: 65536..4294967295 | array 32 | 0xDD + object | *size*: 0..15 | fix map | 0x80..0x8F + object | *size*: 16..65535 | map 16 | 0xDE + object | *size*: 65536..4294967295 | map 32 | 0xDF + binary | *size*: 0..255 | bin 8 | 0xC4 + binary | *size*: 256..65535 | bin 16 | 0xC5 + binary | *size*: 65536..4294967295 | bin 32 | 0xC6 + + @note The mapping is **complete** in the sense that any JSON value type + can be converted to a MessagePack value. + + @note The following values can **not** be converted to a MessagePack value: + - strings with more than 4294967295 bytes + - byte strings with more than 4294967295 bytes + - arrays with more than 4294967295 elements + - objects with more than 4294967295 elements + + @note Any MessagePack output created @ref to_msgpack can be successfully + parsed by @ref from_msgpack. + + @note If NaN or Infinity are stored inside a JSON number, they are + serialized properly. This behavior differs from the @ref dump() + function which serializes NaN or Infinity to `null`. + + @param[in] j JSON value to serialize + @return MessagePack serialization as byte vector + + @complexity Linear in the size of the JSON value @a j. + + @liveexample{The example shows the serialization of a JSON value to a byte + vector in MessagePack format.,to_msgpack} + + @sa http://msgpack.org + @sa see @ref from_msgpack for the analogous deserialization + @sa see @ref to_cbor(const basic_json& for the related CBOR format + @sa see @ref to_ubjson(const basic_json&, const bool, const bool) for the + related UBJSON format + + @since version 2.0.9 + */ + static std::vector to_msgpack(const basic_json& j) + { + std::vector result; + to_msgpack(j, result); + return result; + } + + static void to_msgpack(const basic_json& j, detail::output_adapter o) + { + binary_writer(o).write_msgpack(j); + } + + static void to_msgpack(const basic_json& j, detail::output_adapter o) + { + binary_writer(o).write_msgpack(j); + } + + /*! + @brief create a UBJSON serialization of a given JSON value + + Serializes a given JSON value @a j to a byte vector using the UBJSON + (Universal Binary JSON) serialization format. UBJSON aims to be more compact + than JSON itself, yet more efficient to parse. + + The library uses the following mapping from JSON values types to + UBJSON types according to the UBJSON specification: + + JSON value type | value/range | UBJSON type | marker + --------------- | --------------------------------- | ----------- | ------ + null | `null` | null | `Z` + boolean | `true` | true | `T` + boolean | `false` | false | `F` + number_integer | -9223372036854775808..-2147483649 | int64 | `L` + number_integer | -2147483648..-32769 | int32 | `l` + number_integer | -32768..-129 | int16 | `I` + number_integer | -128..127 | int8 | `i` + number_integer | 128..255 | uint8 | `U` + number_integer | 256..32767 | int16 | `I` + number_integer | 32768..2147483647 | int32 | `l` + number_integer | 2147483648..9223372036854775807 | int64 | `L` + number_unsigned | 0..127 | int8 | `i` + number_unsigned | 128..255 | uint8 | `U` + number_unsigned | 256..32767 | int16 | `I` + number_unsigned | 32768..2147483647 | int32 | `l` + number_unsigned | 2147483648..9223372036854775807 | int64 | `L` + number_unsigned | 2147483649..18446744073709551615 | high-precision | `H` + number_float | *any value* | float64 | `D` + string | *with shortest length indicator* | string | `S` + array | *see notes on optimized format* | array | `[` + object | *see notes on optimized format* | map | `{` + + @note The mapping is **complete** in the sense that any JSON value type + can be converted to a UBJSON value. + + @note The following values can **not** be converted to a UBJSON value: + - strings with more than 9223372036854775807 bytes (theoretical) + + @note The following markers are not used in the conversion: + - `Z`: no-op values are not created. + - `C`: single-byte strings are serialized with `S` markers. + + @note Any UBJSON output created @ref to_ubjson can be successfully parsed + by @ref from_ubjson. + + @note If NaN or Infinity are stored inside a JSON number, they are + serialized properly. This behavior differs from the @ref dump() + function which serializes NaN or Infinity to `null`. + + @note The optimized formats for containers are supported: Parameter + @a use_size adds size information to the beginning of a container and + removes the closing marker. Parameter @a use_type further checks + whether all elements of a container have the same type and adds the + type marker to the beginning of the container. The @a use_type + parameter must only be used together with @a use_size = true. Note + that @a use_size = true alone may result in larger representations - + the benefit of this parameter is that the receiving side is + immediately informed on the number of elements of the container. + + @note If the JSON data contains the binary type, the value stored is a list + of integers, as suggested by the UBJSON documentation. In particular, + this means that serialization and the deserialization of a JSON + containing binary values into UBJSON and back will result in a + different JSON object. + + @param[in] j JSON value to serialize + @param[in] use_size whether to add size annotations to container types + @param[in] use_type whether to add type annotations to container types + (must be combined with @a use_size = true) + @return UBJSON serialization as byte vector + + @complexity Linear in the size of the JSON value @a j. + + @liveexample{The example shows the serialization of a JSON value to a byte + vector in UBJSON format.,to_ubjson} + + @sa http://ubjson.org + @sa see @ref from_ubjson(InputType&&, const bool, const bool) for the + analogous deserialization + @sa see @ref to_cbor(const basic_json& for the related CBOR format + @sa see @ref to_msgpack(const basic_json&) for the related MessagePack format + + @since version 3.1.0 + */ + static std::vector to_ubjson(const basic_json& j, + const bool use_size = false, + const bool use_type = false) + { + std::vector result; + to_ubjson(j, result, use_size, use_type); + return result; + } + + static void to_ubjson(const basic_json& j, detail::output_adapter o, + const bool use_size = false, const bool use_type = false) + { + binary_writer(o).write_ubjson(j, use_size, use_type); + } + + static void to_ubjson(const basic_json& j, detail::output_adapter o, + const bool use_size = false, const bool use_type = false) + { + binary_writer(o).write_ubjson(j, use_size, use_type); + } + + + /*! + @brief Serializes the given JSON object `j` to BSON and returns a vector + containing the corresponding BSON-representation. + + BSON (Binary JSON) is a binary format in which zero or more ordered key/value pairs are + stored as a single entity (a so-called document). + + The library uses the following mapping from JSON values types to BSON types: + + JSON value type | value/range | BSON type | marker + --------------- | --------------------------------- | ----------- | ------ + null | `null` | null | 0x0A + boolean | `true`, `false` | boolean | 0x08 + number_integer | -9223372036854775808..-2147483649 | int64 | 0x12 + number_integer | -2147483648..2147483647 | int32 | 0x10 + number_integer | 2147483648..9223372036854775807 | int64 | 0x12 + number_unsigned | 0..2147483647 | int32 | 0x10 + number_unsigned | 2147483648..9223372036854775807 | int64 | 0x12 + number_unsigned | 9223372036854775808..18446744073709551615| -- | -- + number_float | *any value* | double | 0x01 + string | *any value* | string | 0x02 + array | *any value* | document | 0x04 + object | *any value* | document | 0x03 + binary | *any value* | binary | 0x05 + + @warning The mapping is **incomplete**, since only JSON-objects (and things + contained therein) can be serialized to BSON. + Also, integers larger than 9223372036854775807 cannot be serialized to BSON, + and the keys may not contain U+0000, since they are serialized a + zero-terminated c-strings. + + @throw out_of_range.407 if `j.is_number_unsigned() && j.get() > 9223372036854775807` + @throw out_of_range.409 if a key in `j` contains a NULL (U+0000) + @throw type_error.317 if `!j.is_object()` + + @pre The input `j` is required to be an object: `j.is_object() == true`. + + @note Any BSON output created via @ref to_bson can be successfully parsed + by @ref from_bson. + + @param[in] j JSON value to serialize + @return BSON serialization as byte vector + + @complexity Linear in the size of the JSON value @a j. + + @liveexample{The example shows the serialization of a JSON value to a byte + vector in BSON format.,to_bson} + + @sa http://bsonspec.org/spec.html + @sa see @ref from_bson(detail::input_adapter&&, const bool strict) for the + analogous deserialization + @sa see @ref to_ubjson(const basic_json&, const bool, const bool) for the + related UBJSON format + @sa see @ref to_cbor(const basic_json&) for the related CBOR format + @sa see @ref to_msgpack(const basic_json&) for the related MessagePack format + */ + static std::vector to_bson(const basic_json& j) + { + std::vector result; + to_bson(j, result); + return result; + } + + /*! + @brief Serializes the given JSON object `j` to BSON and forwards the + corresponding BSON-representation to the given output_adapter `o`. + @param j The JSON object to convert to BSON. + @param o The output adapter that receives the binary BSON representation. + @pre The input `j` shall be an object: `j.is_object() == true` + @sa see @ref to_bson(const basic_json&) + */ + static void to_bson(const basic_json& j, detail::output_adapter o) + { + binary_writer(o).write_bson(j); + } + + /*! + @copydoc to_bson(const basic_json&, detail::output_adapter) + */ + static void to_bson(const basic_json& j, detail::output_adapter o) + { + binary_writer(o).write_bson(j); + } + + + /*! + @brief create a JSON value from an input in CBOR format + + Deserializes a given input @a i to a JSON value using the CBOR (Concise + Binary Object Representation) serialization format. + + The library maps CBOR types to JSON value types as follows: + + CBOR type | JSON value type | first byte + ---------------------- | --------------- | ---------- + Integer | number_unsigned | 0x00..0x17 + Unsigned integer | number_unsigned | 0x18 + Unsigned integer | number_unsigned | 0x19 + Unsigned integer | number_unsigned | 0x1A + Unsigned integer | number_unsigned | 0x1B + Negative integer | number_integer | 0x20..0x37 + Negative integer | number_integer | 0x38 + Negative integer | number_integer | 0x39 + Negative integer | number_integer | 0x3A + Negative integer | number_integer | 0x3B + Byte string | binary | 0x40..0x57 + Byte string | binary | 0x58 + Byte string | binary | 0x59 + Byte string | binary | 0x5A + Byte string | binary | 0x5B + UTF-8 string | string | 0x60..0x77 + UTF-8 string | string | 0x78 + UTF-8 string | string | 0x79 + UTF-8 string | string | 0x7A + UTF-8 string | string | 0x7B + UTF-8 string | string | 0x7F + array | array | 0x80..0x97 + array | array | 0x98 + array | array | 0x99 + array | array | 0x9A + array | array | 0x9B + array | array | 0x9F + map | object | 0xA0..0xB7 + map | object | 0xB8 + map | object | 0xB9 + map | object | 0xBA + map | object | 0xBB + map | object | 0xBF + False | `false` | 0xF4 + True | `true` | 0xF5 + Null | `null` | 0xF6 + Half-Precision Float | number_float | 0xF9 + Single-Precision Float | number_float | 0xFA + Double-Precision Float | number_float | 0xFB + + @warning The mapping is **incomplete** in the sense that not all CBOR + types can be converted to a JSON value. The following CBOR types + are not supported and will yield parse errors (parse_error.112): + - date/time (0xC0..0xC1) + - bignum (0xC2..0xC3) + - decimal fraction (0xC4) + - bigfloat (0xC5) + - expected conversions (0xD5..0xD7) + - simple values (0xE0..0xF3, 0xF8) + - undefined (0xF7) + + @warning CBOR allows map keys of any type, whereas JSON only allows + strings as keys in object values. Therefore, CBOR maps with keys + other than UTF-8 strings are rejected (parse_error.113). + + @note Any CBOR output created @ref to_cbor can be successfully parsed by + @ref from_cbor. + + @param[in] i an input in CBOR format convertible to an input adapter + @param[in] strict whether to expect the input to be consumed until EOF + (true by default) + @param[in] allow_exceptions whether to throw exceptions in case of a + parse error (optional, true by default) + @param[in] tag_handler how to treat CBOR tags (optional, error by default) + + @return deserialized JSON value; in case of a parse error and + @a allow_exceptions set to `false`, the return value will be + value_t::discarded. + + @throw parse_error.110 if the given input ends prematurely or the end of + file was not reached when @a strict was set to true + @throw parse_error.112 if unsupported features from CBOR were + used in the given input @a v or if the input is not valid CBOR + @throw parse_error.113 if a string was expected as map key, but not found + + @complexity Linear in the size of the input @a i. + + @liveexample{The example shows the deserialization of a byte vector in CBOR + format to a JSON value.,from_cbor} + + @sa http://cbor.io + @sa see @ref to_cbor(const basic_json&) for the analogous serialization + @sa see @ref from_msgpack(InputType&&, const bool, const bool) for the + related MessagePack format + @sa see @ref from_ubjson(InputType&&, const bool, const bool) for the + related UBJSON format + + @since version 2.0.9; parameter @a start_index since 2.1.1; changed to + consume input adapters, removed start_index parameter, and added + @a strict parameter since 3.0.0; added @a allow_exceptions parameter + since 3.2.0; added @a tag_handler parameter since 3.9.0. + */ + template + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json from_cbor(InputType&& i, + const bool strict = true, + const bool allow_exceptions = true, + const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) + { + basic_json result; + detail::json_sax_dom_parser sdp(result, allow_exceptions); + auto ia = detail::input_adapter(std::forward(i)); + const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler); + return res ? result : basic_json(value_t::discarded); + } + + /*! + @copydoc from_cbor(InputType&&, const bool, const bool, const cbor_tag_handler_t) + */ + template + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json from_cbor(IteratorType first, IteratorType last, + const bool strict = true, + const bool allow_exceptions = true, + const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) + { + basic_json result; + detail::json_sax_dom_parser sdp(result, allow_exceptions); + auto ia = detail::input_adapter(std::move(first), std::move(last)); + const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler); + return res ? result : basic_json(value_t::discarded); + } + + template + JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len)) + static basic_json from_cbor(const T* ptr, std::size_t len, + const bool strict = true, + const bool allow_exceptions = true, + const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) + { + return from_cbor(ptr, ptr + len, strict, allow_exceptions, tag_handler); + } + + + JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len)) + static basic_json from_cbor(detail::span_input_adapter&& i, + const bool strict = true, + const bool allow_exceptions = true, + const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error) + { + basic_json result; + detail::json_sax_dom_parser sdp(result, allow_exceptions); + auto ia = i.get(); + // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) + const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler); + return res ? result : basic_json(value_t::discarded); + } + + /*! + @brief create a JSON value from an input in MessagePack format + + Deserializes a given input @a i to a JSON value using the MessagePack + serialization format. + + The library maps MessagePack types to JSON value types as follows: + + MessagePack type | JSON value type | first byte + ---------------- | --------------- | ---------- + positive fixint | number_unsigned | 0x00..0x7F + fixmap | object | 0x80..0x8F + fixarray | array | 0x90..0x9F + fixstr | string | 0xA0..0xBF + nil | `null` | 0xC0 + false | `false` | 0xC2 + true | `true` | 0xC3 + float 32 | number_float | 0xCA + float 64 | number_float | 0xCB + uint 8 | number_unsigned | 0xCC + uint 16 | number_unsigned | 0xCD + uint 32 | number_unsigned | 0xCE + uint 64 | number_unsigned | 0xCF + int 8 | number_integer | 0xD0 + int 16 | number_integer | 0xD1 + int 32 | number_integer | 0xD2 + int 64 | number_integer | 0xD3 + str 8 | string | 0xD9 + str 16 | string | 0xDA + str 32 | string | 0xDB + array 16 | array | 0xDC + array 32 | array | 0xDD + map 16 | object | 0xDE + map 32 | object | 0xDF + bin 8 | binary | 0xC4 + bin 16 | binary | 0xC5 + bin 32 | binary | 0xC6 + ext 8 | binary | 0xC7 + ext 16 | binary | 0xC8 + ext 32 | binary | 0xC9 + fixext 1 | binary | 0xD4 + fixext 2 | binary | 0xD5 + fixext 4 | binary | 0xD6 + fixext 8 | binary | 0xD7 + fixext 16 | binary | 0xD8 + negative fixint | number_integer | 0xE0-0xFF + + @note Any MessagePack output created @ref to_msgpack can be successfully + parsed by @ref from_msgpack. + + @param[in] i an input in MessagePack format convertible to an input + adapter + @param[in] strict whether to expect the input to be consumed until EOF + (true by default) + @param[in] allow_exceptions whether to throw exceptions in case of a + parse error (optional, true by default) + + @return deserialized JSON value; in case of a parse error and + @a allow_exceptions set to `false`, the return value will be + value_t::discarded. + + @throw parse_error.110 if the given input ends prematurely or the end of + file was not reached when @a strict was set to true + @throw parse_error.112 if unsupported features from MessagePack were + used in the given input @a i or if the input is not valid MessagePack + @throw parse_error.113 if a string was expected as map key, but not found + + @complexity Linear in the size of the input @a i. + + @liveexample{The example shows the deserialization of a byte vector in + MessagePack format to a JSON value.,from_msgpack} + + @sa http://msgpack.org + @sa see @ref to_msgpack(const basic_json&) for the analogous serialization + @sa see @ref from_cbor(InputType&&, const bool, const bool, const cbor_tag_handler_t) for the + related CBOR format + @sa see @ref from_ubjson(InputType&&, const bool, const bool) for + the related UBJSON format + @sa see @ref from_bson(InputType&&, const bool, const bool) for + the related BSON format + + @since version 2.0.9; parameter @a start_index since 2.1.1; changed to + consume input adapters, removed start_index parameter, and added + @a strict parameter since 3.0.0; added @a allow_exceptions parameter + since 3.2.0 + */ + template + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json from_msgpack(InputType&& i, + const bool strict = true, + const bool allow_exceptions = true) + { + basic_json result; + detail::json_sax_dom_parser sdp(result, allow_exceptions); + auto ia = detail::input_adapter(std::forward(i)); + const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::msgpack, &sdp, strict); + return res ? result : basic_json(value_t::discarded); + } + + /*! + @copydoc from_msgpack(InputType&&, const bool, const bool) + */ + template + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json from_msgpack(IteratorType first, IteratorType last, + const bool strict = true, + const bool allow_exceptions = true) + { + basic_json result; + detail::json_sax_dom_parser sdp(result, allow_exceptions); + auto ia = detail::input_adapter(std::move(first), std::move(last)); + const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::msgpack, &sdp, strict); + return res ? result : basic_json(value_t::discarded); + } + + + template + JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len)) + static basic_json from_msgpack(const T* ptr, std::size_t len, + const bool strict = true, + const bool allow_exceptions = true) + { + return from_msgpack(ptr, ptr + len, strict, allow_exceptions); + } + + JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len)) + static basic_json from_msgpack(detail::span_input_adapter&& i, + const bool strict = true, + const bool allow_exceptions = true) + { + basic_json result; + detail::json_sax_dom_parser sdp(result, allow_exceptions); + auto ia = i.get(); + // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) + const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::msgpack, &sdp, strict); + return res ? result : basic_json(value_t::discarded); + } + + + /*! + @brief create a JSON value from an input in UBJSON format + + Deserializes a given input @a i to a JSON value using the UBJSON (Universal + Binary JSON) serialization format. + + The library maps UBJSON types to JSON value types as follows: + + UBJSON type | JSON value type | marker + ----------- | --------------------------------------- | ------ + no-op | *no value, next value is read* | `N` + null | `null` | `Z` + false | `false` | `F` + true | `true` | `T` + float32 | number_float | `d` + float64 | number_float | `D` + uint8 | number_unsigned | `U` + int8 | number_integer | `i` + int16 | number_integer | `I` + int32 | number_integer | `l` + int64 | number_integer | `L` + high-precision number | number_integer, number_unsigned, or number_float - depends on number string | 'H' + string | string | `S` + char | string | `C` + array | array (optimized values are supported) | `[` + object | object (optimized values are supported) | `{` + + @note The mapping is **complete** in the sense that any UBJSON value can + be converted to a JSON value. + + @param[in] i an input in UBJSON format convertible to an input adapter + @param[in] strict whether to expect the input to be consumed until EOF + (true by default) + @param[in] allow_exceptions whether to throw exceptions in case of a + parse error (optional, true by default) + + @return deserialized JSON value; in case of a parse error and + @a allow_exceptions set to `false`, the return value will be + value_t::discarded. + + @throw parse_error.110 if the given input ends prematurely or the end of + file was not reached when @a strict was set to true + @throw parse_error.112 if a parse error occurs + @throw parse_error.113 if a string could not be parsed successfully + + @complexity Linear in the size of the input @a i. + + @liveexample{The example shows the deserialization of a byte vector in + UBJSON format to a JSON value.,from_ubjson} + + @sa http://ubjson.org + @sa see @ref to_ubjson(const basic_json&, const bool, const bool) for the + analogous serialization + @sa see @ref from_cbor(InputType&&, const bool, const bool, const cbor_tag_handler_t) for the + related CBOR format + @sa see @ref from_msgpack(InputType&&, const bool, const bool) for + the related MessagePack format + @sa see @ref from_bson(InputType&&, const bool, const bool) for + the related BSON format + + @since version 3.1.0; added @a allow_exceptions parameter since 3.2.0 + */ + template + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json from_ubjson(InputType&& i, + const bool strict = true, + const bool allow_exceptions = true) + { + basic_json result; + detail::json_sax_dom_parser sdp(result, allow_exceptions); + auto ia = detail::input_adapter(std::forward(i)); + const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::ubjson, &sdp, strict); + return res ? result : basic_json(value_t::discarded); + } + + /*! + @copydoc from_ubjson(InputType&&, const bool, const bool) + */ + template + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json from_ubjson(IteratorType first, IteratorType last, + const bool strict = true, + const bool allow_exceptions = true) + { + basic_json result; + detail::json_sax_dom_parser sdp(result, allow_exceptions); + auto ia = detail::input_adapter(std::move(first), std::move(last)); + const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::ubjson, &sdp, strict); + return res ? result : basic_json(value_t::discarded); + } + + template + JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len)) + static basic_json from_ubjson(const T* ptr, std::size_t len, + const bool strict = true, + const bool allow_exceptions = true) + { + return from_ubjson(ptr, ptr + len, strict, allow_exceptions); + } + + JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len)) + static basic_json from_ubjson(detail::span_input_adapter&& i, + const bool strict = true, + const bool allow_exceptions = true) + { + basic_json result; + detail::json_sax_dom_parser sdp(result, allow_exceptions); + auto ia = i.get(); + // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) + const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::ubjson, &sdp, strict); + return res ? result : basic_json(value_t::discarded); + } + + + /*! + @brief Create a JSON value from an input in BSON format + + Deserializes a given input @a i to a JSON value using the BSON (Binary JSON) + serialization format. + + The library maps BSON record types to JSON value types as follows: + + BSON type | BSON marker byte | JSON value type + --------------- | ---------------- | --------------------------- + double | 0x01 | number_float + string | 0x02 | string + document | 0x03 | object + array | 0x04 | array + binary | 0x05 | binary + undefined | 0x06 | still unsupported + ObjectId | 0x07 | still unsupported + boolean | 0x08 | boolean + UTC Date-Time | 0x09 | still unsupported + null | 0x0A | null + Regular Expr. | 0x0B | still unsupported + DB Pointer | 0x0C | still unsupported + JavaScript Code | 0x0D | still unsupported + Symbol | 0x0E | still unsupported + JavaScript Code | 0x0F | still unsupported + int32 | 0x10 | number_integer + Timestamp | 0x11 | still unsupported + 128-bit decimal float | 0x13 | still unsupported + Max Key | 0x7F | still unsupported + Min Key | 0xFF | still unsupported + + @warning The mapping is **incomplete**. The unsupported mappings + are indicated in the table above. + + @param[in] i an input in BSON format convertible to an input adapter + @param[in] strict whether to expect the input to be consumed until EOF + (true by default) + @param[in] allow_exceptions whether to throw exceptions in case of a + parse error (optional, true by default) + + @return deserialized JSON value; in case of a parse error and + @a allow_exceptions set to `false`, the return value will be + value_t::discarded. + + @throw parse_error.114 if an unsupported BSON record type is encountered + + @complexity Linear in the size of the input @a i. + + @liveexample{The example shows the deserialization of a byte vector in + BSON format to a JSON value.,from_bson} + + @sa http://bsonspec.org/spec.html + @sa see @ref to_bson(const basic_json&) for the analogous serialization + @sa see @ref from_cbor(InputType&&, const bool, const bool, const cbor_tag_handler_t) for the + related CBOR format + @sa see @ref from_msgpack(InputType&&, const bool, const bool) for + the related MessagePack format + @sa see @ref from_ubjson(InputType&&, const bool, const bool) for the + related UBJSON format + */ + template + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json from_bson(InputType&& i, + const bool strict = true, + const bool allow_exceptions = true) + { + basic_json result; + detail::json_sax_dom_parser sdp(result, allow_exceptions); + auto ia = detail::input_adapter(std::forward(i)); + const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::bson, &sdp, strict); + return res ? result : basic_json(value_t::discarded); + } + + /*! + @copydoc from_bson(InputType&&, const bool, const bool) + */ + template + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json from_bson(IteratorType first, IteratorType last, + const bool strict = true, + const bool allow_exceptions = true) + { + basic_json result; + detail::json_sax_dom_parser sdp(result, allow_exceptions); + auto ia = detail::input_adapter(std::move(first), std::move(last)); + const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::bson, &sdp, strict); + return res ? result : basic_json(value_t::discarded); + } + + template + JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len)) + static basic_json from_bson(const T* ptr, std::size_t len, + const bool strict = true, + const bool allow_exceptions = true) + { + return from_bson(ptr, ptr + len, strict, allow_exceptions); + } + + JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len)) + static basic_json from_bson(detail::span_input_adapter&& i, + const bool strict = true, + const bool allow_exceptions = true) + { + basic_json result; + detail::json_sax_dom_parser sdp(result, allow_exceptions); + auto ia = i.get(); + // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg) + const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::bson, &sdp, strict); + return res ? result : basic_json(value_t::discarded); + } + /// @} + + ////////////////////////// + // JSON Pointer support // + ////////////////////////// + + /// @name JSON Pointer functions + /// @{ + + /*! + @brief access specified element via JSON Pointer + + Uses a JSON pointer to retrieve a reference to the respective JSON value. + No bound checking is performed. Similar to @ref operator[](const typename + object_t::key_type&), `null` values are created in arrays and objects if + necessary. + + In particular: + - If the JSON pointer points to an object key that does not exist, it + is created an filled with a `null` value before a reference to it + is returned. + - If the JSON pointer points to an array index that does not exist, it + is created an filled with a `null` value before a reference to it + is returned. All indices between the current maximum and the given + index are also filled with `null`. + - The special value `-` is treated as a synonym for the index past the + end. + + @param[in] ptr a JSON pointer + + @return reference to the element pointed to by @a ptr + + @complexity Constant. + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.404 if the JSON pointer can not be resolved + + @liveexample{The behavior is shown in the example.,operatorjson_pointer} + + @since version 2.0.0 + */ + reference operator[](const json_pointer& ptr) + { + return ptr.get_unchecked(this); + } + + /*! + @brief access specified element via JSON Pointer + + Uses a JSON pointer to retrieve a reference to the respective JSON value. + No bound checking is performed. The function does not change the JSON + value; no `null` values are created. In particular, the special value + `-` yields an exception. + + @param[in] ptr JSON pointer to the desired element + + @return const reference to the element pointed to by @a ptr + + @complexity Constant. + + @throw parse_error.106 if an array index begins with '0' + @throw parse_error.109 if an array index was not a number + @throw out_of_range.402 if the array index '-' is used + @throw out_of_range.404 if the JSON pointer can not be resolved + + @liveexample{The behavior is shown in the example.,operatorjson_pointer_const} + + @since version 2.0.0 + */ + const_reference operator[](const json_pointer& ptr) const + { + return ptr.get_unchecked(this); + } + + /*! + @brief access specified element via JSON Pointer + + Returns a reference to the element at with specified JSON pointer @a ptr, + with bounds checking. + + @param[in] ptr JSON pointer to the desired element + + @return reference to the element pointed to by @a ptr + + @throw parse_error.106 if an array index in the passed JSON pointer @a ptr + begins with '0'. See example below. + + @throw parse_error.109 if an array index in the passed JSON pointer @a ptr + is not a number. See example below. + + @throw out_of_range.401 if an array index in the passed JSON pointer @a ptr + is out of range. See example below. + + @throw out_of_range.402 if the array index '-' is used in the passed JSON + pointer @a ptr. As `at` provides checked access (and no elements are + implicitly inserted), the index '-' is always invalid. See example below. + + @throw out_of_range.403 if the JSON pointer describes a key of an object + which cannot be found. See example below. + + @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved. + See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + + @since version 2.0.0 + + @liveexample{The behavior is shown in the example.,at_json_pointer} + */ + reference at(const json_pointer& ptr) + { + return ptr.get_checked(this); + } + + /*! + @brief access specified element via JSON Pointer + + Returns a const reference to the element at with specified JSON pointer @a + ptr, with bounds checking. + + @param[in] ptr JSON pointer to the desired element + + @return reference to the element pointed to by @a ptr + + @throw parse_error.106 if an array index in the passed JSON pointer @a ptr + begins with '0'. See example below. + + @throw parse_error.109 if an array index in the passed JSON pointer @a ptr + is not a number. See example below. + + @throw out_of_range.401 if an array index in the passed JSON pointer @a ptr + is out of range. See example below. + + @throw out_of_range.402 if the array index '-' is used in the passed JSON + pointer @a ptr. As `at` provides checked access (and no elements are + implicitly inserted), the index '-' is always invalid. See example below. + + @throw out_of_range.403 if the JSON pointer describes a key of an object + which cannot be found. See example below. + + @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved. + See example below. + + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @complexity Constant. + + @since version 2.0.0 + + @liveexample{The behavior is shown in the example.,at_json_pointer_const} + */ + const_reference at(const json_pointer& ptr) const + { + return ptr.get_checked(this); + } + + /*! + @brief return flattened JSON value + + The function creates a JSON object whose keys are JSON pointers (see [RFC + 6901](https://tools.ietf.org/html/rfc6901)) and whose values are all + primitive. The original JSON value can be restored using the @ref + unflatten() function. + + @return an object that maps JSON pointers to primitive values + + @note Empty objects and arrays are flattened to `null` and will not be + reconstructed correctly by the @ref unflatten() function. + + @complexity Linear in the size the JSON value. + + @liveexample{The following code shows how a JSON object is flattened to an + object whose keys consist of JSON pointers.,flatten} + + @sa see @ref unflatten() for the reverse function + + @since version 2.0.0 + */ + basic_json flatten() const + { + basic_json result(value_t::object); + json_pointer::flatten("", *this, result); + return result; + } + + /*! + @brief unflatten a previously flattened JSON value + + The function restores the arbitrary nesting of a JSON value that has been + flattened before using the @ref flatten() function. The JSON value must + meet certain constraints: + 1. The value must be an object. + 2. The keys must be JSON pointers (see + [RFC 6901](https://tools.ietf.org/html/rfc6901)) + 3. The mapped values must be primitive JSON types. + + @return the original JSON from a flattened version + + @note Empty objects and arrays are flattened by @ref flatten() to `null` + values and can not unflattened to their original type. Apart from + this example, for a JSON value `j`, the following is always true: + `j == j.flatten().unflatten()`. + + @complexity Linear in the size the JSON value. + + @throw type_error.314 if value is not an object + @throw type_error.315 if object values are not primitive + + @liveexample{The following code shows how a flattened JSON object is + unflattened into the original nested JSON object.,unflatten} + + @sa see @ref flatten() for the reverse function + + @since version 2.0.0 + */ + basic_json unflatten() const + { + return json_pointer::unflatten(*this); + } + + /// @} + + ////////////////////////// + // JSON Patch functions // + ////////////////////////// + + /// @name JSON Patch functions + /// @{ + + /*! + @brief applies a JSON patch + + [JSON Patch](http://jsonpatch.com) defines a JSON document structure for + expressing a sequence of operations to apply to a JSON) document. With + this function, a JSON Patch is applied to the current JSON value by + executing all operations from the patch. + + @param[in] json_patch JSON patch document + @return patched document + + @note The application of a patch is atomic: Either all operations succeed + and the patched document is returned or an exception is thrown. In + any case, the original value is not changed: the patch is applied + to a copy of the value. + + @throw parse_error.104 if the JSON patch does not consist of an array of + objects + + @throw parse_error.105 if the JSON patch is malformed (e.g., mandatory + attributes are missing); example: `"operation add must have member path"` + + @throw out_of_range.401 if an array index is out of range. + + @throw out_of_range.403 if a JSON pointer inside the patch could not be + resolved successfully in the current JSON value; example: `"key baz not + found"` + + @throw out_of_range.405 if JSON pointer has no parent ("add", "remove", + "move") + + @throw other_error.501 if "test" operation was unsuccessful + + @complexity Linear in the size of the JSON value and the length of the + JSON patch. As usually only a fraction of the JSON value is affected by + the patch, the complexity can usually be neglected. + + @liveexample{The following code shows how a JSON patch is applied to a + value.,patch} + + @sa see @ref diff -- create a JSON patch by comparing two JSON values + + @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902) + @sa [RFC 6901 (JSON Pointer)](https://tools.ietf.org/html/rfc6901) + + @since version 2.0.0 + */ + basic_json patch(const basic_json& json_patch) const + { + // make a working copy to apply the patch to + basic_json result = *this; + + // the valid JSON Patch operations + enum class patch_operations {add, remove, replace, move, copy, test, invalid}; + + const auto get_op = [](const std::string & op) + { + if (op == "add") + { + return patch_operations::add; + } + if (op == "remove") + { + return patch_operations::remove; + } + if (op == "replace") + { + return patch_operations::replace; + } + if (op == "move") + { + return patch_operations::move; + } + if (op == "copy") + { + return patch_operations::copy; + } + if (op == "test") + { + return patch_operations::test; + } + + return patch_operations::invalid; + }; + + // wrapper for "add" operation; add value at ptr + const auto operation_add = [&result](json_pointer & ptr, basic_json val) + { + // adding to the root of the target document means replacing it + if (ptr.empty()) + { + result = val; + return; + } + + // make sure the top element of the pointer exists + json_pointer top_pointer = ptr.top(); + if (top_pointer != ptr) + { + result.at(top_pointer); + } + + // get reference to parent of JSON pointer ptr + const auto last_path = ptr.back(); + ptr.pop_back(); + basic_json& parent = result[ptr]; + + switch (parent.m_type) + { + case value_t::null: + case value_t::object: + { + // use operator[] to add value + parent[last_path] = val; + break; + } + + case value_t::array: + { + if (last_path == "-") + { + // special case: append to back + parent.push_back(val); + } + else + { + const auto idx = json_pointer::array_index(last_path); + if (JSON_HEDLEY_UNLIKELY(idx > parent.size())) + { + // avoid undefined behavior + JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range", parent)); + } + + // default case: insert add offset + parent.insert(parent.begin() + static_cast(idx), val); + } + break; + } + + // if there exists a parent it cannot be primitive + case value_t::string: // LCOV_EXCL_LINE + case value_t::boolean: // LCOV_EXCL_LINE + case value_t::number_integer: // LCOV_EXCL_LINE + case value_t::number_unsigned: // LCOV_EXCL_LINE + case value_t::number_float: // LCOV_EXCL_LINE + case value_t::binary: // LCOV_EXCL_LINE + case value_t::discarded: // LCOV_EXCL_LINE + default: // LCOV_EXCL_LINE + JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE + } + }; + + // wrapper for "remove" operation; remove value at ptr + const auto operation_remove = [this, &result](json_pointer & ptr) + { + // get reference to parent of JSON pointer ptr + const auto last_path = ptr.back(); + ptr.pop_back(); + basic_json& parent = result.at(ptr); + + // remove child + if (parent.is_object()) + { + // perform range check + auto it = parent.find(last_path); + if (JSON_HEDLEY_LIKELY(it != parent.end())) + { + parent.erase(it); + } + else + { + JSON_THROW(out_of_range::create(403, "key '" + last_path + "' not found", *this)); + } + } + else if (parent.is_array()) + { + // note erase performs range check + parent.erase(json_pointer::array_index(last_path)); + } + }; + + // type check: top level value must be an array + if (JSON_HEDLEY_UNLIKELY(!json_patch.is_array())) + { + JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects", json_patch)); + } + + // iterate and apply the operations + for (const auto& val : json_patch) + { + // wrapper to get a value for an operation + const auto get_value = [&val](const std::string & op, + const std::string & member, + bool string_type) -> basic_json & + { + // find value + auto it = val.m_value.object->find(member); + + // context-sensitive error message + const auto error_msg = (op == "op") ? "operation" : "operation '" + op + "'"; + + // check if desired value is present + if (JSON_HEDLEY_UNLIKELY(it == val.m_value.object->end())) + { + // NOLINTNEXTLINE(performance-inefficient-string-concatenation) + JSON_THROW(parse_error::create(105, 0, error_msg + " must have member '" + member + "'", val)); + } + + // check if result is of type string + if (JSON_HEDLEY_UNLIKELY(string_type && !it->second.is_string())) + { + // NOLINTNEXTLINE(performance-inefficient-string-concatenation) + JSON_THROW(parse_error::create(105, 0, error_msg + " must have string member '" + member + "'", val)); + } + + // no error: return value + return it->second; + }; + + // type check: every element of the array must be an object + if (JSON_HEDLEY_UNLIKELY(!val.is_object())) + { + JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects", val)); + } + + // collect mandatory members + const auto op = get_value("op", "op", true).template get(); + const auto path = get_value(op, "path", true).template get(); + json_pointer ptr(path); + + switch (get_op(op)) + { + case patch_operations::add: + { + operation_add(ptr, get_value("add", "value", false)); + break; + } + + case patch_operations::remove: + { + operation_remove(ptr); + break; + } + + case patch_operations::replace: + { + // the "path" location must exist - use at() + result.at(ptr) = get_value("replace", "value", false); + break; + } + + case patch_operations::move: + { + const auto from_path = get_value("move", "from", true).template get(); + json_pointer from_ptr(from_path); + + // the "from" location must exist - use at() + basic_json v = result.at(from_ptr); + + // The move operation is functionally identical to a + // "remove" operation on the "from" location, followed + // immediately by an "add" operation at the target + // location with the value that was just removed. + operation_remove(from_ptr); + operation_add(ptr, v); + break; + } + + case patch_operations::copy: + { + const auto from_path = get_value("copy", "from", true).template get(); + const json_pointer from_ptr(from_path); + + // the "from" location must exist - use at() + basic_json v = result.at(from_ptr); + + // The copy is functionally identical to an "add" + // operation at the target location using the value + // specified in the "from" member. + operation_add(ptr, v); + break; + } + + case patch_operations::test: + { + bool success = false; + JSON_TRY + { + // check if "value" matches the one at "path" + // the "path" location must exist - use at() + success = (result.at(ptr) == get_value("test", "value", false)); + } + JSON_INTERNAL_CATCH (out_of_range&) + { + // ignore out of range errors: success remains false + } + + // throw an exception if test fails + if (JSON_HEDLEY_UNLIKELY(!success)) + { + JSON_THROW(other_error::create(501, "unsuccessful: " + val.dump(), val)); + } + + break; + } + + case patch_operations::invalid: + default: + { + // op must be "add", "remove", "replace", "move", "copy", or + // "test" + JSON_THROW(parse_error::create(105, 0, "operation value '" + op + "' is invalid", val)); + } + } + } + + return result; + } + + /*! + @brief creates a diff as a JSON patch + + Creates a [JSON Patch](http://jsonpatch.com) so that value @a source can + be changed into the value @a target by calling @ref patch function. + + @invariant For two JSON values @a source and @a target, the following code + yields always `true`: + @code {.cpp} + source.patch(diff(source, target)) == target; + @endcode + + @note Currently, only `remove`, `add`, and `replace` operations are + generated. + + @param[in] source JSON value to compare from + @param[in] target JSON value to compare against + @param[in] path helper value to create JSON pointers + + @return a JSON patch to convert the @a source to @a target + + @complexity Linear in the lengths of @a source and @a target. + + @liveexample{The following code shows how a JSON patch is created as a + diff for two JSON values.,diff} + + @sa see @ref patch -- apply a JSON patch + @sa see @ref merge_patch -- apply a JSON Merge Patch + + @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902) + + @since version 2.0.0 + */ + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json diff(const basic_json& source, const basic_json& target, + const std::string& path = "") + { + // the patch + basic_json result(value_t::array); + + // if the values are the same, return empty patch + if (source == target) + { + return result; + } + + if (source.type() != target.type()) + { + // different types: replace value + result.push_back( + { + {"op", "replace"}, {"path", path}, {"value", target} + }); + return result; + } + + switch (source.type()) + { + case value_t::array: + { + // first pass: traverse common elements + std::size_t i = 0; + while (i < source.size() && i < target.size()) + { + // recursive call to compare array values at index i + auto temp_diff = diff(source[i], target[i], path + "/" + std::to_string(i)); + result.insert(result.end(), temp_diff.begin(), temp_diff.end()); + ++i; + } + + // i now reached the end of at least one array + // in a second pass, traverse the remaining elements + + // remove my remaining elements + const auto end_index = static_cast(result.size()); + while (i < source.size()) + { + // add operations in reverse order to avoid invalid + // indices + result.insert(result.begin() + end_index, object( + { + {"op", "remove"}, + {"path", path + "/" + std::to_string(i)} + })); + ++i; + } + + // add other remaining elements + while (i < target.size()) + { + result.push_back( + { + {"op", "add"}, + {"path", path + "/-"}, + {"value", target[i]} + }); + ++i; + } + + break; + } + + case value_t::object: + { + // first pass: traverse this object's elements + for (auto it = source.cbegin(); it != source.cend(); ++it) + { + // escape the key name to be used in a JSON patch + const auto path_key = path + "/" + detail::escape(it.key()); + + if (target.find(it.key()) != target.end()) + { + // recursive call to compare object values at key it + auto temp_diff = diff(it.value(), target[it.key()], path_key); + result.insert(result.end(), temp_diff.begin(), temp_diff.end()); + } + else + { + // found a key that is not in o -> remove it + result.push_back(object( + { + {"op", "remove"}, {"path", path_key} + })); + } + } + + // second pass: traverse other object's elements + for (auto it = target.cbegin(); it != target.cend(); ++it) + { + if (source.find(it.key()) == source.end()) + { + // found a key that is not in this -> add it + const auto path_key = path + "/" + detail::escape(it.key()); + result.push_back( + { + {"op", "add"}, {"path", path_key}, + {"value", it.value()} + }); + } + } + + break; + } + + case value_t::null: + case value_t::string: + case value_t::boolean: + case value_t::number_integer: + case value_t::number_unsigned: + case value_t::number_float: + case value_t::binary: + case value_t::discarded: + default: + { + // both primitive type: replace value + result.push_back( + { + {"op", "replace"}, {"path", path}, {"value", target} + }); + break; + } + } + + return result; + } + + /// @} + + //////////////////////////////// + // JSON Merge Patch functions // + //////////////////////////////// + + /// @name JSON Merge Patch functions + /// @{ + + /*! + @brief applies a JSON Merge Patch + + The merge patch format is primarily intended for use with the HTTP PATCH + method as a means of describing a set of modifications to a target + resource's content. This function applies a merge patch to the current + JSON value. + + The function implements the following algorithm from Section 2 of + [RFC 7396 (JSON Merge Patch)](https://tools.ietf.org/html/rfc7396): + + ``` + define MergePatch(Target, Patch): + if Patch is an Object: + if Target is not an Object: + Target = {} // Ignore the contents and set it to an empty Object + for each Name/Value pair in Patch: + if Value is null: + if Name exists in Target: + remove the Name/Value pair from Target + else: + Target[Name] = MergePatch(Target[Name], Value) + return Target + else: + return Patch + ``` + + Thereby, `Target` is the current object; that is, the patch is applied to + the current value. + + @param[in] apply_patch the patch to apply + + @complexity Linear in the lengths of @a patch. + + @liveexample{The following code shows how a JSON Merge Patch is applied to + a JSON document.,merge_patch} + + @sa see @ref patch -- apply a JSON patch + @sa [RFC 7396 (JSON Merge Patch)](https://tools.ietf.org/html/rfc7396) + + @since version 3.0.0 + */ + void merge_patch(const basic_json& apply_patch) + { + if (apply_patch.is_object()) + { + if (!is_object()) + { + *this = object(); + } + for (auto it = apply_patch.begin(); it != apply_patch.end(); ++it) + { + if (it.value().is_null()) + { + erase(it.key()); + } + else + { + operator[](it.key()).merge_patch(it.value()); + } + } + } + else + { + *this = apply_patch; + } + } + + /// @} +}; + +/*! +@brief user-defined to_string function for JSON values + +This function implements a user-defined to_string for JSON objects. + +@param[in] j a JSON object +@return a std::string object +*/ + +NLOHMANN_BASIC_JSON_TPL_DECLARATION +std::string to_string(const NLOHMANN_BASIC_JSON_TPL& j) +{ + return j.dump(); +} +} // namespace nlohmann + +/////////////////////// +// nonmember support // +/////////////////////// + +// specialization of std::swap, and std::hash +namespace std +{ + +/// hash value for JSON objects +template<> +struct hash +{ + /*! + @brief return a hash value for a JSON object + + @since version 1.0.0 + */ + std::size_t operator()(const nlohmann::json& j) const + { + return nlohmann::detail::hash(j); + } +}; + +/// specialization for std::less +/// @note: do not remove the space after '<', +/// see https://github.com/nlohmann/json/pull/679 +template<> +struct less<::nlohmann::detail::value_t> +{ + /*! + @brief compare two value_t enum values + @since version 3.0.0 + */ + bool operator()(nlohmann::detail::value_t lhs, + nlohmann::detail::value_t rhs) const noexcept + { + return nlohmann::detail::operator<(lhs, rhs); + } +}; + +// C++20 prohibit function specialization in the std namespace. +#ifndef JSON_HAS_CPP_20 + +/*! +@brief exchanges the values of two JSON objects + +@since version 1.0.0 +*/ +template<> +inline void swap(nlohmann::json& j1, nlohmann::json& j2) noexcept( // NOLINT(readability-inconsistent-declaration-parameter-name) + is_nothrow_move_constructible::value&& // NOLINT(misc-redundant-expression) + is_nothrow_move_assignable::value + ) +{ + j1.swap(j2); +} + +#endif + +} // namespace std + +/*! +@brief user-defined string literal for JSON values + +This operator implements a user-defined string literal for JSON objects. It +can be used by adding `"_json"` to a string literal and returns a JSON object +if no parse error occurred. + +@param[in] s a string representation of a JSON object +@param[in] n the length of string @a s +@return a JSON object + +@since version 1.0.0 +*/ +JSON_HEDLEY_NON_NULL(1) +inline nlohmann::json operator "" _json(const char* s, std::size_t n) +{ + return nlohmann::json::parse(s, s + n); +} + +/*! +@brief user-defined string literal for JSON pointer + +This operator implements a user-defined string literal for JSON Pointers. It +can be used by adding `"_json_pointer"` to a string literal and returns a JSON pointer +object if no parse error occurred. + +@param[in] s a string representation of a JSON Pointer +@param[in] n the length of string @a s +@return a JSON pointer object + +@since version 2.0.0 +*/ +JSON_HEDLEY_NON_NULL(1) +inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std::size_t n) +{ + return nlohmann::json::json_pointer(std::string(s, n)); +} + +// #include + + +// restore clang diagnostic settings +#if defined(__clang__) + #pragma clang diagnostic pop +#endif + +// clean up +#undef JSON_ASSERT +#undef JSON_INTERNAL_CATCH +#undef JSON_CATCH +#undef JSON_THROW +#undef JSON_TRY +#undef JSON_PRIVATE_UNLESS_TESTED +#undef JSON_HAS_CPP_11 +#undef JSON_HAS_CPP_14 +#undef JSON_HAS_CPP_17 +#undef JSON_HAS_CPP_20 +#undef NLOHMANN_BASIC_JSON_TPL_DECLARATION +#undef NLOHMANN_BASIC_JSON_TPL +#undef JSON_EXPLICIT +#undef NLOHMANN_CAN_CALL_STD_FUNC_IMPL + +// #include + + +#undef JSON_HEDLEY_ALWAYS_INLINE +#undef JSON_HEDLEY_ARM_VERSION +#undef JSON_HEDLEY_ARM_VERSION_CHECK +#undef JSON_HEDLEY_ARRAY_PARAM +#undef JSON_HEDLEY_ASSUME +#undef JSON_HEDLEY_BEGIN_C_DECLS +#undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE +#undef JSON_HEDLEY_CLANG_HAS_BUILTIN +#undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE +#undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE +#undef JSON_HEDLEY_CLANG_HAS_EXTENSION +#undef JSON_HEDLEY_CLANG_HAS_FEATURE +#undef JSON_HEDLEY_CLANG_HAS_WARNING +#undef JSON_HEDLEY_COMPCERT_VERSION +#undef JSON_HEDLEY_COMPCERT_VERSION_CHECK +#undef JSON_HEDLEY_CONCAT +#undef JSON_HEDLEY_CONCAT3 +#undef JSON_HEDLEY_CONCAT3_EX +#undef JSON_HEDLEY_CONCAT_EX +#undef JSON_HEDLEY_CONST +#undef JSON_HEDLEY_CONSTEXPR +#undef JSON_HEDLEY_CONST_CAST +#undef JSON_HEDLEY_CPP_CAST +#undef JSON_HEDLEY_CRAY_VERSION +#undef JSON_HEDLEY_CRAY_VERSION_CHECK +#undef JSON_HEDLEY_C_DECL +#undef JSON_HEDLEY_DEPRECATED +#undef JSON_HEDLEY_DEPRECATED_FOR +#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL +#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ +#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED +#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES +#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS +#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION +#undef JSON_HEDLEY_DIAGNOSTIC_POP +#undef JSON_HEDLEY_DIAGNOSTIC_PUSH +#undef JSON_HEDLEY_DMC_VERSION +#undef JSON_HEDLEY_DMC_VERSION_CHECK +#undef JSON_HEDLEY_EMPTY_BASES +#undef JSON_HEDLEY_EMSCRIPTEN_VERSION +#undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK +#undef JSON_HEDLEY_END_C_DECLS +#undef JSON_HEDLEY_FLAGS +#undef JSON_HEDLEY_FLAGS_CAST +#undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE +#undef JSON_HEDLEY_GCC_HAS_BUILTIN +#undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE +#undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE +#undef JSON_HEDLEY_GCC_HAS_EXTENSION +#undef JSON_HEDLEY_GCC_HAS_FEATURE +#undef JSON_HEDLEY_GCC_HAS_WARNING +#undef JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK +#undef JSON_HEDLEY_GCC_VERSION +#undef JSON_HEDLEY_GCC_VERSION_CHECK +#undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE +#undef JSON_HEDLEY_GNUC_HAS_BUILTIN +#undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE +#undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE +#undef JSON_HEDLEY_GNUC_HAS_EXTENSION +#undef JSON_HEDLEY_GNUC_HAS_FEATURE +#undef JSON_HEDLEY_GNUC_HAS_WARNING +#undef JSON_HEDLEY_GNUC_VERSION +#undef JSON_HEDLEY_GNUC_VERSION_CHECK +#undef JSON_HEDLEY_HAS_ATTRIBUTE +#undef JSON_HEDLEY_HAS_BUILTIN +#undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE +#undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS +#undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE +#undef JSON_HEDLEY_HAS_EXTENSION +#undef JSON_HEDLEY_HAS_FEATURE +#undef JSON_HEDLEY_HAS_WARNING +#undef JSON_HEDLEY_IAR_VERSION +#undef JSON_HEDLEY_IAR_VERSION_CHECK +#undef JSON_HEDLEY_IBM_VERSION +#undef JSON_HEDLEY_IBM_VERSION_CHECK +#undef JSON_HEDLEY_IMPORT +#undef JSON_HEDLEY_INLINE +#undef JSON_HEDLEY_INTEL_CL_VERSION +#undef JSON_HEDLEY_INTEL_CL_VERSION_CHECK +#undef JSON_HEDLEY_INTEL_VERSION +#undef JSON_HEDLEY_INTEL_VERSION_CHECK +#undef JSON_HEDLEY_IS_CONSTANT +#undef JSON_HEDLEY_IS_CONSTEXPR_ +#undef JSON_HEDLEY_LIKELY +#undef JSON_HEDLEY_MALLOC +#undef JSON_HEDLEY_MCST_LCC_VERSION +#undef JSON_HEDLEY_MCST_LCC_VERSION_CHECK +#undef JSON_HEDLEY_MESSAGE +#undef JSON_HEDLEY_MSVC_VERSION +#undef JSON_HEDLEY_MSVC_VERSION_CHECK +#undef JSON_HEDLEY_NEVER_INLINE +#undef JSON_HEDLEY_NON_NULL +#undef JSON_HEDLEY_NO_ESCAPE +#undef JSON_HEDLEY_NO_RETURN +#undef JSON_HEDLEY_NO_THROW +#undef JSON_HEDLEY_NULL +#undef JSON_HEDLEY_PELLES_VERSION +#undef JSON_HEDLEY_PELLES_VERSION_CHECK +#undef JSON_HEDLEY_PGI_VERSION +#undef JSON_HEDLEY_PGI_VERSION_CHECK +#undef JSON_HEDLEY_PREDICT +#undef JSON_HEDLEY_PRINTF_FORMAT +#undef JSON_HEDLEY_PRIVATE +#undef JSON_HEDLEY_PUBLIC +#undef JSON_HEDLEY_PURE +#undef JSON_HEDLEY_REINTERPRET_CAST +#undef JSON_HEDLEY_REQUIRE +#undef JSON_HEDLEY_REQUIRE_CONSTEXPR +#undef JSON_HEDLEY_REQUIRE_MSG +#undef JSON_HEDLEY_RESTRICT +#undef JSON_HEDLEY_RETURNS_NON_NULL +#undef JSON_HEDLEY_SENTINEL +#undef JSON_HEDLEY_STATIC_ASSERT +#undef JSON_HEDLEY_STATIC_CAST +#undef JSON_HEDLEY_STRINGIFY +#undef JSON_HEDLEY_STRINGIFY_EX +#undef JSON_HEDLEY_SUNPRO_VERSION +#undef JSON_HEDLEY_SUNPRO_VERSION_CHECK +#undef JSON_HEDLEY_TINYC_VERSION +#undef JSON_HEDLEY_TINYC_VERSION_CHECK +#undef JSON_HEDLEY_TI_ARMCL_VERSION +#undef JSON_HEDLEY_TI_ARMCL_VERSION_CHECK +#undef JSON_HEDLEY_TI_CL2000_VERSION +#undef JSON_HEDLEY_TI_CL2000_VERSION_CHECK +#undef JSON_HEDLEY_TI_CL430_VERSION +#undef JSON_HEDLEY_TI_CL430_VERSION_CHECK +#undef JSON_HEDLEY_TI_CL6X_VERSION +#undef JSON_HEDLEY_TI_CL6X_VERSION_CHECK +#undef JSON_HEDLEY_TI_CL7X_VERSION +#undef JSON_HEDLEY_TI_CL7X_VERSION_CHECK +#undef JSON_HEDLEY_TI_CLPRU_VERSION +#undef JSON_HEDLEY_TI_CLPRU_VERSION_CHECK +#undef JSON_HEDLEY_TI_VERSION +#undef JSON_HEDLEY_TI_VERSION_CHECK +#undef JSON_HEDLEY_UNAVAILABLE +#undef JSON_HEDLEY_UNLIKELY +#undef JSON_HEDLEY_UNPREDICTABLE +#undef JSON_HEDLEY_UNREACHABLE +#undef JSON_HEDLEY_UNREACHABLE_RETURN +#undef JSON_HEDLEY_VERSION +#undef JSON_HEDLEY_VERSION_DECODE_MAJOR +#undef JSON_HEDLEY_VERSION_DECODE_MINOR +#undef JSON_HEDLEY_VERSION_DECODE_REVISION +#undef JSON_HEDLEY_VERSION_ENCODE +#undef JSON_HEDLEY_WARNING +#undef JSON_HEDLEY_WARN_UNUSED_RESULT +#undef JSON_HEDLEY_WARN_UNUSED_RESULT_MSG +#undef JSON_HEDLEY_FALL_THROUGH + + + +#endif // INCLUDE_NLOHMANN_JSON_HPP_ diff --git a/tools/dkr_assets_tool_classes/common/util/md5.h b/tools/dkr_assets_tool_src/libs/md5.hpp similarity index 98% rename from tools/dkr_assets_tool_classes/common/util/md5.h rename to tools/dkr_assets_tool_src/libs/md5.hpp index 58962849..5392eb17 100644 --- a/tools/dkr_assets_tool_classes/common/util/md5.h +++ b/tools/dkr_assets_tool_src/libs/md5.hpp @@ -144,7 +144,7 @@ namespace md5 { buffer[k++] = static_cast(static_cast(*ptr) + UCHAR_MAX + 1); if (k == 0x40) { auto j = 0; - for (auto i = 0; i < LBLOCK; ++i) { + for (uint32_t i = 0; i < LBLOCK; ++i) { input[i] = to_uint32(&buffer[j]); j += 4; } @@ -161,7 +161,7 @@ namespace md5 { const auto s = S + r * 4; const auto k = K + r * LBLOCK; - for (auto i = 0; i < input.size(); ++i) { + for (size_t i = 0; i < input.size(); ++i) { const auto new_b = t(F[r], a, b, c, d, input[g[i]], s[i % 4], k[i]); a = d; d = c; @@ -203,4 +203,4 @@ namespace md5 { } } -#endif +#endif \ No newline at end of file diff --git a/tools/dkr_assets_tool_classes/libs/n64graphics-utils.c b/tools/dkr_assets_tool_src/libs/n64graphics/n64graphics-utils.c similarity index 100% rename from tools/dkr_assets_tool_classes/libs/n64graphics-utils.c rename to tools/dkr_assets_tool_src/libs/n64graphics/n64graphics-utils.c diff --git a/tools/dkr_assets_tool_classes/libs/n64graphics-utils.h b/tools/dkr_assets_tool_src/libs/n64graphics/n64graphics-utils.h similarity index 100% rename from tools/dkr_assets_tool_classes/libs/n64graphics-utils.h rename to tools/dkr_assets_tool_src/libs/n64graphics/n64graphics-utils.h diff --git a/tools/dkr_assets_tool_classes/libs/n64graphics.c b/tools/dkr_assets_tool_src/libs/n64graphics/n64graphics.c similarity index 99% rename from tools/dkr_assets_tool_classes/libs/n64graphics.c rename to tools/dkr_assets_tool_src/libs/n64graphics/n64graphics.c index 90ea13c6..e3fc65a6 100644 --- a/tools/dkr_assets_tool_classes/libs/n64graphics.c +++ b/tools/dkr_assets_tool_src/libs/n64graphics/n64graphics.c @@ -6,9 +6,9 @@ #define STBI_NO_HDR #define STBI_NO_TGA #define STB_IMAGE_IMPLEMENTATION -#include "stb_image.h" +#include "../stb_image.h" #define STB_IMAGE_WRITE_IMPLEMENTATION -#include "stb_image_write.h" +#include "../stb_image_write.h" #include "n64graphics.h" #include "n64graphics-utils.h" @@ -155,9 +155,9 @@ ia *raw2i(const uint8_t *raw, int width, int height, int depth) bits >>= 4; } img[i].intensity = SCALE_4_8(bits); - img[i].alpha = img[i].intensity; // alpha copy intensity + //img[i].alpha = img[i].intensity; // alpha copy intensity // TODO: modes - // img[i].alpha = 0xFF; // alpha = 1 + img[i].alpha = 0xFF; // alpha = 1 // img[i].alpha = img[i].intensity ? 0xFF : 0x00; // binary } break; diff --git a/tools/dkr_assets_tool_classes/libs/n64graphics.h b/tools/dkr_assets_tool_src/libs/n64graphics/n64graphics.h similarity index 100% rename from tools/dkr_assets_tool_classes/libs/n64graphics.h rename to tools/dkr_assets_tool_src/libs/n64graphics/n64graphics.h diff --git a/tools/dkr_assets_tool_classes/libs/stb_image.h b/tools/dkr_assets_tool_src/libs/stb_image.h similarity index 100% rename from tools/dkr_assets_tool_classes/libs/stb_image.h rename to tools/dkr_assets_tool_src/libs/stb_image.h diff --git a/tools/dkr_assets_tool_classes/libs/stb_image_write.h b/tools/dkr_assets_tool_src/libs/stb_image_write.h similarity index 100% rename from tools/dkr_assets_tool_classes/libs/stb_image_write.h rename to tools/dkr_assets_tool_src/libs/stb_image_write.h diff --git a/tools/dkr_assets_tool_src/libs/tiny_gltf.h b/tools/dkr_assets_tool_src/libs/tiny_gltf.h new file mode 100644 index 00000000..7b86b899 --- /dev/null +++ b/tools/dkr_assets_tool_src/libs/tiny_gltf.h @@ -0,0 +1,8508 @@ +// +// Header-only tiny glTF 2.0 loader and serializer. +// +// +// The MIT License (MIT) +// +// Copyright (c) 2015 - Present Syoyo Fujita, Aurélien Chatelain and many +// 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. + +// Version: - v2.8.10 +// See https://github.com/syoyo/tinygltf/releases for release history. +// +// Tiny glTF loader is using following third party libraries: +// +// - jsonhpp: C++ JSON library. +// - base64: base64 decode/encode library. +// - stb_image: Image loading library. +// +#ifndef TINY_GLTF_H_ +#define TINY_GLTF_H_ + +#include +#include +#include // std::fabs +#include +#include +#include +#include +#include +#include +#include + +// Auto-detect C++14 standard version +#if !defined(TINYGLTF_USE_CPP14) && defined(__cplusplus) && \ + (__cplusplus >= 201402L) +#define TINYGLTF_USE_CPP14 +#endif + +#ifdef __ANDROID__ +#ifdef TINYGLTF_ANDROID_LOAD_FROM_ASSETS +#include +#endif +#endif + +#ifdef __GNUC__ +#if (__GNUC__ < 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ <= 8)) +#define TINYGLTF_NOEXCEPT +#else +#define TINYGLTF_NOEXCEPT noexcept +#endif +#else +#define TINYGLTF_NOEXCEPT noexcept +#endif + +#define DEFAULT_METHODS(x) \ + ~x() = default; \ + x(const x &) = default; \ + x(x &&) TINYGLTF_NOEXCEPT = default; \ + x &operator=(const x &) = default; \ + x &operator=(x &&) TINYGLTF_NOEXCEPT = default; + +namespace tinygltf { + +#define TINYGLTF_MODE_POINTS (0) +#define TINYGLTF_MODE_LINE (1) +#define TINYGLTF_MODE_LINE_LOOP (2) +#define TINYGLTF_MODE_LINE_STRIP (3) +#define TINYGLTF_MODE_TRIANGLES (4) +#define TINYGLTF_MODE_TRIANGLE_STRIP (5) +#define TINYGLTF_MODE_TRIANGLE_FAN (6) + +#define TINYGLTF_COMPONENT_TYPE_BYTE (5120) +#define TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE (5121) +#define TINYGLTF_COMPONENT_TYPE_SHORT (5122) +#define TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT (5123) +#define TINYGLTF_COMPONENT_TYPE_INT (5124) +#define TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT (5125) +#define TINYGLTF_COMPONENT_TYPE_FLOAT (5126) +#define TINYGLTF_COMPONENT_TYPE_DOUBLE \ + (5130) // OpenGL double type. Note that some of glTF 2.0 validator does not + // support double type even the schema seems allow any value of + // integer: + // https://github.com/KhronosGroup/glTF/blob/b9884a2fd45130b4d673dd6c8a706ee21ee5c5f7/specification/2.0/schema/accessor.schema.json#L22 + +#define TINYGLTF_TEXTURE_FILTER_NEAREST (9728) +#define TINYGLTF_TEXTURE_FILTER_LINEAR (9729) +#define TINYGLTF_TEXTURE_FILTER_NEAREST_MIPMAP_NEAREST (9984) +#define TINYGLTF_TEXTURE_FILTER_LINEAR_MIPMAP_NEAREST (9985) +#define TINYGLTF_TEXTURE_FILTER_NEAREST_MIPMAP_LINEAR (9986) +#define TINYGLTF_TEXTURE_FILTER_LINEAR_MIPMAP_LINEAR (9987) + +#define TINYGLTF_TEXTURE_WRAP_REPEAT (10497) +#define TINYGLTF_TEXTURE_WRAP_CLAMP_TO_EDGE (33071) +#define TINYGLTF_TEXTURE_WRAP_MIRRORED_REPEAT (33648) + +// Redeclarations of the above for technique.parameters. +#define TINYGLTF_PARAMETER_TYPE_BYTE (5120) +#define TINYGLTF_PARAMETER_TYPE_UNSIGNED_BYTE (5121) +#define TINYGLTF_PARAMETER_TYPE_SHORT (5122) +#define TINYGLTF_PARAMETER_TYPE_UNSIGNED_SHORT (5123) +#define TINYGLTF_PARAMETER_TYPE_INT (5124) +#define TINYGLTF_PARAMETER_TYPE_UNSIGNED_INT (5125) +#define TINYGLTF_PARAMETER_TYPE_FLOAT (5126) + +#define TINYGLTF_PARAMETER_TYPE_FLOAT_VEC2 (35664) +#define TINYGLTF_PARAMETER_TYPE_FLOAT_VEC3 (35665) +#define TINYGLTF_PARAMETER_TYPE_FLOAT_VEC4 (35666) + +#define TINYGLTF_PARAMETER_TYPE_INT_VEC2 (35667) +#define TINYGLTF_PARAMETER_TYPE_INT_VEC3 (35668) +#define TINYGLTF_PARAMETER_TYPE_INT_VEC4 (35669) + +#define TINYGLTF_PARAMETER_TYPE_BOOL (35670) +#define TINYGLTF_PARAMETER_TYPE_BOOL_VEC2 (35671) +#define TINYGLTF_PARAMETER_TYPE_BOOL_VEC3 (35672) +#define TINYGLTF_PARAMETER_TYPE_BOOL_VEC4 (35673) + +#define TINYGLTF_PARAMETER_TYPE_FLOAT_MAT2 (35674) +#define TINYGLTF_PARAMETER_TYPE_FLOAT_MAT3 (35675) +#define TINYGLTF_PARAMETER_TYPE_FLOAT_MAT4 (35676) + +#define TINYGLTF_PARAMETER_TYPE_SAMPLER_2D (35678) + +// End parameter types + +#define TINYGLTF_TYPE_VEC2 (2) +#define TINYGLTF_TYPE_VEC3 (3) +#define TINYGLTF_TYPE_VEC4 (4) +#define TINYGLTF_TYPE_MAT2 (32 + 2) +#define TINYGLTF_TYPE_MAT3 (32 + 3) +#define TINYGLTF_TYPE_MAT4 (32 + 4) +#define TINYGLTF_TYPE_SCALAR (64 + 1) +#define TINYGLTF_TYPE_VECTOR (64 + 4) +#define TINYGLTF_TYPE_MATRIX (64 + 16) + +#define TINYGLTF_IMAGE_FORMAT_JPEG (0) +#define TINYGLTF_IMAGE_FORMAT_PNG (1) +#define TINYGLTF_IMAGE_FORMAT_BMP (2) +#define TINYGLTF_IMAGE_FORMAT_GIF (3) + +#define TINYGLTF_TEXTURE_FORMAT_ALPHA (6406) +#define TINYGLTF_TEXTURE_FORMAT_RGB (6407) +#define TINYGLTF_TEXTURE_FORMAT_RGBA (6408) +#define TINYGLTF_TEXTURE_FORMAT_LUMINANCE (6409) +#define TINYGLTF_TEXTURE_FORMAT_LUMINANCE_ALPHA (6410) + +#define TINYGLTF_TEXTURE_TARGET_TEXTURE2D (3553) +#define TINYGLTF_TEXTURE_TYPE_UNSIGNED_BYTE (5121) + +#define TINYGLTF_TARGET_ARRAY_BUFFER (34962) +#define TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER (34963) + +#define TINYGLTF_SHADER_TYPE_VERTEX_SHADER (35633) +#define TINYGLTF_SHADER_TYPE_FRAGMENT_SHADER (35632) + +#define TINYGLTF_DOUBLE_EPS (1.e-12) +#define TINYGLTF_DOUBLE_EQUAL(a, b) (std::fabs((b) - (a)) < TINYGLTF_DOUBLE_EPS) + +#ifdef __ANDROID__ +#ifdef TINYGLTF_ANDROID_LOAD_FROM_ASSETS +#ifdef TINYGLTF_IMPLEMENTATION +AAssetManager *asset_manager = nullptr; +#else +extern AAssetManager *asset_manager; +#endif +#endif +#endif + +typedef enum { + NULL_TYPE, + REAL_TYPE, + INT_TYPE, + BOOL_TYPE, + STRING_TYPE, + ARRAY_TYPE, + BINARY_TYPE, + OBJECT_TYPE +} Type; + +typedef enum { + Permissive, + Strict +} ParseStrictness; + +static inline int32_t GetComponentSizeInBytes(uint32_t componentType) { + if (componentType == TINYGLTF_COMPONENT_TYPE_BYTE) { + return 1; + } else if (componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) { + return 1; + } else if (componentType == TINYGLTF_COMPONENT_TYPE_SHORT) { + return 2; + } else if (componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) { + return 2; + } else if (componentType == TINYGLTF_COMPONENT_TYPE_INT) { + return 4; + } else if (componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT) { + return 4; + } else if (componentType == TINYGLTF_COMPONENT_TYPE_FLOAT) { + return 4; + } else if (componentType == TINYGLTF_COMPONENT_TYPE_DOUBLE) { + return 8; + } else { + // Unknown component type + return -1; + } +} + +static inline int32_t GetNumComponentsInType(uint32_t ty) { + if (ty == TINYGLTF_TYPE_SCALAR) { + return 1; + } else if (ty == TINYGLTF_TYPE_VEC2) { + return 2; + } else if (ty == TINYGLTF_TYPE_VEC3) { + return 3; + } else if (ty == TINYGLTF_TYPE_VEC4) { + return 4; + } else if (ty == TINYGLTF_TYPE_MAT2) { + return 4; + } else if (ty == TINYGLTF_TYPE_MAT3) { + return 9; + } else if (ty == TINYGLTF_TYPE_MAT4) { + return 16; + } else { + // Unknown component type + return -1; + } +} + +// TODO(syoyo): Move these functions to TinyGLTF class +bool IsDataURI(const std::string &in); +bool DecodeDataURI(std::vector *out, std::string &mime_type, + const std::string &in, size_t reqBytes, bool checkSize); + +#ifdef __clang__ +#pragma clang diagnostic push +// Suppress warning for : static Value null_value +#pragma clang diagnostic ignored "-Wexit-time-destructors" +#pragma clang diagnostic ignored "-Wpadded" +#endif + +// Simple class to represent JSON object +class Value { + public: + typedef std::vector Array; + typedef std::map Object; + + Value() = default; + + explicit Value(bool b) : type_(BOOL_TYPE) { boolean_value_ = b; } + explicit Value(int i) : type_(INT_TYPE) { + int_value_ = i; + real_value_ = i; + } + explicit Value(double n) : type_(REAL_TYPE) { real_value_ = n; } + explicit Value(const std::string &s) : type_(STRING_TYPE) { + string_value_ = s; + } + explicit Value(std::string &&s) + : type_(STRING_TYPE), string_value_(std::move(s)) {} + explicit Value(const char *s) : type_(STRING_TYPE) { string_value_ = s; } + explicit Value(const unsigned char *p, size_t n) : type_(BINARY_TYPE) { + binary_value_.resize(n); + memcpy(binary_value_.data(), p, n); + } + explicit Value(std::vector &&v) noexcept + : type_(BINARY_TYPE), + binary_value_(std::move(v)) {} + explicit Value(const Array &a) : type_(ARRAY_TYPE) { array_value_ = a; } + explicit Value(Array &&a) noexcept : type_(ARRAY_TYPE), + array_value_(std::move(a)) {} + + explicit Value(const Object &o) : type_(OBJECT_TYPE) { object_value_ = o; } + explicit Value(Object &&o) noexcept : type_(OBJECT_TYPE), + object_value_(std::move(o)) {} + + DEFAULT_METHODS(Value) + + char Type() const { return static_cast(type_); } + + bool IsBool() const { return (type_ == BOOL_TYPE); } + + bool IsInt() const { return (type_ == INT_TYPE); } + + bool IsNumber() const { return (type_ == REAL_TYPE) || (type_ == INT_TYPE); } + + bool IsReal() const { return (type_ == REAL_TYPE); } + + bool IsString() const { return (type_ == STRING_TYPE); } + + bool IsBinary() const { return (type_ == BINARY_TYPE); } + + bool IsArray() const { return (type_ == ARRAY_TYPE); } + + bool IsObject() const { return (type_ == OBJECT_TYPE); } + + // Use this function if you want to have number value as double. + double GetNumberAsDouble() const { + if (type_ == INT_TYPE) { + return double(int_value_); + } else { + return real_value_; + } + } + + // Use this function if you want to have number value as int. + // TODO(syoyo): Support int value larger than 32 bits + int GetNumberAsInt() const { + if (type_ == REAL_TYPE) { + return int(real_value_); + } else { + return int_value_; + } + } + + // Accessor + template + const T &Get() const; + template + T &Get(); + + // Lookup value from an array + const Value &Get(int idx) const { + static Value null_value; + assert(IsArray()); + assert(idx >= 0); + return (static_cast(idx) < array_value_.size()) + ? array_value_[static_cast(idx)] + : null_value; + } + + // Lookup value from a key-value pair + const Value &Get(const std::string &key) const { + static Value null_value; + assert(IsObject()); + Object::const_iterator it = object_value_.find(key); + return (it != object_value_.end()) ? it->second : null_value; + } + + size_t ArrayLen() const { + if (!IsArray()) return 0; + return array_value_.size(); + } + + // Valid only for object type. + bool Has(const std::string &key) const { + if (!IsObject()) return false; + Object::const_iterator it = object_value_.find(key); + return (it != object_value_.end()) ? true : false; + } + + // List keys + std::vector Keys() const { + std::vector keys; + if (!IsObject()) return keys; // empty + + for (Object::const_iterator it = object_value_.begin(); + it != object_value_.end(); ++it) { + keys.push_back(it->first); + } + + return keys; + } + + size_t Size() const { return (IsArray() ? ArrayLen() : Keys().size()); } + + bool operator==(const tinygltf::Value &other) const; + + protected: + int type_ = NULL_TYPE; + + int int_value_ = 0; + double real_value_ = 0.0; + std::string string_value_; + std::vector binary_value_; + Array array_value_; + Object object_value_; + bool boolean_value_ = false; +}; + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#define TINYGLTF_VALUE_GET(ctype, var) \ + template <> \ + inline const ctype &Value::Get() const { \ + return var; \ + } \ + template <> \ + inline ctype &Value::Get() { \ + return var; \ + } +TINYGLTF_VALUE_GET(bool, boolean_value_) +TINYGLTF_VALUE_GET(double, real_value_) +TINYGLTF_VALUE_GET(int, int_value_) +TINYGLTF_VALUE_GET(std::string, string_value_) +TINYGLTF_VALUE_GET(std::vector, binary_value_) +TINYGLTF_VALUE_GET(Value::Array, array_value_) +TINYGLTF_VALUE_GET(Value::Object, object_value_) +#undef TINYGLTF_VALUE_GET + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wc++98-compat" +#pragma clang diagnostic ignored "-Wpadded" +#endif + +/// Aggregate object for representing a color +using ColorValue = std::array; + +// === legacy interface ==== +// TODO(syoyo): Deprecate `Parameter` class. +struct Parameter { + bool bool_value = false; + bool has_number_value = false; + std::string string_value; + std::vector number_array; + std::map json_double_value; + double number_value = 0.0; + + // context sensitive methods. depending the type of the Parameter you are + // accessing, these are either valid or not + // If this parameter represent a texture map in a material, will return the + // texture index + + /// Return the index of a texture if this Parameter is a texture map. + /// Returned value is only valid if the parameter represent a texture from a + /// material + int TextureIndex() const { + const auto it = json_double_value.find("index"); + if (it != std::end(json_double_value)) { + return int(it->second); + } + return -1; + } + + /// Return the index of a texture coordinate set if this Parameter is a + /// texture map. Returned value is only valid if the parameter represent a + /// texture from a material + int TextureTexCoord() const { + const auto it = json_double_value.find("texCoord"); + if (it != std::end(json_double_value)) { + return int(it->second); + } + // As per the spec, if texCoord is omitted, this parameter is 0 + return 0; + } + + /// Return the scale of a texture if this Parameter is a normal texture map. + /// Returned value is only valid if the parameter represent a normal texture + /// from a material + double TextureScale() const { + const auto it = json_double_value.find("scale"); + if (it != std::end(json_double_value)) { + return it->second; + } + // As per the spec, if scale is omitted, this parameter is 1 + return 1; + } + + /// Return the strength of a texture if this Parameter is a an occlusion map. + /// Returned value is only valid if the parameter represent an occlusion map + /// from a material + double TextureStrength() const { + const auto it = json_double_value.find("strength"); + if (it != std::end(json_double_value)) { + return it->second; + } + // As per the spec, if strength is omitted, this parameter is 1 + return 1; + } + + /// Material factor, like the roughness or metalness of a material + /// Returned value is only valid if the parameter represent a texture from a + /// material + double Factor() const { return number_value; } + + /// Return the color of a material + /// Returned value is only valid if the parameter represent a texture from a + /// material + ColorValue ColorFactor() const { + return { + {// this aggregate initialize the std::array object, and uses C++11 RVO. + number_array[0], number_array[1], number_array[2], + (number_array.size() > 3 ? number_array[3] : 1.0)}}; + } + + Parameter() = default; + DEFAULT_METHODS(Parameter) + bool operator==(const Parameter &) const; +}; + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +typedef std::map ParameterMap; +typedef std::map ExtensionMap; + +struct AnimationChannel { + int sampler{-1}; // required + int target_node{-1}; // optional index of the node to target (alternative + // target should be provided by extension) + std::string target_path; // required with standard values of ["translation", + // "rotation", "scale", "weights"] + Value extras; + ExtensionMap extensions; + Value target_extras; + ExtensionMap target_extensions; + + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; + std::string target_extras_json_string; + std::string target_extensions_json_string; + + AnimationChannel() = default; + DEFAULT_METHODS(AnimationChannel) + bool operator==(const AnimationChannel &) const; +}; + +struct AnimationSampler { + int input{-1}; // required + int output{-1}; // required + std::string interpolation; // "LINEAR", "STEP","CUBICSPLINE" or user defined + // string. default "LINEAR" + Value extras; + ExtensionMap extensions; + + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; + + AnimationSampler() : interpolation("LINEAR") {} + DEFAULT_METHODS(AnimationSampler) + bool operator==(const AnimationSampler &) const; +}; + +struct Animation { + std::string name; + std::vector channels; + std::vector samplers; + Value extras; + ExtensionMap extensions; + + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; + + Animation() = default; + DEFAULT_METHODS(Animation) + bool operator==(const Animation &) const; +}; + +struct Skin { + std::string name; + int inverseBindMatrices{-1}; // required here but not in the spec + int skeleton{-1}; // The index of the node used as a skeleton root + std::vector joints; // Indices of skeleton nodes + + Value extras; + ExtensionMap extensions; + + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; + + Skin() = default; + DEFAULT_METHODS(Skin) + bool operator==(const Skin &) const; +}; + +struct Sampler { + std::string name; + // glTF 2.0 spec does not define default value for `minFilter` and + // `magFilter`. Set -1 in TinyGLTF(issue #186) + int minFilter = + -1; // optional. -1 = no filter defined. ["NEAREST", "LINEAR", + // "NEAREST_MIPMAP_NEAREST", "LINEAR_MIPMAP_NEAREST", + // "NEAREST_MIPMAP_LINEAR", "LINEAR_MIPMAP_LINEAR"] + int magFilter = + -1; // optional. -1 = no filter defined. ["NEAREST", "LINEAR"] + int wrapS = + TINYGLTF_TEXTURE_WRAP_REPEAT; // ["CLAMP_TO_EDGE", "MIRRORED_REPEAT", + // "REPEAT"], default "REPEAT" + int wrapT = + TINYGLTF_TEXTURE_WRAP_REPEAT; // ["CLAMP_TO_EDGE", "MIRRORED_REPEAT", + // "REPEAT"], default "REPEAT" + // int wrapR = TINYGLTF_TEXTURE_WRAP_REPEAT; // TinyGLTF extension. currently + // not used. + + Value extras; + ExtensionMap extensions; + + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; + + Sampler() = default; + DEFAULT_METHODS(Sampler) + bool operator==(const Sampler &) const; +}; + +struct Image { + std::string name; + int width{-1}; + int height{-1}; + int component{-1}; + int bits{-1}; // bit depth per channel. 8(byte), 16 or 32. + int pixel_type{-1}; // pixel type(TINYGLTF_COMPONENT_TYPE_***). usually + // UBYTE(bits = 8) or USHORT(bits = 16) + std::vector image; + int bufferView{-1}; // (required if no uri) + std::string mimeType; // (required if no uri) ["image/jpeg", "image/png", + // "image/bmp", "image/gif"] + std::string uri; // (required if no mimeType) uri is not decoded(e.g. + // whitespace may be represented as %20) + Value extras; + ExtensionMap extensions; + + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; + + // When this flag is true, data is stored to `image` in as-is format(e.g. jpeg + // compressed for "image/jpeg" mime) This feature is good if you use custom + // image loader function. (e.g. delayed decoding of images for faster glTF + // parsing) Default parser for Image does not provide as-is loading feature at + // the moment. (You can manipulate this by providing your own LoadImageData + // function) + bool as_is{false}; + + Image() = default; + DEFAULT_METHODS(Image) + + bool operator==(const Image &) const; +}; + +struct Texture { + std::string name; + + int sampler{-1}; + int source{-1}; + Value extras; + ExtensionMap extensions; + + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; + + Texture() = default; + DEFAULT_METHODS(Texture) + + bool operator==(const Texture &) const; +}; + +struct TextureInfo { + int index{-1}; // required. + int texCoord{0}; // The set index of texture's TEXCOORD attribute used for + // texture coordinate mapping. + + Value extras; + ExtensionMap extensions; + + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; + + TextureInfo() = default; + DEFAULT_METHODS(TextureInfo) + bool operator==(const TextureInfo &) const; +}; + +struct NormalTextureInfo { + int index{-1}; // required + int texCoord{0}; // The set index of texture's TEXCOORD attribute used for + // texture coordinate mapping. + double scale{ + 1.0}; // scaledNormal = normalize(( + // * 2.0 - 1.0) * vec3(, , 1.0)) + + Value extras; + ExtensionMap extensions; + + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; + + NormalTextureInfo() = default; + DEFAULT_METHODS(NormalTextureInfo) + bool operator==(const NormalTextureInfo &) const; +}; + +struct OcclusionTextureInfo { + int index{-1}; // required + int texCoord{0}; // The set index of texture's TEXCOORD attribute used for + // texture coordinate mapping. + double strength{1.0}; // occludedColor = lerp(color, color * , ) + + Value extras; + ExtensionMap extensions; + + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; + + OcclusionTextureInfo() = default; + DEFAULT_METHODS(OcclusionTextureInfo) + bool operator==(const OcclusionTextureInfo &) const; +}; + +// pbrMetallicRoughness class defined in glTF 2.0 spec. +struct PbrMetallicRoughness { + std::vector baseColorFactor{1.0, 1.0, 1.0, 1.0}; // len = 4. default [1,1,1,1] + TextureInfo baseColorTexture; + double metallicFactor{1.0}; // default 1 + double roughnessFactor{1.0}; // default 1 + TextureInfo metallicRoughnessTexture; + + Value extras; + ExtensionMap extensions; + + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; + + PbrMetallicRoughness() = default; + DEFAULT_METHODS(PbrMetallicRoughness) + + bool operator==(const PbrMetallicRoughness &) const; +}; + +// Each extension should be stored in a ParameterMap. +// members not in the values could be included in the ParameterMap +// to keep a single material model +struct Material { + std::string name; + + std::vector emissiveFactor{0.0, 0.0, 0.0}; // length 3. default [0, 0, 0] + std::string alphaMode{"OPAQUE"}; // default "OPAQUE" + double alphaCutoff{0.5}; // default 0.5 + bool doubleSided{false}; // default false + + PbrMetallicRoughness pbrMetallicRoughness; + + NormalTextureInfo normalTexture; + OcclusionTextureInfo occlusionTexture; + TextureInfo emissiveTexture; + + // For backward compatibility + // TODO(syoyo): Remove `values` and `additionalValues` in the next release. + ParameterMap values; + ParameterMap additionalValues; + + ExtensionMap extensions; + Value extras; + + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; + + Material() = default; + DEFAULT_METHODS(Material) + + bool operator==(const Material &) const; +}; + +struct BufferView { + std::string name; + int buffer{-1}; // Required + size_t byteOffset{0}; // minimum 0, default 0 + size_t byteLength{0}; // required, minimum 1. 0 = invalid + size_t byteStride{0}; // minimum 4, maximum 252 (multiple of 4), default 0 = + // understood to be tightly packed + int target{0}; // ["ARRAY_BUFFER", "ELEMENT_ARRAY_BUFFER"] for vertex indices + // or attribs. Could be 0 for other data + Value extras; + ExtensionMap extensions; + + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; + + bool dracoDecoded{false}; // Flag indicating this has been draco decoded + + BufferView() = default; + DEFAULT_METHODS(BufferView) + bool operator==(const BufferView &) const; +}; + +struct Accessor { + int bufferView{-1}; // optional in spec but required here since sparse + // accessor are not supported + std::string name; + size_t byteOffset{0}; + bool normalized{false}; // optional. + int componentType{-1}; // (required) One of TINYGLTF_COMPONENT_TYPE_*** + size_t count{0}; // required + int type{-1}; // (required) One of TINYGLTF_TYPE_*** .. + Value extras; + ExtensionMap extensions; + + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; + + std::vector + minValues; // optional. integer value is promoted to double + std::vector + maxValues; // optional. integer value is promoted to double + + struct Sparse { + int count; + bool isSparse; + struct { + size_t byteOffset; + int bufferView; + int componentType; // a TINYGLTF_COMPONENT_TYPE_ value + Value extras; + ExtensionMap extensions; + std::string extras_json_string; + std::string extensions_json_string; + } indices; + struct { + int bufferView; + size_t byteOffset; + Value extras; + ExtensionMap extensions; + std::string extras_json_string; + std::string extensions_json_string; + } values; + Value extras; + ExtensionMap extensions; + std::string extras_json_string; + std::string extensions_json_string; + }; + + Sparse sparse; + + /// + /// Utility function to compute byteStride for a given bufferView object. + /// Returns -1 upon invalid glTF value or parameter configuration. + /// + int ByteStride(const BufferView &bufferViewObject) const { + if (bufferViewObject.byteStride == 0) { + // Assume data is tightly packed. + int componentSizeInBytes = + GetComponentSizeInBytes(static_cast(componentType)); + if (componentSizeInBytes <= 0) { + return -1; + } + + int numComponents = GetNumComponentsInType(static_cast(type)); + if (numComponents <= 0) { + return -1; + } + + return componentSizeInBytes * numComponents; + } else { + // Check if byteStride is a multiple of the size of the accessor's + // component type. + int componentSizeInBytes = + GetComponentSizeInBytes(static_cast(componentType)); + if (componentSizeInBytes <= 0) { + return -1; + } + + if ((bufferViewObject.byteStride % uint32_t(componentSizeInBytes)) != 0) { + return -1; + } + return static_cast(bufferViewObject.byteStride); + } + + // unreachable return 0; + } + + Accessor() + + { + sparse.isSparse = false; + } + DEFAULT_METHODS(Accessor) + bool operator==(const tinygltf::Accessor &) const; +}; + +struct PerspectiveCamera { + double aspectRatio{0.0}; // min > 0 + double yfov{0.0}; // required. min > 0 + double zfar{0.0}; // min > 0 + double znear{0.0}; // required. min > 0 + + PerspectiveCamera() = default; + DEFAULT_METHODS(PerspectiveCamera) + bool operator==(const PerspectiveCamera &) const; + + ExtensionMap extensions; + Value extras; + + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; +}; + +struct OrthographicCamera { + double xmag{0.0}; // required. must not be zero. + double ymag{0.0}; // required. must not be zero. + double zfar{0.0}; // required. `zfar` must be greater than `znear`. + double znear{0.0}; // required + + OrthographicCamera() = default; + DEFAULT_METHODS(OrthographicCamera) + bool operator==(const OrthographicCamera &) const; + + ExtensionMap extensions; + Value extras; + + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; +}; + +struct Camera { + std::string type; // required. "perspective" or "orthographic" + std::string name; + + PerspectiveCamera perspective; + OrthographicCamera orthographic; + + Camera() = default; + DEFAULT_METHODS(Camera) + bool operator==(const Camera &) const; + + ExtensionMap extensions; + Value extras; + + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; +}; + +struct Primitive { + std::map attributes; // (required) A dictionary object of + // integer, where each integer + // is the index of the accessor + // containing an attribute. + int material{-1}; // The index of the material to apply to this primitive + // when rendering. + int indices{-1}; // The index of the accessor that contains the indices. + int mode{-1}; // one of TINYGLTF_MODE_*** + std::vector > targets; // array of morph targets, + // where each target is a dict with attributes in ["POSITION, "NORMAL", + // "TANGENT"] pointing + // to their corresponding accessors + ExtensionMap extensions; + Value extras; + + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; + + Primitive() = default; + DEFAULT_METHODS(Primitive) + bool operator==(const Primitive &) const; +}; + +struct Mesh { + std::string name; + std::vector primitives; + std::vector weights; // weights to be applied to the Morph Targets + ExtensionMap extensions; + Value extras; + + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; + + Mesh() = default; + DEFAULT_METHODS(Mesh) + bool operator==(const Mesh &) const; +}; + +class Node { + public: + Node() = default; + + DEFAULT_METHODS(Node) + + bool operator==(const Node &) const; + + int camera{-1}; // the index of the camera referenced by this node + + std::string name; + int skin{-1}; + int mesh{-1}; + int light{-1}; // light source index (KHR_lights_punctual) + int emitter{-1}; // audio emitter index (KHR_audio) + std::vector children; + std::vector rotation; // length must be 0 or 4 + std::vector scale; // length must be 0 or 3 + std::vector translation; // length must be 0 or 3 + std::vector matrix; // length must be 0 or 16 + std::vector weights; // The weights of the instantiated Morph Target + + ExtensionMap extensions; + Value extras; + + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; +}; + +struct Buffer { + std::string name; + std::vector data; + std::string + uri; // considered as required here but not in the spec (need to clarify) + // uri is not decoded(e.g. whitespace may be represented as %20) + Value extras; + ExtensionMap extensions; + + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; + + Buffer() = default; + DEFAULT_METHODS(Buffer) + bool operator==(const Buffer &) const; +}; + +struct Asset { + std::string version = "2.0"; // required + std::string generator; + std::string minVersion; + std::string copyright; + ExtensionMap extensions; + Value extras; + + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; + + Asset() = default; + DEFAULT_METHODS(Asset) + bool operator==(const Asset &) const; +}; + +struct Scene { + std::string name; + std::vector nodes; + std::vector audioEmitters; // KHR_audio global emitters + + ExtensionMap extensions; + Value extras; + + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; + + Scene() = default; + DEFAULT_METHODS(Scene) + bool operator==(const Scene &) const; +}; + +struct SpotLight { + double innerConeAngle{0.0}; + double outerConeAngle{0.7853981634}; + + SpotLight() = default; + DEFAULT_METHODS(SpotLight) + bool operator==(const SpotLight &) const; + + ExtensionMap extensions; + Value extras; + + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; +}; + +struct Light { + std::string name; + std::vector color; + double intensity{1.0}; + std::string type; + double range{0.0}; // 0.0 = infinite + SpotLight spot; + + Light() = default; + DEFAULT_METHODS(Light) + + bool operator==(const Light &) const; + + ExtensionMap extensions; + Value extras; + + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; +}; + +struct PositionalEmitter { + double coneInnerAngle{6.283185307179586}; + double coneOuterAngle{6.283185307179586}; + double coneOuterGain{0.0}; + double maxDistance{100.0}; + double refDistance{1.0}; + double rolloffFactor{1.0}; + + PositionalEmitter() = default; + DEFAULT_METHODS(PositionalEmitter) + bool operator==(const PositionalEmitter &) const; + + ExtensionMap extensions; + Value extras; + + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; +}; + +struct AudioEmitter { + std::string name; + double gain{1.0}; + bool loop{false}; + bool playing{false}; + std::string + type; // positional - Positional audio emitters. Using sound cones, the + // orientation is +Z having the same front side for a glTF asset. + // global - Global audio emitters are not affected by the position + // of audio listeners. coneInnerAngle, coneOuterAngle, + // coneOuterGain, distanceModel, maxDistance, refDistance, and + // rolloffFactor should all be ignored when set. + std::string + distanceModel; // linear - A linear distance model calculating the + // gain induced by the distance according to: 1.0 + // - rolloffFactor * (distance - refDistance) / + // (maxDistance - refDistance) + // inverse - (default) An inverse distance model + // calculating the gain induced by the distance according + // to: refDistance / (refDistance + rolloffFactor * + // (Math.max(distance, refDistance) - refDistance)) + // exponential - An exponential distance model calculating + // the gain induced by the distance according to: + // pow((Math.max(distance, refDistance) / refDistance, + // -rolloffFactor)) + PositionalEmitter positional; + int source{-1}; + + AudioEmitter() : type("global"), distanceModel("inverse") {} + DEFAULT_METHODS(AudioEmitter) + + bool operator==(const AudioEmitter &) const; + + ExtensionMap extensions; + Value extras; + + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; +}; + +struct AudioSource { + std::string name; + std::string uri; + int bufferView{-1}; // (required if no uri) + std::string + mimeType; // (required if no uri) The audio's MIME type. Required if + // bufferView is defined. Unless specified by another + // extension, the only supported mimeType is audio/mpeg. + + AudioSource() = default; + DEFAULT_METHODS(AudioSource) + + bool operator==(const AudioSource &) const; + + Value extras; + ExtensionMap extensions; + + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; +}; + +class Model { + public: + Model() = default; + DEFAULT_METHODS(Model) + + bool operator==(const Model &) const; + + std::vector accessors; + std::vector animations; + std::vector buffers; + std::vector bufferViews; + std::vector materials; + std::vector meshes; + std::vector nodes; + std::vector textures; + std::vector images; + std::vector skins; + std::vector samplers; + std::vector cameras; + std::vector scenes; + std::vector lights; + std::vector audioEmitters; + std::vector audioSources; + + int defaultScene{-1}; + std::vector extensionsUsed; + std::vector extensionsRequired; + + Asset asset; + + Value extras; + ExtensionMap extensions; + + // Filled when SetStoreOriginalJSONForExtrasAndExtensions is enabled. + std::string extras_json_string; + std::string extensions_json_string; +}; + +enum SectionCheck { + NO_REQUIRE = 0x00, + REQUIRE_VERSION = 0x01, + REQUIRE_SCENE = 0x02, + REQUIRE_SCENES = 0x04, + REQUIRE_NODES = 0x08, + REQUIRE_ACCESSORS = 0x10, + REQUIRE_BUFFERS = 0x20, + REQUIRE_BUFFER_VIEWS = 0x40, + REQUIRE_ALL = 0x7f +}; + +/// +/// URIEncodeFunction type. Signature for custom URI encoding of external +/// resources such as .bin and image files. Used by tinygltf to re-encode the +/// final location of saved files. object_type may be used to encode buffer and +/// image URIs differently, for example. See +/// https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#uris +/// +typedef bool (*URIEncodeFunction)(const std::string &in_uri, + const std::string &object_type, + std::string *out_uri, void *user_data); + +/// +/// URIDecodeFunction type. Signature for custom URI decoding of external +/// resources such as .bin and image files. Used by tinygltf when computing +/// filenames to write resources. +/// +typedef bool (*URIDecodeFunction)(const std::string &in_uri, + std::string *out_uri, void *user_data); + +// Declaration of default uri decode function +bool URIDecode(const std::string &in_uri, std::string *out_uri, + void *user_data); + +/// +/// A structure containing URI callbacks and a pointer to their user data. +/// +struct URICallbacks { + URIEncodeFunction encode; // Optional encode method + URIDecodeFunction decode; // Required decode method + + void *user_data; // An argument that is passed to all uri callbacks +}; + +/// +/// LoadImageDataFunction type. Signature for custom image loading callbacks. +/// +typedef bool (*LoadImageDataFunction)(Image *, const int, std::string *, + std::string *, int, int, + const unsigned char *, int, + void *user_pointer); + +/// +/// WriteImageDataFunction type. Signature for custom image writing callbacks. +/// The out_uri parameter becomes the URI written to the gltf and may reference +/// a file or contain a data URI. +/// +typedef bool (*WriteImageDataFunction)(const std::string *basepath, + const std::string *filename, + const Image *image, bool embedImages, + const URICallbacks *uri_cb, + std::string *out_uri, + void *user_pointer); + +#ifndef TINYGLTF_NO_STB_IMAGE +// Declaration of default image loader callback +bool LoadImageData(Image *image, const int image_idx, std::string *err, + std::string *warn, int req_width, int req_height, + const unsigned char *bytes, int size, void *); +#endif + +#ifndef TINYGLTF_NO_STB_IMAGE_WRITE +// Declaration of default image writer callback +bool WriteImageData(const std::string *basepath, const std::string *filename, + const Image *image, bool embedImages, + const URICallbacks *uri_cb, std::string *out_uri, void *); +#endif + +/// +/// FilExistsFunction type. Signature for custom filesystem callbacks. +/// +typedef bool (*FileExistsFunction)(const std::string &abs_filename, void *); + +/// +/// ExpandFilePathFunction type. Signature for custom filesystem callbacks. +/// +typedef std::string (*ExpandFilePathFunction)(const std::string &, void *); + +/// +/// ReadWholeFileFunction type. Signature for custom filesystem callbacks. +/// +typedef bool (*ReadWholeFileFunction)(std::vector *, + std::string *, const std::string &, + void *); + +/// +/// WriteWholeFileFunction type. Signature for custom filesystem callbacks. +/// +typedef bool (*WriteWholeFileFunction)(std::string *, const std::string &, + const std::vector &, + void *); + +/// +/// GetFileSizeFunction type. Signature for custom filesystem callbacks. +/// +typedef bool (*GetFileSizeFunction)(size_t *filesize_out, std::string *err, + const std::string &abs_filename, + void *userdata); + +/// +/// A structure containing all required filesystem callbacks and a pointer to +/// their user data. +/// +struct FsCallbacks { + FileExistsFunction FileExists; + ExpandFilePathFunction ExpandFilePath; + ReadWholeFileFunction ReadWholeFile; + WriteWholeFileFunction WriteWholeFile; + GetFileSizeFunction GetFileSizeInBytes; // To avoid GetFileSize Win32 API, + // add `InBytes` suffix. + + void *user_data; // An argument that is passed to all fs callbacks +}; + +#ifndef TINYGLTF_NO_FS +// Declaration of default filesystem callbacks + +bool FileExists(const std::string &abs_filename, void *); + +/// +/// Expand file path(e.g. `~` to home directory on posix, `%APPDATA%` to +/// `C:\\Users\\tinygltf\\AppData`) +/// +/// @param[in] filepath File path string. Assume UTF-8 +/// @param[in] userdata User data. Set to `nullptr` if you don't need it. +/// +std::string ExpandFilePath(const std::string &filepath, void *userdata); + +bool ReadWholeFile(std::vector *out, std::string *err, + const std::string &filepath, void *); + +bool WriteWholeFile(std::string *err, const std::string &filepath, + const std::vector &contents, void *); + +bool GetFileSizeInBytes(size_t *filesize_out, std::string *err, + const std::string &filepath, void *); +#endif + +/// +/// glTF Parser/Serializer context. +/// +class TinyGLTF { + public: +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wc++98-compat" +#endif + + TinyGLTF() = default; + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + + ~TinyGLTF() = default; + + /// + /// Loads glTF ASCII asset from a file. + /// Set warning message to `warn` for example it fails to load asserts. + /// Returns false and set error string to `err` if there's an error. + /// + bool LoadASCIIFromFile(Model *model, std::string *err, std::string *warn, + const std::string &filename, + unsigned int check_sections = REQUIRE_VERSION); + + /// + /// Loads glTF ASCII asset from string(memory). + /// `length` = strlen(str); + /// `base_dir` is a search path of glTF asset(e.g. images). Path Must be an + /// expanded path (e.g. no tilde(`~`), no environment variables). Set warning + /// message to `warn` for example it fails to load asserts. Returns false and + /// set error string to `err` if there's an error. + /// + bool LoadASCIIFromString(Model *model, std::string *err, std::string *warn, + const char *str, const unsigned int length, + const std::string &base_dir, + unsigned int check_sections = REQUIRE_VERSION); + + /// + /// Loads glTF binary asset from a file. + /// Set warning message to `warn` for example it fails to load asserts. + /// Returns false and set error string to `err` if there's an error. + /// + bool LoadBinaryFromFile(Model *model, std::string *err, std::string *warn, + const std::string &filename, + unsigned int check_sections = REQUIRE_VERSION); + + /// + /// Loads glTF binary asset from memory. + /// `length` = strlen(str); + /// `base_dir` is a search path of glTF asset(e.g. images). Path Must be an + /// expanded path (e.g. no tilde(`~`), no environment variables). + /// Set warning message to `warn` for example it fails to load asserts. + /// Returns false and set error string to `err` if there's an error. + /// + bool LoadBinaryFromMemory(Model *model, std::string *err, std::string *warn, + const unsigned char *bytes, + const unsigned int length, + const std::string &base_dir = "", + unsigned int check_sections = REQUIRE_VERSION); + + /// + /// Write glTF to stream, buffers and images will be embedded + /// + bool WriteGltfSceneToStream(const Model *model, std::ostream &stream, + bool prettyPrint, bool writeBinary); + + /// + /// Write glTF to file. + /// + bool WriteGltfSceneToFile(const Model *model, const std::string &filename, + bool embedImages, bool embedBuffers, + bool prettyPrint, bool writeBinary); + + /// + /// Sets the parsing strictness. + /// + void SetParseStrictness(ParseStrictness strictness); + + /// + /// Set callback to use for loading image data + /// + void SetImageLoader(LoadImageDataFunction LoadImageData, void *user_data); + + /// + /// Unset(remove) callback of loading image data + /// + void RemoveImageLoader(); + + /// + /// Set callback to use for writing image data + /// + void SetImageWriter(WriteImageDataFunction WriteImageData, void *user_data); + + /// + /// Set callbacks to use for URI encoding and decoding and their user data + /// + void SetURICallbacks(URICallbacks callbacks); + + /// + /// Set callbacks to use for filesystem (fs) access and their user data + /// + void SetFsCallbacks(FsCallbacks callbacks); + + /// + /// Set serializing default values(default = false). + /// When true, default values are force serialized to .glTF. + /// This may be helpful if you want to serialize a full description of glTF + /// data. + /// + /// TODO(LTE): Supply parsing option as function arguments to + /// `LoadASCIIFromFile()` and others, not by a class method + /// + void SetSerializeDefaultValues(const bool enabled) { + serialize_default_values_ = enabled; + } + + bool GetSerializeDefaultValues() const { return serialize_default_values_; } + + /// + /// Store original JSON string for `extras` and `extensions`. + /// This feature will be useful when the user want to reconstruct custom data + /// structure from JSON string. + /// + void SetStoreOriginalJSONForExtrasAndExtensions(const bool enabled) { + store_original_json_for_extras_and_extensions_ = enabled; + } + + bool GetStoreOriginalJSONForExtrasAndExtensions() const { + return store_original_json_for_extras_and_extensions_; + } + + /// + /// Specify whether preserve image channels when loading images or not. + /// (Not effective when the user supplies their own LoadImageData callbacks) + /// + void SetPreserveImageChannels(bool onoff) { + preserve_image_channels_ = onoff; + } + + /// + /// Set maximum allowed external file size in bytes. + /// Default: 2GB + /// Only effective for built-in ReadWholeFileFunction FS function. + /// + void SetMaxExternalFileSize(size_t max_bytes) { + max_external_file_size_ = max_bytes; + } + + size_t GetMaxExternalFileSize() const { return max_external_file_size_; } + + bool GetPreserveImageChannels() const { return preserve_image_channels_; } + + private: + /// + /// Loads glTF asset from string(memory). + /// `length` = strlen(str); + /// Set warning message to `warn` for example it fails to load asserts + /// Returns false and set error string to `err` if there's an error. + /// + bool LoadFromString(Model *model, std::string *err, std::string *warn, + const char *str, const unsigned int length, + const std::string &base_dir, unsigned int check_sections); + + const unsigned char *bin_data_ = nullptr; + size_t bin_size_ = 0; + bool is_binary_ = false; + + ParseStrictness strictness_ = ParseStrictness::Strict; + + bool serialize_default_values_ = false; ///< Serialize default values? + + bool store_original_json_for_extras_and_extensions_ = false; + + bool preserve_image_channels_ = false; /// Default false(expand channels to + /// RGBA) for backward compatibility. + + size_t max_external_file_size_{ + size_t((std::numeric_limits::max)())}; // Default 2GB + + // Warning & error messages + std::string warn_; + std::string err_; + + FsCallbacks fs = { +#ifndef TINYGLTF_NO_FS + &tinygltf::FileExists, + &tinygltf::ExpandFilePath, + &tinygltf::ReadWholeFile, + &tinygltf::WriteWholeFile, + &tinygltf::GetFileSizeInBytes, + + nullptr // Fs callback user data +#else + nullptr, nullptr, nullptr, nullptr, nullptr, + + nullptr // Fs callback user data +#endif + }; + + URICallbacks uri_cb = { + // Use paths as-is by default. This will use JSON string escaping. + nullptr, + // Decode all URIs before using them as paths as the application may have + // percent encoded them. + &tinygltf::URIDecode, + // URI callback user data + nullptr}; + + LoadImageDataFunction LoadImageData = +#ifndef TINYGLTF_NO_STB_IMAGE + &tinygltf::LoadImageData; +#else + nullptr; +#endif + void *load_image_user_data_{nullptr}; + bool user_image_loader_{false}; + + WriteImageDataFunction WriteImageData = +#ifndef TINYGLTF_NO_STB_IMAGE_WRITE + &tinygltf::WriteImageData; +#else + nullptr; +#endif + void *write_image_user_data_{nullptr}; +}; + +#ifdef __clang__ +#pragma clang diagnostic pop // -Wpadded +#endif + +} // namespace tinygltf + +#endif // TINY_GLTF_H_ + +#if defined(TINYGLTF_IMPLEMENTATION) || defined(__INTELLISENSE__) +#include +// #include +#ifndef TINYGLTF_NO_FS +#include // for is_directory check + +#include +#include +#endif +#include + +#ifdef __clang__ +// Disable some warnings for external files. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wfloat-equal" +#pragma clang diagnostic ignored "-Wexit-time-destructors" +#pragma clang diagnostic ignored "-Wconversion" +#pragma clang diagnostic ignored "-Wold-style-cast" +#pragma clang diagnostic ignored "-Wglobal-constructors" +#if __has_warning("-Wreserved-id-macro") +#pragma clang diagnostic ignored "-Wreserved-id-macro" +#endif +#pragma clang diagnostic ignored "-Wdisabled-macro-expansion" +#pragma clang diagnostic ignored "-Wpadded" +#pragma clang diagnostic ignored "-Wc++98-compat" +#pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +#pragma clang diagnostic ignored "-Wdocumentation-unknown-command" +#pragma clang diagnostic ignored "-Wswitch-enum" +#pragma clang diagnostic ignored "-Wimplicit-fallthrough" +#pragma clang diagnostic ignored "-Wweak-vtables" +#pragma clang diagnostic ignored "-Wcovered-switch-default" +#if __has_warning("-Wdouble-promotion") +#pragma clang diagnostic ignored "-Wdouble-promotion" +#endif +#if __has_warning("-Wcomma") +#pragma clang diagnostic ignored "-Wcomma" +#endif +#if __has_warning("-Wzero-as-null-pointer-constant") +#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" +#endif +#if __has_warning("-Wcast-qual") +#pragma clang diagnostic ignored "-Wcast-qual" +#endif +#if __has_warning("-Wmissing-variable-declarations") +#pragma clang diagnostic ignored "-Wmissing-variable-declarations" +#endif +#if __has_warning("-Wmissing-prototypes") +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#endif +#if __has_warning("-Wcast-align") +#pragma clang diagnostic ignored "-Wcast-align" +#endif +#if __has_warning("-Wnewline-eof") +#pragma clang diagnostic ignored "-Wnewline-eof" +#endif +#if __has_warning("-Wunused-parameter") +#pragma clang diagnostic ignored "-Wunused-parameter" +#endif +#if __has_warning("-Wmismatched-tags") +#pragma clang diagnostic ignored "-Wmismatched-tags" +#endif +#if __has_warning("-Wextra-semi-stmt") +#pragma clang diagnostic ignored "-Wextra-semi-stmt" +#endif +#endif + +// Disable GCC warnings +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wtype-limits" +#endif // __GNUC__ + +#ifndef TINYGLTF_NO_INCLUDE_JSON +#ifndef TINYGLTF_USE_RAPIDJSON +#include "json.hpp" +#else +#ifndef TINYGLTF_NO_INCLUDE_RAPIDJSON +#include "document.h" +#include "prettywriter.h" +#include "rapidjson.h" +#include "stringbuffer.h" +#include "writer.h" +#endif +#endif +#endif + +#ifdef TINYGLTF_ENABLE_DRACO +#include "draco/compression/decode.h" +#include "draco/core/decoder_buffer.h" +#endif + +#ifndef TINYGLTF_NO_STB_IMAGE +#ifndef TINYGLTF_NO_INCLUDE_STB_IMAGE +#include "stb_image.h" +#endif +#endif + +#ifndef TINYGLTF_NO_STB_IMAGE_WRITE +#ifndef TINYGLTF_NO_INCLUDE_STB_IMAGE_WRITE +#include "stb_image_write.h" +#endif +#endif + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + +#ifdef _WIN32 + +// issue 143. +// Define NOMINMAX to avoid min/max defines, +// but undef it after included Windows.h +#ifndef NOMINMAX +#define TINYGLTF_INTERNAL_NOMINMAX +#define NOMINMAX +#endif + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#define TINYGLTF_INTERNAL_WIN32_LEAN_AND_MEAN +#endif +#ifndef __MINGW32__ +#include // include API for expanding a file path +#else +#include +#endif + +#ifdef TINYGLTF_INTERNAL_WIN32_LEAN_AND_MEAN +#undef WIN32_LEAN_AND_MEAN +#endif + +#if defined(TINYGLTF_INTERNAL_NOMINMAX) +#undef NOMINMAX +#endif + +#if defined(__GLIBCXX__) // mingw + +#include // _O_RDONLY + +#include // fstream (all sorts of IO stuff) + stdio_filebuf (=streambuf) + +#endif + +#elif !defined(__ANDROID__) && !defined(__OpenBSD__) +// #include +#endif + +#if defined(__sparcv9) || defined(__powerpc__) +// Big endian +#else +#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU +#define TINYGLTF_LITTLE_ENDIAN 1 +#endif +#endif + +namespace tinygltf { +namespace detail { +#ifdef TINYGLTF_USE_RAPIDJSON + +#ifdef TINYGLTF_USE_RAPIDJSON_CRTALLOCATOR +// This uses the RapidJSON CRTAllocator. It is thread safe and multiple +// documents may be active at once. +using json = + rapidjson::GenericValue, rapidjson::CrtAllocator>; +using json_iterator = json::MemberIterator; +using json_const_iterator = json::ConstMemberIterator; +using json_const_array_iterator = json const *; +using JsonDocument = + rapidjson::GenericDocument, rapidjson::CrtAllocator>; +rapidjson::CrtAllocator s_CrtAllocator; // stateless and thread safe +rapidjson::CrtAllocator &GetAllocator() { return s_CrtAllocator; } +#else +// This uses the default RapidJSON MemoryPoolAllocator. It is very fast, but +// not thread safe. Only a single JsonDocument may be active at any one time, +// meaning only a single gltf load/save can be active any one time. +using json = rapidjson::Value; +using json_iterator = json::MemberIterator; +using json_const_iterator = json::ConstMemberIterator; +using json_const_array_iterator = json const *; +rapidjson::Document *s_pActiveDocument = nullptr; +rapidjson::Document::AllocatorType &GetAllocator() { + assert(s_pActiveDocument); // Root json node must be JsonDocument type + return s_pActiveDocument->GetAllocator(); +} + +#ifdef __clang__ +#pragma clang diagnostic push +// Suppress JsonDocument(JsonDocument &&rhs) noexcept +#pragma clang diagnostic ignored "-Wunused-member-function" +#endif + +struct JsonDocument : public rapidjson::Document { + JsonDocument() { + assert(s_pActiveDocument == + nullptr); // When using default allocator, only one document can be + // active at a time, if you need multiple active at once, + // define TINYGLTF_USE_RAPIDJSON_CRTALLOCATOR + s_pActiveDocument = this; + } + JsonDocument(const JsonDocument &) = delete; + JsonDocument(JsonDocument &&rhs) noexcept + : rapidjson::Document(std::move(rhs)) { + s_pActiveDocument = this; + rhs.isNil = true; + } + ~JsonDocument() { + if (!isNil) { + s_pActiveDocument = nullptr; + } + } + + private: + bool isNil = false; +}; + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#endif // TINYGLTF_USE_RAPIDJSON_CRTALLOCATOR + +#else +using nlohmann::json; +using json_iterator = json::iterator; +using json_const_iterator = json::const_iterator; +using json_const_array_iterator = json_const_iterator; +using JsonDocument = json; +#endif + +void JsonParse(JsonDocument &doc, const char *str, size_t length, + bool throwExc = false) { +#ifdef TINYGLTF_USE_RAPIDJSON + (void)throwExc; + doc.Parse(str, length); +#else + doc = detail::json::parse(str, str + length, nullptr, throwExc); +#endif +} +} // namespace detail +} // namespace tinygltf + +#ifdef __APPLE__ +#include "TargetConditionals.h" +#endif + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wc++98-compat" +#endif + +namespace tinygltf { + +/// +/// Internal LoadImageDataOption struct. +/// This struct is passed through `user_pointer` in LoadImageData. +/// The struct is not passed when the user supply their own LoadImageData +/// callbacks. +/// +struct LoadImageDataOption { + // true: preserve image channels(e.g. load as RGB image if the image has RGB + // channels) default `false`(channels are expanded to RGBA for backward + // compatibility). + bool preserve_channels{false}; +}; + +// Equals function for Value, for recursivity +static bool Equals(const tinygltf::Value &one, const tinygltf::Value &other) { + if (one.Type() != other.Type()) return false; + + switch (one.Type()) { + case NULL_TYPE: + return true; + case BOOL_TYPE: + return one.Get() == other.Get(); + case REAL_TYPE: + return TINYGLTF_DOUBLE_EQUAL(one.Get(), other.Get()); + case INT_TYPE: + return one.Get() == other.Get(); + case OBJECT_TYPE: { + auto oneObj = one.Get(); + auto otherObj = other.Get(); + if (oneObj.size() != otherObj.size()) return false; + for (auto &it : oneObj) { + auto otherIt = otherObj.find(it.first); + if (otherIt == otherObj.end()) return false; + + if (!Equals(it.second, otherIt->second)) return false; + } + return true; + } + case ARRAY_TYPE: { + if (one.Size() != other.Size()) return false; + for (int i = 0; i < int(one.Size()); ++i) + if (!Equals(one.Get(i), other.Get(i))) return false; + return true; + } + case STRING_TYPE: + return one.Get() == other.Get(); + case BINARY_TYPE: + return one.Get >() == + other.Get >(); + default: { + // unhandled type + return false; + } + } +} + +// Equals function for std::vector using TINYGLTF_DOUBLE_EPSILON +static bool Equals(const std::vector &one, + const std::vector &other) { + if (one.size() != other.size()) return false; + for (int i = 0; i < int(one.size()); ++i) { + if (!TINYGLTF_DOUBLE_EQUAL(one[size_t(i)], other[size_t(i)])) return false; + } + return true; +} + +bool Accessor::operator==(const Accessor &other) const { + return this->bufferView == other.bufferView && + this->byteOffset == other.byteOffset && + this->componentType == other.componentType && + this->count == other.count && this->extensions == other.extensions && + this->extras == other.extras && + Equals(this->maxValues, other.maxValues) && + Equals(this->minValues, other.minValues) && this->name == other.name && + this->normalized == other.normalized && this->type == other.type; +} +bool Animation::operator==(const Animation &other) const { + return this->channels == other.channels && + this->extensions == other.extensions && this->extras == other.extras && + this->name == other.name && this->samplers == other.samplers; +} +bool AnimationChannel::operator==(const AnimationChannel &other) const { + return this->extensions == other.extensions && this->extras == other.extras && + this->target_node == other.target_node && + this->target_path == other.target_path && + this->sampler == other.sampler; +} +bool AnimationSampler::operator==(const AnimationSampler &other) const { + return this->extras == other.extras && this->extensions == other.extensions && + this->input == other.input && + this->interpolation == other.interpolation && + this->output == other.output; +} +bool Asset::operator==(const Asset &other) const { + return this->copyright == other.copyright && + this->extensions == other.extensions && this->extras == other.extras && + this->generator == other.generator && + this->minVersion == other.minVersion && this->version == other.version; +} +bool Buffer::operator==(const Buffer &other) const { + return this->data == other.data && this->extensions == other.extensions && + this->extras == other.extras && this->name == other.name && + this->uri == other.uri; +} +bool BufferView::operator==(const BufferView &other) const { + return this->buffer == other.buffer && this->byteLength == other.byteLength && + this->byteOffset == other.byteOffset && + this->byteStride == other.byteStride && this->name == other.name && + this->target == other.target && this->extensions == other.extensions && + this->extras == other.extras && + this->dracoDecoded == other.dracoDecoded; +} +bool Camera::operator==(const Camera &other) const { + return this->name == other.name && this->extensions == other.extensions && + this->extras == other.extras && + this->orthographic == other.orthographic && + this->perspective == other.perspective && this->type == other.type; +} +bool Image::operator==(const Image &other) const { + return this->bufferView == other.bufferView && + this->component == other.component && + this->extensions == other.extensions && this->extras == other.extras && + this->height == other.height && this->image == other.image && + this->mimeType == other.mimeType && this->name == other.name && + this->uri == other.uri && this->width == other.width; +} +bool Light::operator==(const Light &other) const { + return Equals(this->color, other.color) && this->name == other.name && + this->type == other.type; +} +bool AudioEmitter::operator==(const AudioEmitter &other) const { + return this->name == other.name && + TINYGLTF_DOUBLE_EQUAL(this->gain, other.gain) && + this->loop == other.loop && this->playing == other.playing && + this->type == other.type && + this->distanceModel == other.distanceModel && + this->source == other.source; +} +bool AudioSource::operator==(const AudioSource &other) const { + return this->name == other.name && this->uri == other.uri; +} +bool Material::operator==(const Material &other) const { + return (this->pbrMetallicRoughness == other.pbrMetallicRoughness) && + (this->normalTexture == other.normalTexture) && + (this->occlusionTexture == other.occlusionTexture) && + (this->emissiveTexture == other.emissiveTexture) && + Equals(this->emissiveFactor, other.emissiveFactor) && + (this->alphaMode == other.alphaMode) && + TINYGLTF_DOUBLE_EQUAL(this->alphaCutoff, other.alphaCutoff) && + (this->doubleSided == other.doubleSided) && + (this->extensions == other.extensions) && + (this->extras == other.extras) && (this->values == other.values) && + (this->additionalValues == other.additionalValues) && + (this->name == other.name); +} +bool Mesh::operator==(const Mesh &other) const { + return this->extensions == other.extensions && this->extras == other.extras && + this->name == other.name && Equals(this->weights, other.weights) && + this->primitives == other.primitives; +} +bool Model::operator==(const Model &other) const { + return this->accessors == other.accessors && + this->animations == other.animations && this->asset == other.asset && + this->buffers == other.buffers && + this->bufferViews == other.bufferViews && + this->cameras == other.cameras && + this->defaultScene == other.defaultScene && + this->extensions == other.extensions && + this->extensionsRequired == other.extensionsRequired && + this->extensionsUsed == other.extensionsUsed && + this->extras == other.extras && this->images == other.images && + this->lights == other.lights && this->materials == other.materials && + this->meshes == other.meshes && this->nodes == other.nodes && + this->samplers == other.samplers && this->scenes == other.scenes && + this->skins == other.skins && this->textures == other.textures; +} +bool Node::operator==(const Node &other) const { + return this->camera == other.camera && this->children == other.children && + this->extensions == other.extensions && this->extras == other.extras && + Equals(this->matrix, other.matrix) && this->mesh == other.mesh && + (this->light == other.light) && (this->emitter == other.emitter) && + this->name == other.name && Equals(this->rotation, other.rotation) && + Equals(this->scale, other.scale) && this->skin == other.skin && + Equals(this->translation, other.translation) && + Equals(this->weights, other.weights); +} +bool SpotLight::operator==(const SpotLight &other) const { + return this->extensions == other.extensions && this->extras == other.extras && + TINYGLTF_DOUBLE_EQUAL(this->innerConeAngle, other.innerConeAngle) && + TINYGLTF_DOUBLE_EQUAL(this->outerConeAngle, other.outerConeAngle); +} +bool PositionalEmitter::operator==(const PositionalEmitter &other) const { + return this->extensions == other.extensions && this->extras == other.extras && + TINYGLTF_DOUBLE_EQUAL(this->coneInnerAngle, other.coneInnerAngle) && + TINYGLTF_DOUBLE_EQUAL(this->coneOuterAngle, other.coneOuterAngle) && + TINYGLTF_DOUBLE_EQUAL(this->coneOuterGain, other.coneOuterGain) && + TINYGLTF_DOUBLE_EQUAL(this->maxDistance, other.maxDistance) && + TINYGLTF_DOUBLE_EQUAL(this->refDistance, other.refDistance) && + TINYGLTF_DOUBLE_EQUAL(this->rolloffFactor, other.rolloffFactor); +} +bool OrthographicCamera::operator==(const OrthographicCamera &other) const { + return this->extensions == other.extensions && this->extras == other.extras && + TINYGLTF_DOUBLE_EQUAL(this->xmag, other.xmag) && + TINYGLTF_DOUBLE_EQUAL(this->ymag, other.ymag) && + TINYGLTF_DOUBLE_EQUAL(this->zfar, other.zfar) && + TINYGLTF_DOUBLE_EQUAL(this->znear, other.znear); +} +bool Parameter::operator==(const Parameter &other) const { + if (this->bool_value != other.bool_value || + this->has_number_value != other.has_number_value) + return false; + + if (!TINYGLTF_DOUBLE_EQUAL(this->number_value, other.number_value)) + return false; + + if (this->json_double_value.size() != other.json_double_value.size()) + return false; + for (auto &it : this->json_double_value) { + auto otherIt = other.json_double_value.find(it.first); + if (otherIt == other.json_double_value.end()) return false; + + if (!TINYGLTF_DOUBLE_EQUAL(it.second, otherIt->second)) return false; + } + + if (!Equals(this->number_array, other.number_array)) return false; + + if (this->string_value != other.string_value) return false; + + return true; +} +bool PerspectiveCamera::operator==(const PerspectiveCamera &other) const { + return TINYGLTF_DOUBLE_EQUAL(this->aspectRatio, other.aspectRatio) && + this->extensions == other.extensions && this->extras == other.extras && + TINYGLTF_DOUBLE_EQUAL(this->yfov, other.yfov) && + TINYGLTF_DOUBLE_EQUAL(this->zfar, other.zfar) && + TINYGLTF_DOUBLE_EQUAL(this->znear, other.znear); +} +bool Primitive::operator==(const Primitive &other) const { + return this->attributes == other.attributes && this->extras == other.extras && + this->indices == other.indices && this->material == other.material && + this->mode == other.mode && this->targets == other.targets; +} +bool Sampler::operator==(const Sampler &other) const { + return this->extensions == other.extensions && this->extras == other.extras && + this->magFilter == other.magFilter && + this->minFilter == other.minFilter && this->name == other.name && + this->wrapS == other.wrapS && this->wrapT == other.wrapT; + + // this->wrapR == other.wrapR +} +bool Scene::operator==(const Scene &other) const { + return this->extensions == other.extensions && this->extras == other.extras && + this->name == other.name && this->nodes == other.nodes; +} +bool Skin::operator==(const Skin &other) const { + return this->extensions == other.extensions && this->extras == other.extras && + this->inverseBindMatrices == other.inverseBindMatrices && + this->joints == other.joints && this->name == other.name && + this->skeleton == other.skeleton; +} +bool Texture::operator==(const Texture &other) const { + return this->extensions == other.extensions && this->extras == other.extras && + this->name == other.name && this->sampler == other.sampler && + this->source == other.source; +} +bool TextureInfo::operator==(const TextureInfo &other) const { + return this->extensions == other.extensions && this->extras == other.extras && + this->index == other.index && this->texCoord == other.texCoord; +} +bool NormalTextureInfo::operator==(const NormalTextureInfo &other) const { + return this->extensions == other.extensions && this->extras == other.extras && + this->index == other.index && this->texCoord == other.texCoord && + TINYGLTF_DOUBLE_EQUAL(this->scale, other.scale); +} +bool OcclusionTextureInfo::operator==(const OcclusionTextureInfo &other) const { + return this->extensions == other.extensions && this->extras == other.extras && + this->index == other.index && this->texCoord == other.texCoord && + TINYGLTF_DOUBLE_EQUAL(this->strength, other.strength); +} +bool PbrMetallicRoughness::operator==(const PbrMetallicRoughness &other) const { + return this->extensions == other.extensions && this->extras == other.extras && + (this->baseColorTexture == other.baseColorTexture) && + (this->metallicRoughnessTexture == other.metallicRoughnessTexture) && + Equals(this->baseColorFactor, other.baseColorFactor) && + TINYGLTF_DOUBLE_EQUAL(this->metallicFactor, other.metallicFactor) && + TINYGLTF_DOUBLE_EQUAL(this->roughnessFactor, other.roughnessFactor); +} +bool Value::operator==(const Value &other) const { + return Equals(*this, other); +} + +static void swap4(unsigned int *val) { +#ifdef TINYGLTF_LITTLE_ENDIAN + (void)val; +#else + unsigned int tmp = *val; + unsigned char *dst = reinterpret_cast(val); + unsigned char *src = reinterpret_cast(&tmp); + + dst[0] = src[3]; + dst[1] = src[2]; + dst[2] = src[1]; + dst[3] = src[0]; +#endif +} + +static std::string JoinPath(const std::string &path0, + const std::string &path1) { + if (path0.empty()) { + return path1; + } else { + // check '/' + char lastChar = *path0.rbegin(); + if (lastChar != '/') { + return path0 + std::string("/") + path1; + } else { + return path0 + path1; + } + } +} + +static std::string FindFile(const std::vector &paths, + const std::string &filepath, FsCallbacks *fs) { + if (fs == nullptr || fs->ExpandFilePath == nullptr || + fs->FileExists == nullptr) { + // Error, fs callback[s] missing + return std::string(); + } + + // https://github.com/syoyo/tinygltf/issues/416 + // Use strlen() since std::string's size/length reports the number of elements + // in the buffer, not the length of string(null-terminated) strip + // null-character in the middle of string. + size_t slength = strlen(filepath.c_str()); + if (slength == 0) { + return std::string(); + } + + std::string cleaned_filepath = std::string(filepath.c_str()); + + for (size_t i = 0; i < paths.size(); i++) { + std::string absPath = + fs->ExpandFilePath(JoinPath(paths[i], cleaned_filepath), fs->user_data); + if (fs->FileExists(absPath, fs->user_data)) { + return absPath; + } + } + + return std::string(); +} + +static std::string GetFilePathExtension(const std::string &FileName) { + if (FileName.find_last_of(".") != std::string::npos) + return FileName.substr(FileName.find_last_of(".") + 1); + return ""; +} + +static std::string GetBaseDir(const std::string &filepath) { + if (filepath.find_last_of("/\\") != std::string::npos) + return filepath.substr(0, filepath.find_last_of("/\\")); + return ""; +} + +static std::string GetBaseFilename(const std::string &filepath) { + auto idx = filepath.find_last_of("/\\"); + if (idx != std::string::npos) return filepath.substr(idx + 1); + return filepath; +} + +std::string base64_encode(unsigned char const *, unsigned int len); +std::string base64_decode(std::string const &s); + +/* + base64.cpp and base64.h + + Copyright (C) 2004-2008 René Nyffenegger + + This source code is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this source code must not be misrepresented; you must not + claim that you wrote the original source code. If you use this source code + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original source code. + + 3. This notice may not be removed or altered from any source distribution. + + René Nyffenegger rene.nyffenegger@adp-gmbh.ch + +*/ + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wsign-conversion" +#pragma clang diagnostic ignored "-Wconversion" +#endif + +static inline bool is_base64(unsigned char c) { + return (isalnum(c) || (c == '+') || (c == '/')); +} + +std::string base64_encode(unsigned char const *bytes_to_encode, + unsigned int in_len) { + std::string ret; + int i = 0; + int j = 0; + unsigned char char_array_3[3]; + unsigned char char_array_4[4]; + + const char *base64_chars = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + + while (in_len--) { + char_array_3[i++] = *(bytes_to_encode++); + if (i == 3) { + char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; + char_array_4[1] = + ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = + ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[3] = char_array_3[2] & 0x3f; + + for (i = 0; (i < 4); i++) ret += base64_chars[char_array_4[i]]; + i = 0; + } + } + + if (i) { + for (j = i; j < 3; j++) char_array_3[j] = '\0'; + + char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; + char_array_4[1] = + ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = + ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); + + for (j = 0; (j < i + 1); j++) ret += base64_chars[char_array_4[j]]; + + while ((i++ < 3)) ret += '='; + } + + return ret; +} + +std::string base64_decode(std::string const &encoded_string) { + int in_len = static_cast(encoded_string.size()); + int i = 0; + int j = 0; + int in_ = 0; + unsigned char char_array_4[4], char_array_3[3]; + std::string ret; + + const std::string base64_chars = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + + while (in_len-- && (encoded_string[in_] != '=') && + is_base64(encoded_string[in_])) { + char_array_4[i++] = encoded_string[in_]; + in_++; + if (i == 4) { + for (i = 0; i < 4; i++) + char_array_4[i] = + static_cast(base64_chars.find(char_array_4[i])); + + char_array_3[0] = + (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); + char_array_3[1] = + ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); + char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + + for (i = 0; (i < 3); i++) ret += char_array_3[i]; + i = 0; + } + } + + if (i) { + for (j = i; j < 4; j++) char_array_4[j] = 0; + + for (j = 0; j < 4; j++) + char_array_4[j] = + static_cast(base64_chars.find(char_array_4[j])); + + char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); + char_array_3[1] = + ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); + char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + + for (j = 0; (j < i - 1); j++) ret += char_array_3[j]; + } + + return ret; +} +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +// https://github.com/syoyo/tinygltf/issues/228 +// TODO(syoyo): Use uriparser https://uriparser.github.io/ for stricter Uri +// decoding? +// +// Uri Decoding from DLIB +// http://dlib.net/dlib/server/server_http.cpp.html +// --- dlib begin ------------------------------------------------------------ +// Copyright (C) 2003 Davis E. King (davis@dlib.net) +// License: Boost Software License +// Boost Software License - Version 1.0 - August 17th, 2003 + +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +namespace dlib { + +inline unsigned char from_hex(unsigned char ch) { + if (ch <= '9' && ch >= '0') + ch -= '0'; + else if (ch <= 'f' && ch >= 'a') + ch -= 'a' - 10; + else if (ch <= 'F' && ch >= 'A') + ch -= 'A' - 10; + else + ch = 0; + return ch; +} + +static const std::string urldecode(const std::string &str) { + using namespace std; + string result; + string::size_type i; + for (i = 0; i < str.size(); ++i) { + if (str[i] == '+') { + result += ' '; + } else if (str[i] == '%' && str.size() > i + 2) { + const unsigned char ch1 = + from_hex(static_cast(str[i + 1])); + const unsigned char ch2 = + from_hex(static_cast(str[i + 2])); + const unsigned char ch = static_cast((ch1 << 4) | ch2); + result += static_cast(ch); + i += 2; + } else { + result += str[i]; + } + } + return result; +} + +} // namespace dlib +// --- dlib end -------------------------------------------------------------- + +bool URIDecode(const std::string &in_uri, std::string *out_uri, + void *user_data) { + (void)user_data; + *out_uri = dlib::urldecode(in_uri); + return true; +} + +static bool LoadExternalFile(std::vector *out, std::string *err, + std::string *warn, const std::string &filename, + const std::string &basedir, bool required, + size_t reqBytes, bool checkSize, + size_t maxFileSize, FsCallbacks *fs) { + if (fs == nullptr || fs->FileExists == nullptr || + fs->ExpandFilePath == nullptr || fs->ReadWholeFile == nullptr) { + // This is a developer error, assert() ? + if (err) { + (*err) += "FS callback[s] not set\n"; + } + return false; + } + + std::string *failMsgOut = required ? err : warn; + + out->clear(); + + std::vector paths; + paths.push_back(basedir); + paths.push_back("."); + + std::string filepath = FindFile(paths, filename, fs); + if (filepath.empty() || filename.empty()) { + if (failMsgOut) { + (*failMsgOut) += "File not found : " + filename + "\n"; + } + return false; + } + + // Check file size + if (fs->GetFileSizeInBytes) { + size_t file_size{0}; + std::string _err; + bool ok = + fs->GetFileSizeInBytes(&file_size, &_err, filepath, fs->user_data); + if (!ok) { + if (_err.size()) { + if (failMsgOut) { + (*failMsgOut) += "Getting file size failed : " + filename + + ", err = " + _err + "\n"; + } + } + return false; + } + + if (file_size > maxFileSize) { + if (failMsgOut) { + (*failMsgOut) += "File size " + std::to_string(file_size) + + " exceeds maximum allowed file size " + + std::to_string(maxFileSize) + " : " + filepath + "\n"; + } + return false; + } + } + + std::vector buf; + std::string fileReadErr; + bool fileRead = + fs->ReadWholeFile(&buf, &fileReadErr, filepath, fs->user_data); + if (!fileRead) { + if (failMsgOut) { + (*failMsgOut) += + "File read error : " + filepath + " : " + fileReadErr + "\n"; + } + return false; + } + + size_t sz = buf.size(); + if (sz == 0) { + if (failMsgOut) { + (*failMsgOut) += "File is empty : " + filepath + "\n"; + } + return false; + } + + if (checkSize) { + if (reqBytes == sz) { + out->swap(buf); + return true; + } else { + std::stringstream ss; + ss << "File size mismatch : " << filepath << ", requestedBytes " + << reqBytes << ", but got " << sz << std::endl; + if (failMsgOut) { + (*failMsgOut) += ss.str(); + } + return false; + } + } + + out->swap(buf); + return true; +} + +void TinyGLTF::SetParseStrictness(ParseStrictness strictness) { + strictness_ = strictness; +} + +void TinyGLTF::SetImageLoader(LoadImageDataFunction func, void *user_data) { + LoadImageData = func; + load_image_user_data_ = user_data; + user_image_loader_ = true; +} + +void TinyGLTF::RemoveImageLoader() { + LoadImageData = +#ifndef TINYGLTF_NO_STB_IMAGE + &tinygltf::LoadImageData; +#else + nullptr; +#endif + + load_image_user_data_ = nullptr; + user_image_loader_ = false; +} + +#ifndef TINYGLTF_NO_STB_IMAGE +bool LoadImageData(Image *image, const int image_idx, std::string *err, + std::string *warn, int req_width, int req_height, + const unsigned char *bytes, int size, void *user_data) { + (void)warn; + + LoadImageDataOption option; + if (user_data) { + option = *reinterpret_cast(user_data); + } + + int w = 0, h = 0, comp = 0, req_comp = 0; + + unsigned char *data = nullptr; + + // preserve_channels true: Use channels stored in the image file. + // false: force 32-bit textures for common Vulkan compatibility. It appears + // that some GPU drivers do not support 24-bit images for Vulkan + req_comp = option.preserve_channels ? 0 : 4; + int bits = 8; + int pixel_type = TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE; + + // It is possible that the image we want to load is a 16bit per channel image + // We are going to attempt to load it as 16bit per channel, and if it worked, + // set the image data accordingly. We are casting the returned pointer into + // unsigned char, because we are representing "bytes". But we are updating + // the Image metadata to signal that this image uses 2 bytes (16bits) per + // channel: + if (stbi_is_16_bit_from_memory(bytes, size)) { + data = reinterpret_cast( + stbi_load_16_from_memory(bytes, size, &w, &h, &comp, req_comp)); + if (data) { + bits = 16; + pixel_type = TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT; + } + } + + // at this point, if data is still NULL, it means that the image wasn't + // 16bit per channel, we are going to load it as a normal 8bit per channel + // image as we used to do: + // if image cannot be decoded, ignore parsing and keep it by its path + // don't break in this case + // FIXME we should only enter this function if the image is embedded. If + // image->uri references + // an image file, it should be left as it is. Image loading should not be + // mandatory (to support other formats) + if (!data) data = stbi_load_from_memory(bytes, size, &w, &h, &comp, req_comp); + if (!data) { + // NOTE: you can use `warn` instead of `err` + if (err) { + (*err) += + "Unknown image format. STB cannot decode image data for image[" + + std::to_string(image_idx) + "] name = \"" + image->name + "\".\n"; + } + return false; + } + + if ((w < 1) || (h < 1)) { + stbi_image_free(data); + if (err) { + (*err) += "Invalid image data for image[" + std::to_string(image_idx) + + "] name = \"" + image->name + "\"\n"; + } + return false; + } + + if (req_width > 0) { + if (req_width != w) { + stbi_image_free(data); + if (err) { + (*err) += "Image width mismatch for image[" + + std::to_string(image_idx) + "] name = \"" + image->name + + "\"\n"; + } + return false; + } + } + + if (req_height > 0) { + if (req_height != h) { + stbi_image_free(data); + if (err) { + (*err) += "Image height mismatch. for image[" + + std::to_string(image_idx) + "] name = \"" + image->name + + "\"\n"; + } + return false; + } + } + + if (req_comp != 0) { + // loaded data has `req_comp` channels(components) + comp = req_comp; + } + + image->width = w; + image->height = h; + image->component = comp; + image->bits = bits; + image->pixel_type = pixel_type; + image->image.resize(static_cast(w * h * comp) * size_t(bits / 8)); + std::copy(data, data + w * h * comp * (bits / 8), image->image.begin()); + stbi_image_free(data); + + return true; +} +#endif + +void TinyGLTF::SetImageWriter(WriteImageDataFunction func, void *user_data) { + WriteImageData = func; + write_image_user_data_ = user_data; +} + +#ifndef TINYGLTF_NO_STB_IMAGE_WRITE +static void WriteToMemory_stbi(void *context, void *data, int size) { + std::vector *buffer = + reinterpret_cast *>(context); + + unsigned char *pData = reinterpret_cast(data); + + buffer->insert(buffer->end(), pData, pData + size); +} + +bool WriteImageData(const std::string *basepath, const std::string *filename, + const Image *image, bool embedImages, + const URICallbacks *uri_cb, std::string *out_uri, + void *fsPtr) { + const std::string ext = GetFilePathExtension(*filename); + + // Write image to temporary buffer + std::string header; + std::vector data; + + if (ext == "png") { + if ((image->bits != 8) || + (image->pixel_type != TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE)) { + // Unsupported pixel format + return false; + } + + if (!stbi_write_png_to_func(WriteToMemory_stbi, &data, image->width, + image->height, image->component, + &image->image[0], 0)) { + return false; + } + header = "data:image/png;base64,"; + } else if (ext == "jpg") { + if (!stbi_write_jpg_to_func(WriteToMemory_stbi, &data, image->width, + image->height, image->component, + &image->image[0], 100)) { + return false; + } + header = "data:image/jpeg;base64,"; + } else if (ext == "bmp") { + if (!stbi_write_bmp_to_func(WriteToMemory_stbi, &data, image->width, + image->height, image->component, + &image->image[0])) { + return false; + } + header = "data:image/bmp;base64,"; + } else if (!embedImages) { + // Error: can't output requested format to file + return false; + } + + if (embedImages) { + // Embed base64-encoded image into URI + if (data.size()) { + *out_uri = header + base64_encode(&data[0], + static_cast(data.size())); + } else { + // Throw error? + } + } else { + // Write image to disc + FsCallbacks *fs = reinterpret_cast(fsPtr); + if ((fs != nullptr) && (fs->WriteWholeFile != nullptr)) { + const std::string imagefilepath = JoinPath(*basepath, *filename); + std::string writeError; + if (!fs->WriteWholeFile(&writeError, imagefilepath, data, + fs->user_data)) { + // Could not write image file to disc; Throw error ? + return false; + } + } else { + // Throw error? + } + if (uri_cb->encode) { + if (!uri_cb->encode(*filename, "image", out_uri, uri_cb->user_data)) { + return false; + } + } else { + *out_uri = *filename; + } + } + + return true; +} +#endif + +void TinyGLTF::SetURICallbacks(URICallbacks callbacks) { + assert(callbacks.decode); + if (callbacks.decode) { + uri_cb = callbacks; + } +} + +void TinyGLTF::SetFsCallbacks(FsCallbacks callbacks) { fs = callbacks; } + +#ifdef _WIN32 +static inline std::wstring UTF8ToWchar(const std::string &str) { + int wstr_size = + MultiByteToWideChar(CP_UTF8, 0, str.data(), (int)str.size(), nullptr, 0); + std::wstring wstr((size_t)wstr_size, 0); + MultiByteToWideChar(CP_UTF8, 0, str.data(), (int)str.size(), &wstr[0], + (int)wstr.size()); + return wstr; +} + +static inline std::string WcharToUTF8(const std::wstring &wstr) { + int str_size = WideCharToMultiByte(CP_UTF8, 0, wstr.data(), (int)wstr.size(), + nullptr, 0, nullptr, nullptr); + std::string str((size_t)str_size, 0); + WideCharToMultiByte(CP_UTF8, 0, wstr.data(), (int)wstr.size(), &str[0], + (int)str.size(), nullptr, nullptr); + return str; +} +#endif + +#ifndef TINYGLTF_NO_FS +// Default implementations of filesystem functions + +bool FileExists(const std::string &abs_filename, void *) { + bool ret; +#ifdef TINYGLTF_ANDROID_LOAD_FROM_ASSETS + if (asset_manager) { + AAsset *asset = AAssetManager_open(asset_manager, abs_filename.c_str(), + AASSET_MODE_STREAMING); + if (!asset) { + return false; + } + AAsset_close(asset); + ret = true; + } else { + return false; + } +#else +#ifdef _WIN32 +#if defined(_MSC_VER) || defined(_LIBCPP_VERSION) + + // First check if a file is a directory. + DWORD result = GetFileAttributesW(UTF8ToWchar(abs_filename).c_str()); + if (result == INVALID_FILE_ATTRIBUTES) { + return false; + } + if (result & FILE_ATTRIBUTE_DIRECTORY) { + return false; + } + + FILE *fp = nullptr; + errno_t err = _wfopen_s(&fp, UTF8ToWchar(abs_filename).c_str(), L"rb"); + if (err != 0) { + return false; + } +#elif defined(__GLIBCXX__) + FILE *fp = fopen(abs_filename.c_str(), "rb"); + if (!fp) { + return false; + } +#else + // TODO: is_directory check + FILE *fp = nullptr; + errno_t err = fopen_s(&fp, abs_filename.c_str(), "rb"); + if (err != 0) { + return false; + } +#endif + +#else + struct stat sb; + if (stat(abs_filename.c_str(), &sb)) { + return false; + } + if (S_ISDIR(sb.st_mode)) { + return false; + } + + FILE *fp = fopen(abs_filename.c_str(), "rb"); +#endif + if (fp) { + ret = true; + fclose(fp); + } else { + ret = false; + } +#endif + + return ret; +} + +std::string ExpandFilePath(const std::string &filepath, void *) { + // https://github.com/syoyo/tinygltf/issues/368 + // + // No file path expansion in built-in FS function anymore, since glTF URI + // should not contain tilde('~') and environment variables, and for security + // reason(`wordexp`). + // + // Users need to supply `base_dir`(in `LoadASCIIFromString`, + // `LoadBinaryFromMemory`) in expanded absolute path. + + return filepath; + +#if 0 +#ifdef _WIN32 + // Assume input `filepath` is encoded in UTF-8 + std::wstring wfilepath = UTF8ToWchar(filepath); + DWORD wlen = ExpandEnvironmentStringsW(wfilepath.c_str(), nullptr, 0); + wchar_t *wstr = new wchar_t[wlen]; + ExpandEnvironmentStringsW(wfilepath.c_str(), wstr, wlen); + + std::wstring ws(wstr); + delete[] wstr; + return WcharToUTF8(ws); + +#else + +#if defined(TARGET_OS_IPHONE) || defined(TARGET_IPHONE_SIMULATOR) || \ + defined(__ANDROID__) || defined(__EMSCRIPTEN__) || defined(__OpenBSD__) + // no expansion + std::string s = filepath; +#else + std::string s; + wordexp_t p; + + if (filepath.empty()) { + return ""; + } + + // Quote the string to keep any spaces in filepath intact. + std::string quoted_path = "\"" + filepath + "\""; + // char** w; + int ret = wordexp(quoted_path.c_str(), &p, 0); + if (ret) { + // err + s = filepath; + return s; + } + + // Use first element only. + if (p.we_wordv) { + s = std::string(p.we_wordv[0]); + wordfree(&p); + } else { + s = filepath; + } + +#endif + + return s; +#endif +#endif +} + +bool GetFileSizeInBytes(size_t *filesize_out, std::string *err, + const std::string &filepath, void *userdata) { + (void)userdata; + +#ifdef TINYGLTF_ANDROID_LOAD_FROM_ASSETS + if (asset_manager) { + AAsset *asset = AAssetManager_open(asset_manager, filepath.c_str(), + AASSET_MODE_STREAMING); + if (!asset) { + if (err) { + (*err) += "File open error : " + filepath + "\n"; + } + return false; + } + size_t size = AAsset_getLength(asset); + + if (size == 0) { + if (err) { + (*err) += "Invalid file size : " + filepath + + " (does the path point to a directory?)"; + } + return false; + } + + return true; + } else { + if (err) { + (*err) += "No asset manager specified : " + filepath + "\n"; + } + return false; + } +#else +#ifdef _WIN32 +#if defined(__GLIBCXX__) // mingw + int file_descriptor = + _wopen(UTF8ToWchar(filepath).c_str(), _O_RDONLY | _O_BINARY); + __gnu_cxx::stdio_filebuf wfile_buf(file_descriptor, std::ios_base::in); + std::istream f(&wfile_buf); +#elif defined(_MSC_VER) || defined(_LIBCPP_VERSION) + // For libcxx, assume _LIBCPP_HAS_OPEN_WITH_WCHAR is defined to accept + // `wchar_t *` + std::ifstream f(UTF8ToWchar(filepath).c_str(), std::ifstream::binary); +#else + // Unknown compiler/runtime + std::ifstream f(filepath.c_str(), std::ifstream::binary); +#endif +#else + std::ifstream f(filepath.c_str(), std::ifstream::binary); +#endif + if (!f) { + if (err) { + (*err) += "File open error : " + filepath + "\n"; + } + return false; + } + + // For directory(and pipe?), peek() will fail(Posix gnustl/libc++ only) + f.peek(); + if (!f) { + if (err) { + (*err) += + "File read error. Maybe empty file or invalid file : " + filepath + + "\n"; + } + return false; + } + + f.seekg(0, f.end); + size_t sz = static_cast(f.tellg()); + + // std::cout << "sz = " << sz << "\n"; + f.seekg(0, f.beg); + + if (int64_t(sz) < 0) { + if (err) { + (*err) += "Invalid file size : " + filepath + + " (does the path point to a directory?)"; + } + return false; + } else if (sz == 0) { + if (err) { + (*err) += "File is empty : " + filepath + "\n"; + } + return false; + } else if (sz >= (std::numeric_limits::max)()) { + if (err) { + (*err) += "Invalid file size : " + filepath + "\n"; + } + return false; + } + + (*filesize_out) = sz; + return true; +#endif +} + +bool ReadWholeFile(std::vector *out, std::string *err, + const std::string &filepath, void *) { +#ifdef TINYGLTF_ANDROID_LOAD_FROM_ASSETS + if (asset_manager) { + AAsset *asset = AAssetManager_open(asset_manager, filepath.c_str(), + AASSET_MODE_STREAMING); + if (!asset) { + if (err) { + (*err) += "File open error : " + filepath + "\n"; + } + return false; + } + size_t size = AAsset_getLength(asset); + if (size == 0) { + if (err) { + (*err) += "Invalid file size : " + filepath + + " (does the path point to a directory?)"; + } + return false; + } + out->resize(size); + AAsset_read(asset, reinterpret_cast(&out->at(0)), size); + AAsset_close(asset); + return true; + } else { + if (err) { + (*err) += "No asset manager specified : " + filepath + "\n"; + } + return false; + } +#else +#ifdef _WIN32 +#if defined(__GLIBCXX__) // mingw + int file_descriptor = + _wopen(UTF8ToWchar(filepath).c_str(), _O_RDONLY | _O_BINARY); + __gnu_cxx::stdio_filebuf wfile_buf(file_descriptor, std::ios_base::in); + std::istream f(&wfile_buf); +#elif defined(_MSC_VER) || defined(_LIBCPP_VERSION) + // For libcxx, assume _LIBCPP_HAS_OPEN_WITH_WCHAR is defined to accept + // `wchar_t *` + std::ifstream f(UTF8ToWchar(filepath).c_str(), std::ifstream::binary); +#else + // Unknown compiler/runtime + std::ifstream f(filepath.c_str(), std::ifstream::binary); +#endif +#else + std::ifstream f(filepath.c_str(), std::ifstream::binary); +#endif + if (!f) { + if (err) { + (*err) += "File open error : " + filepath + "\n"; + } + return false; + } + + // For directory(and pipe?), peek() will fail(Posix gnustl/libc++ only) + f.peek(); + if (!f) { + if (err) { + (*err) += + "File read error. Maybe empty file or invalid file : " + filepath + + "\n"; + } + return false; + } + + f.seekg(0, f.end); + size_t sz = static_cast(f.tellg()); + + // std::cout << "sz = " << sz << "\n"; + f.seekg(0, f.beg); + + if (int64_t(sz) < 0) { + if (err) { + (*err) += "Invalid file size : " + filepath + + " (does the path point to a directory?)"; + } + return false; + } else if (sz == 0) { + if (err) { + (*err) += "File is empty : " + filepath + "\n"; + } + return false; + } else if (sz >= (std::numeric_limits::max)()) { + if (err) { + (*err) += "Invalid file size : " + filepath + "\n"; + } + return false; + } + + out->resize(sz); + f.read(reinterpret_cast(&out->at(0)), + static_cast(sz)); + + return true; +#endif +} + +bool WriteWholeFile(std::string *err, const std::string &filepath, + const std::vector &contents, void *) { +#ifdef _WIN32 +#if defined(__GLIBCXX__) // mingw + int file_descriptor = _wopen(UTF8ToWchar(filepath).c_str(), + _O_CREAT | _O_WRONLY | _O_TRUNC | _O_BINARY); + __gnu_cxx::stdio_filebuf wfile_buf( + file_descriptor, std::ios_base::out | std::ios_base::binary); + std::ostream f(&wfile_buf); +#elif defined(_MSC_VER) + std::ofstream f(UTF8ToWchar(filepath).c_str(), std::ofstream::binary); +#else // clang? + std::ofstream f(filepath.c_str(), std::ofstream::binary); +#endif +#else + std::ofstream f(filepath.c_str(), std::ofstream::binary); +#endif + if (!f) { + if (err) { + (*err) += "File open error for writing : " + filepath + "\n"; + } + return false; + } + + f.write(reinterpret_cast(&contents.at(0)), + static_cast(contents.size())); + if (!f) { + if (err) { + (*err) += "File write error: " + filepath + "\n"; + } + return false; + } + + return true; +} + +#endif // TINYGLTF_NO_FS + +static std::string MimeToExt(const std::string &mimeType) { + if (mimeType == "image/jpeg") { + return "jpg"; + } else if (mimeType == "image/png") { + return "png"; + } else if (mimeType == "image/bmp") { + return "bmp"; + } else if (mimeType == "image/gif") { + return "gif"; + } + + return ""; +} + +static bool UpdateImageObject(const Image &image, std::string &baseDir, + int index, bool embedImages, + const URICallbacks *uri_cb, + WriteImageDataFunction *WriteImageData, + void *user_data, std::string *out_uri) { + std::string filename; + std::string ext; + // If image has uri, use it as a filename + if (image.uri.size()) { + std::string decoded_uri; + if (!uri_cb->decode(image.uri, &decoded_uri, uri_cb->user_data)) { + // A decode failure results in a failure to write the gltf. + return false; + } + filename = GetBaseFilename(decoded_uri); + ext = GetFilePathExtension(filename); + } else if (image.bufferView != -1) { + // If there's no URI and the data exists in a buffer, + // don't change properties or write images + } else if (image.name.size()) { + ext = MimeToExt(image.mimeType); + // Otherwise use name as filename + filename = image.name + "." + ext; + } else { + ext = MimeToExt(image.mimeType); + // Fallback to index of image as filename + filename = std::to_string(index) + "." + ext; + } + + // If callback is set and image data exists, modify image data object. If + // image data does not exist, this is not considered a failure and the + // original uri should be maintained. + bool imageWritten = false; + if (*WriteImageData != nullptr && !filename.empty() && !image.image.empty()) { + imageWritten = (*WriteImageData)(&baseDir, &filename, &image, embedImages, + uri_cb, out_uri, user_data); + if (!imageWritten) { + return false; + } + } + + // Use the original uri if the image was not written. + if (!imageWritten) { + *out_uri = image.uri; + } + + return true; +} + +bool IsDataURI(const std::string &in) { + std::string header = "data:application/octet-stream;base64,"; + if (in.find(header) == 0) { + return true; + } + + header = "data:image/jpeg;base64,"; + if (in.find(header) == 0) { + return true; + } + + header = "data:image/png;base64,"; + if (in.find(header) == 0) { + return true; + } + + header = "data:image/bmp;base64,"; + if (in.find(header) == 0) { + return true; + } + + header = "data:image/gif;base64,"; + if (in.find(header) == 0) { + return true; + } + + header = "data:text/plain;base64,"; + if (in.find(header) == 0) { + return true; + } + + header = "data:application/gltf-buffer;base64,"; + if (in.find(header) == 0) { + return true; + } + + return false; +} + +bool DecodeDataURI(std::vector *out, std::string &mime_type, + const std::string &in, size_t reqBytes, bool checkSize) { + std::string header = "data:application/octet-stream;base64,"; + std::string data; + if (in.find(header) == 0) { + data = base64_decode(in.substr(header.size())); // cut mime string. + } + + if (data.empty()) { + header = "data:image/jpeg;base64,"; + if (in.find(header) == 0) { + mime_type = "image/jpeg"; + data = base64_decode(in.substr(header.size())); // cut mime string. + } + } + + if (data.empty()) { + header = "data:image/png;base64,"; + if (in.find(header) == 0) { + mime_type = "image/png"; + data = base64_decode(in.substr(header.size())); // cut mime string. + } + } + + if (data.empty()) { + header = "data:image/bmp;base64,"; + if (in.find(header) == 0) { + mime_type = "image/bmp"; + data = base64_decode(in.substr(header.size())); // cut mime string. + } + } + + if (data.empty()) { + header = "data:image/gif;base64,"; + if (in.find(header) == 0) { + mime_type = "image/gif"; + data = base64_decode(in.substr(header.size())); // cut mime string. + } + } + + if (data.empty()) { + header = "data:text/plain;base64,"; + if (in.find(header) == 0) { + mime_type = "text/plain"; + data = base64_decode(in.substr(header.size())); + } + } + + if (data.empty()) { + header = "data:application/gltf-buffer;base64,"; + if (in.find(header) == 0) { + data = base64_decode(in.substr(header.size())); + } + } + + // TODO(syoyo): Allow empty buffer? #229 + if (data.empty()) { + return false; + } + + if (checkSize) { + if (data.size() != reqBytes) { + return false; + } + out->resize(reqBytes); + } else { + out->resize(data.size()); + } + std::copy(data.begin(), data.end(), out->begin()); + return true; +} + +namespace detail { +bool GetInt(const detail::json &o, int &val) { +#ifdef TINYGLTF_USE_RAPIDJSON + if (!o.IsDouble()) { + if (o.IsInt()) { + val = o.GetInt(); + return true; + } else if (o.IsUint()) { + val = static_cast(o.GetUint()); + return true; + } else if (o.IsInt64()) { + val = static_cast(o.GetInt64()); + return true; + } else if (o.IsUint64()) { + val = static_cast(o.GetUint64()); + return true; + } + } + + return false; +#else + auto type = o.type(); + + if ((type == detail::json::value_t::number_integer) || + (type == detail::json::value_t::number_unsigned)) { + val = static_cast(o.get()); + return true; + } + + return false; +#endif +} + +#ifdef TINYGLTF_USE_RAPIDJSON +bool GetDouble(const detail::json &o, double &val) { + if (o.IsDouble()) { + val = o.GetDouble(); + return true; + } + + return false; +} +#endif + +bool GetNumber(const detail::json &o, double &val) { +#ifdef TINYGLTF_USE_RAPIDJSON + if (o.IsNumber()) { + val = o.GetDouble(); + return true; + } + + return false; +#else + if (o.is_number()) { + val = o.get(); + return true; + } + + return false; +#endif +} + +bool GetString(const detail::json &o, std::string &val) { +#ifdef TINYGLTF_USE_RAPIDJSON + if (o.IsString()) { + val = o.GetString(); + return true; + } + + return false; +#else + if (o.type() == detail::json::value_t::string) { + val = o.get(); + return true; + } + + return false; +#endif +} + +bool IsArray(const detail::json &o) { +#ifdef TINYGLTF_USE_RAPIDJSON + return o.IsArray(); +#else + return o.is_array(); +#endif +} + +detail::json_const_array_iterator ArrayBegin(const detail::json &o) { +#ifdef TINYGLTF_USE_RAPIDJSON + return o.Begin(); +#else + return o.begin(); +#endif +} + +detail::json_const_array_iterator ArrayEnd(const detail::json &o) { +#ifdef TINYGLTF_USE_RAPIDJSON + return o.End(); +#else + return o.end(); +#endif +} + +bool IsObject(const detail::json &o) { +#ifdef TINYGLTF_USE_RAPIDJSON + return o.IsObject(); +#else + return o.is_object(); +#endif +} + +detail::json_const_iterator ObjectBegin(const detail::json &o) { +#ifdef TINYGLTF_USE_RAPIDJSON + return o.MemberBegin(); +#else + return o.begin(); +#endif +} + +detail::json_const_iterator ObjectEnd(const detail::json &o) { +#ifdef TINYGLTF_USE_RAPIDJSON + return o.MemberEnd(); +#else + return o.end(); +#endif +} + +// Making this a const char* results in a pointer to a temporary when +// TINYGLTF_USE_RAPIDJSON is off. +std::string GetKey(detail::json_const_iterator &it) { +#ifdef TINYGLTF_USE_RAPIDJSON + return it->name.GetString(); +#else + return it.key().c_str(); +#endif +} + +bool FindMember(const detail::json &o, const char *member, + detail::json_const_iterator &it) { +#ifdef TINYGLTF_USE_RAPIDJSON + if (!o.IsObject()) { + return false; + } + it = o.FindMember(member); + return it != o.MemberEnd(); +#else + it = o.find(member); + return it != o.end(); +#endif +} + +bool FindMember(detail::json &o, const char *member, + detail::json_iterator &it) { +#ifdef TINYGLTF_USE_RAPIDJSON + if (!o.IsObject()) { + return false; + } + it = o.FindMember(member); + return it != o.MemberEnd(); +#else + it = o.find(member); + return it != o.end(); +#endif +} + +void Erase(detail::json &o, detail::json_iterator &it) { +#ifdef TINYGLTF_USE_RAPIDJSON + o.EraseMember(it); +#else + o.erase(it); +#endif +} + +bool IsEmpty(const detail::json &o) { +#ifdef TINYGLTF_USE_RAPIDJSON + return o.ObjectEmpty(); +#else + return o.empty(); +#endif +} + +const detail::json &GetValue(detail::json_const_iterator &it) { +#ifdef TINYGLTF_USE_RAPIDJSON + return it->value; +#else + return it.value(); +#endif +} + +detail::json &GetValue(detail::json_iterator &it) { +#ifdef TINYGLTF_USE_RAPIDJSON + return it->value; +#else + return it.value(); +#endif +} + +std::string JsonToString(const detail::json &o, int spacing = -1) { +#ifdef TINYGLTF_USE_RAPIDJSON + using namespace rapidjson; + StringBuffer buffer; + if (spacing == -1) { + Writer writer(buffer); + // TODO: Better error handling. + // https://github.com/syoyo/tinygltf/issues/332 + if (!o.Accept(writer)) { + return "tiny_gltf::JsonToString() failed rapidjson conversion"; + } + } else { + PrettyWriter writer(buffer); + writer.SetIndent(' ', uint32_t(spacing)); + if (!o.Accept(writer)) { + return "tiny_gltf::JsonToString() failed rapidjson conversion"; + } + } + return buffer.GetString(); +#else + return o.dump(spacing); +#endif +} + +} // namespace detail + +static bool ParseJsonAsValue(Value *ret, const detail::json &o) { + Value val{}; +#ifdef TINYGLTF_USE_RAPIDJSON + using rapidjson::Type; + switch (o.GetType()) { + case Type::kObjectType: { + Value::Object value_object; + for (auto it = o.MemberBegin(); it != o.MemberEnd(); ++it) { + Value entry; + ParseJsonAsValue(&entry, it->value); + if (entry.Type() != NULL_TYPE) + value_object.emplace(detail::GetKey(it), std::move(entry)); + } + if (value_object.size() > 0) val = Value(std::move(value_object)); + } break; + case Type::kArrayType: { + Value::Array value_array; + value_array.reserve(o.Size()); + for (auto it = o.Begin(); it != o.End(); ++it) { + Value entry; + ParseJsonAsValue(&entry, *it); + if (entry.Type() != NULL_TYPE) + value_array.emplace_back(std::move(entry)); + } + if (value_array.size() > 0) val = Value(std::move(value_array)); + } break; + case Type::kStringType: + val = Value(std::string(o.GetString())); + break; + case Type::kFalseType: + case Type::kTrueType: + val = Value(o.GetBool()); + break; + case Type::kNumberType: + if (!o.IsDouble()) { + int i = 0; + detail::GetInt(o, i); + val = Value(i); + } else { + double d = 0.0; + detail::GetDouble(o, d); + val = Value(d); + } + break; + case Type::kNullType: + break; + // all types are covered, so no `case default` + } +#else + switch (o.type()) { + case detail::json::value_t::object: { + Value::Object value_object; + for (auto it = o.begin(); it != o.end(); it++) { + Value entry; + ParseJsonAsValue(&entry, it.value()); + if (entry.Type() != NULL_TYPE) + value_object.emplace(it.key(), std::move(entry)); + } + if (value_object.size() > 0) val = Value(std::move(value_object)); + } break; + case detail::json::value_t::array: { + Value::Array value_array; + value_array.reserve(o.size()); + for (auto it = o.begin(); it != o.end(); it++) { + Value entry; + ParseJsonAsValue(&entry, it.value()); + if (entry.Type() != NULL_TYPE) + value_array.emplace_back(std::move(entry)); + } + if (value_array.size() > 0) val = Value(std::move(value_array)); + } break; + case detail::json::value_t::string: + val = Value(o.get()); + break; + case detail::json::value_t::boolean: + val = Value(o.get()); + break; + case detail::json::value_t::number_integer: + case detail::json::value_t::number_unsigned: + val = Value(static_cast(o.get())); + break; + case detail::json::value_t::number_float: + val = Value(o.get()); + break; + case detail::json::value_t::null: + case detail::json::value_t::discarded: + case detail::json::value_t::binary: + // default: + break; + } +#endif + const bool isNotNull = val.Type() != NULL_TYPE; + + if (ret) *ret = std::move(val); + + return isNotNull; +} + +static bool ParseExtrasProperty(Value *ret, const detail::json &o) { + detail::json_const_iterator it; + if (!detail::FindMember(o, "extras", it)) { + return false; + } + + return ParseJsonAsValue(ret, detail::GetValue(it)); +} + +static bool ParseBooleanProperty(bool *ret, std::string *err, + const detail::json &o, + const std::string &property, + const bool required, + const std::string &parent_node = "") { + detail::json_const_iterator it; + if (!detail::FindMember(o, property.c_str(), it)) { + if (required) { + if (err) { + (*err) += "'" + property + "' property is missing"; + if (!parent_node.empty()) { + (*err) += " in " + parent_node; + } + (*err) += ".\n"; + } + } + return false; + } + + auto &value = detail::GetValue(it); + + bool isBoolean; + bool boolValue = false; +#ifdef TINYGLTF_USE_RAPIDJSON + isBoolean = value.IsBool(); + if (isBoolean) { + boolValue = value.GetBool(); + } +#else + isBoolean = value.is_boolean(); + if (isBoolean) { + boolValue = value.get(); + } +#endif + if (!isBoolean) { + if (required) { + if (err) { + (*err) += "'" + property + "' property is not a bool type.\n"; + } + } + return false; + } + + if (ret) { + (*ret) = boolValue; + } + + return true; +} + +static bool ParseIntegerProperty(int *ret, std::string *err, + const detail::json &o, + const std::string &property, + const bool required, + const std::string &parent_node = "") { + detail::json_const_iterator it; + if (!detail::FindMember(o, property.c_str(), it)) { + if (required) { + if (err) { + (*err) += "'" + property + "' property is missing"; + if (!parent_node.empty()) { + (*err) += " in " + parent_node; + } + (*err) += ".\n"; + } + } + return false; + } + + int intValue; + bool isInt = detail::GetInt(detail::GetValue(it), intValue); + if (!isInt) { + if (required) { + if (err) { + (*err) += "'" + property + "' property is not an integer type.\n"; + } + } + return false; + } + + if (ret) { + (*ret) = intValue; + } + + return true; +} + +static bool ParseUnsignedProperty(size_t *ret, std::string *err, + const detail::json &o, + const std::string &property, + const bool required, + const std::string &parent_node = "") { + detail::json_const_iterator it; + if (!detail::FindMember(o, property.c_str(), it)) { + if (required) { + if (err) { + (*err) += "'" + property + "' property is missing"; + if (!parent_node.empty()) { + (*err) += " in " + parent_node; + } + (*err) += ".\n"; + } + } + return false; + } + + auto &value = detail::GetValue(it); + + size_t uValue = 0; + bool isUValue; +#ifdef TINYGLTF_USE_RAPIDJSON + isUValue = false; + if (value.IsUint()) { + uValue = value.GetUint(); + isUValue = true; + } else if (value.IsUint64()) { + uValue = value.GetUint64(); + isUValue = true; + } +#else + isUValue = value.is_number_unsigned(); + if (isUValue) { + uValue = value.get(); + } +#endif + if (!isUValue) { + if (required) { + if (err) { + (*err) += "'" + property + "' property is not a positive integer.\n"; + } + } + return false; + } + + if (ret) { + (*ret) = uValue; + } + + return true; +} + +static bool ParseNumberProperty(double *ret, std::string *err, + const detail::json &o, + const std::string &property, + const bool required, + const std::string &parent_node = "") { + detail::json_const_iterator it; + + if (!detail::FindMember(o, property.c_str(), it)) { + if (required) { + if (err) { + (*err) += "'" + property + "' property is missing"; + if (!parent_node.empty()) { + (*err) += " in " + parent_node; + } + (*err) += ".\n"; + } + } + return false; + } + + double numberValue; + bool isNumber = detail::GetNumber(detail::GetValue(it), numberValue); + + if (!isNumber) { + if (required) { + if (err) { + (*err) += "'" + property + "' property is not a number type.\n"; + } + } + return false; + } + + if (ret) { + (*ret) = numberValue; + } + + return true; +} + +static bool ParseNumberArrayProperty(std::vector *ret, std::string *err, + const detail::json &o, + const std::string &property, bool required, + const std::string &parent_node = "") { + detail::json_const_iterator it; + if (!detail::FindMember(o, property.c_str(), it)) { + if (required) { + if (err) { + (*err) += "'" + property + "' property is missing"; + if (!parent_node.empty()) { + (*err) += " in " + parent_node; + } + (*err) += ".\n"; + } + } + return false; + } + + if (!detail::IsArray(detail::GetValue(it))) { + if (required) { + if (err) { + (*err) += "'" + property + "' property is not an array"; + if (!parent_node.empty()) { + (*err) += " in " + parent_node; + } + (*err) += ".\n"; + } + } + return false; + } + + ret->clear(); + auto end = detail::ArrayEnd(detail::GetValue(it)); + for (auto i = detail::ArrayBegin(detail::GetValue(it)); i != end; ++i) { + double numberValue; + const bool isNumber = detail::GetNumber(*i, numberValue); + if (!isNumber) { + if (required) { + if (err) { + (*err) += "'" + property + "' property is not a number.\n"; + if (!parent_node.empty()) { + (*err) += " in " + parent_node; + } + (*err) += ".\n"; + } + } + return false; + } + ret->push_back(numberValue); + } + + return true; +} + +static bool ParseIntegerArrayProperty(std::vector *ret, std::string *err, + const detail::json &o, + const std::string &property, + bool required, + const std::string &parent_node = "") { + detail::json_const_iterator it; + if (!detail::FindMember(o, property.c_str(), it)) { + if (required) { + if (err) { + (*err) += "'" + property + "' property is missing"; + if (!parent_node.empty()) { + (*err) += " in " + parent_node; + } + (*err) += ".\n"; + } + } + return false; + } + + if (!detail::IsArray(detail::GetValue(it))) { + if (required) { + if (err) { + (*err) += "'" + property + "' property is not an array"; + if (!parent_node.empty()) { + (*err) += " in " + parent_node; + } + (*err) += ".\n"; + } + } + return false; + } + + ret->clear(); + auto end = detail::ArrayEnd(detail::GetValue(it)); + for (auto i = detail::ArrayBegin(detail::GetValue(it)); i != end; ++i) { + int numberValue; + bool isNumber = detail::GetInt(*i, numberValue); + if (!isNumber) { + if (required) { + if (err) { + (*err) += "'" + property + "' property is not an integer type.\n"; + if (!parent_node.empty()) { + (*err) += " in " + parent_node; + } + (*err) += ".\n"; + } + } + return false; + } + ret->push_back(numberValue); + } + + return true; +} + +static bool ParseStringProperty( + std::string *ret, std::string *err, const detail::json &o, + const std::string &property, bool required, + const std::string &parent_node = std::string()) { + detail::json_const_iterator it; + if (!detail::FindMember(o, property.c_str(), it)) { + if (required) { + if (err) { + (*err) += "'" + property + "' property is missing"; + if (parent_node.empty()) { + (*err) += ".\n"; + } else { + (*err) += " in `" + parent_node + "'.\n"; + } + } + } + return false; + } + + std::string strValue; + if (!detail::GetString(detail::GetValue(it), strValue)) { + if (required) { + if (err) { + (*err) += "'" + property + "' property is not a string type.\n"; + } + } + return false; + } + + if (ret) { + (*ret) = std::move(strValue); + } + + return true; +} + +static bool ParseStringIntegerProperty(std::map *ret, + std::string *err, const detail::json &o, + const std::string &property, + bool required, + const std::string &parent = "") { + detail::json_const_iterator it; + if (!detail::FindMember(o, property.c_str(), it)) { + if (required) { + if (err) { + if (!parent.empty()) { + (*err) += + "'" + property + "' property is missing in " + parent + ".\n"; + } else { + (*err) += "'" + property + "' property is missing.\n"; + } + } + } + return false; + } + + const detail::json &dict = detail::GetValue(it); + + // Make sure we are dealing with an object / dictionary. + if (!detail::IsObject(dict)) { + if (required) { + if (err) { + (*err) += "'" + property + "' property is not an object.\n"; + } + } + return false; + } + + ret->clear(); + + detail::json_const_iterator dictIt(detail::ObjectBegin(dict)); + detail::json_const_iterator dictItEnd(detail::ObjectEnd(dict)); + + for (; dictIt != dictItEnd; ++dictIt) { + int intVal; + if (!detail::GetInt(detail::GetValue(dictIt), intVal)) { + if (required) { + if (err) { + (*err) += "'" + property + "' value is not an integer type.\n"; + } + } + return false; + } + + // Insert into the list. + (*ret)[detail::GetKey(dictIt)] = intVal; + } + return true; +} + +static bool ParseJSONProperty(std::map *ret, + std::string *err, const detail::json &o, + const std::string &property, bool required) { + detail::json_const_iterator it; + if (!detail::FindMember(o, property.c_str(), it)) { + if (required) { + if (err) { + (*err) += "'" + property + "' property is missing. \n'"; + } + } + return false; + } + + const detail::json &obj = detail::GetValue(it); + + if (!detail::IsObject(obj)) { + if (required) { + if (err) { + (*err) += "'" + property + "' property is not a JSON object.\n"; + } + } + return false; + } + + ret->clear(); + + detail::json_const_iterator it2(detail::ObjectBegin(obj)); + detail::json_const_iterator itEnd(detail::ObjectEnd(obj)); + for (; it2 != itEnd; ++it2) { + double numVal; + if (detail::GetNumber(detail::GetValue(it2), numVal)) + ret->emplace(std::string(detail::GetKey(it2)), numVal); + } + + return true; +} + +static bool ParseParameterProperty(Parameter *param, std::string *err, + const detail::json &o, + const std::string &prop, bool required) { + // A parameter value can either be a string or an array of either a boolean or + // a number. Booleans of any kind aren't supported here. Granted, it + // complicates the Parameter structure and breaks it semantically in the sense + // that the client probably works off the assumption that if the string is + // empty the vector is used, etc. Would a tagged union work? + if (ParseStringProperty(¶m->string_value, err, o, prop, false)) { + // Found string property. + return true; + } else if (ParseNumberArrayProperty(¶m->number_array, err, o, prop, + false)) { + // Found a number array. + return true; + } else if (ParseNumberProperty(¶m->number_value, err, o, prop, false)) { + param->has_number_value = true; + return true; + } else if (ParseJSONProperty(¶m->json_double_value, err, o, prop, + false)) { + return true; + } else if (ParseBooleanProperty(¶m->bool_value, err, o, prop, false)) { + return true; + } else { + if (required) { + if (err) { + (*err) += "parameter must be a string or number / number array.\n"; + } + } + return false; + } +} + +static bool ParseExtensionsProperty(ExtensionMap *ret, std::string *err, + const detail::json &o) { + (void)err; + + detail::json_const_iterator it; + if (!detail::FindMember(o, "extensions", it)) { + return false; + } + + auto &obj = detail::GetValue(it); + if (!detail::IsObject(obj)) { + return false; + } + ExtensionMap extensions; + detail::json_const_iterator extIt = + detail::ObjectBegin(obj); // it.value().begin(); + detail::json_const_iterator extEnd = detail::ObjectEnd(obj); + for (; extIt != extEnd; ++extIt) { + auto &itObj = detail::GetValue(extIt); + if (!detail::IsObject(itObj)) continue; + std::string key(detail::GetKey(extIt)); + if (!ParseJsonAsValue(&extensions[key], itObj)) { + if (!key.empty()) { + // create empty object so that an extension object is still of type + // object + extensions[key] = Value{Value::Object{}}; + } + } + } + if (ret) { + (*ret) = std::move(extensions); + } + return true; +} + +template +static bool ParseExtrasAndExtensions(GltfType *target, std::string *err, + const detail::json &o, + bool store_json_strings) { + ParseExtensionsProperty(&target->extensions, err, o); + ParseExtrasProperty(&target->extras, o); + + if (store_json_strings) { + { + detail::json_const_iterator it; + if (detail::FindMember(o, "extensions", it)) { + target->extensions_json_string = + detail::JsonToString(detail::GetValue(it)); + } + } + { + detail::json_const_iterator it; + if (detail::FindMember(o, "extras", it)) { + target->extras_json_string = detail::JsonToString(detail::GetValue(it)); + } + } + } + return true; +} + +static bool ParseAsset(Asset *asset, std::string *err, const detail::json &o, + bool store_original_json_for_extras_and_extensions) { + ParseStringProperty(&asset->version, err, o, "version", true, "Asset"); + ParseStringProperty(&asset->generator, err, o, "generator", false, "Asset"); + ParseStringProperty(&asset->minVersion, err, o, "minVersion", false, "Asset"); + ParseStringProperty(&asset->copyright, err, o, "copyright", false, "Asset"); + + ParseExtrasAndExtensions(asset, err, o, + store_original_json_for_extras_and_extensions); + return true; +} + +static bool ParseImage(Image *image, const int image_idx, std::string *err, + std::string *warn, const detail::json &o, + bool store_original_json_for_extras_and_extensions, + const std::string &basedir, const size_t max_file_size, + FsCallbacks *fs, const URICallbacks *uri_cb, + LoadImageDataFunction *LoadImageData = nullptr, + void *load_image_user_data = nullptr) { + // A glTF image must either reference a bufferView or an image uri + + // schema says oneOf [`bufferView`, `uri`] + // TODO(syoyo): Check the type of each parameters. + detail::json_const_iterator it; + bool hasBufferView = detail::FindMember(o, "bufferView", it); + bool hasURI = detail::FindMember(o, "uri", it); + + ParseStringProperty(&image->name, err, o, "name", false); + + if (hasBufferView && hasURI) { + // Should not both defined. + if (err) { + (*err) += + "Only one of `bufferView` or `uri` should be defined, but both are " + "defined for image[" + + std::to_string(image_idx) + "] name = \"" + image->name + "\"\n"; + } + return false; + } + + if (!hasBufferView && !hasURI) { + if (err) { + (*err) += "Neither required `bufferView` nor `uri` defined for image[" + + std::to_string(image_idx) + "] name = \"" + image->name + + "\"\n"; + } + return false; + } + + ParseExtrasAndExtensions(image, err, o, + store_original_json_for_extras_and_extensions); + + if (hasBufferView) { + int bufferView = -1; + if (!ParseIntegerProperty(&bufferView, err, o, "bufferView", true)) { + if (err) { + (*err) += "Failed to parse `bufferView` for image[" + + std::to_string(image_idx) + "] name = \"" + image->name + + "\"\n"; + } + return false; + } + + std::string mime_type; + ParseStringProperty(&mime_type, err, o, "mimeType", false); + + int width = 0; + ParseIntegerProperty(&width, err, o, "width", false); + + int height = 0; + ParseIntegerProperty(&height, err, o, "height", false); + + // Just only save some information here. Loading actual image data from + // bufferView is done after this `ParseImage` function. + image->bufferView = bufferView; + image->mimeType = mime_type; + image->width = width; + image->height = height; + + return true; + } + + // Parse URI & Load image data. + + std::string uri; + std::string tmp_err; + if (!ParseStringProperty(&uri, &tmp_err, o, "uri", true)) { + if (err) { + (*err) += "Failed to parse `uri` for image[" + std::to_string(image_idx) + + "] name = \"" + image->name + "\".\n"; + } + return false; + } + + std::vector img; + + if (IsDataURI(uri)) { + if (!DecodeDataURI(&img, image->mimeType, uri, 0, false)) { + if (err) { + (*err) += "Failed to decode 'uri' for image[" + + std::to_string(image_idx) + "] name = \"" + image->name + + "\"\n"; + } + return false; + } + } else { + // Assume external file + // Keep texture path (for textures that cannot be decoded) + image->uri = uri; +#ifdef TINYGLTF_NO_EXTERNAL_IMAGE + return true; +#else + std::string decoded_uri; + if (!uri_cb->decode(uri, &decoded_uri, uri_cb->user_data)) { + if (warn) { + (*warn) += "Failed to decode 'uri' for image[" + + std::to_string(image_idx) + "] name = \"" + image->name + + "\"\n"; + } + + // Image loading failure is not critical to overall gltf loading. + return true; + } + + if (!LoadExternalFile(&img, err, warn, decoded_uri, basedir, + /* required */ false, /* required bytes */ 0, + /* checksize */ false, + /* max file size */ max_file_size, fs)) { + if (warn) { + (*warn) += "Failed to load external 'uri' for image[" + + std::to_string(image_idx) + "] name = \"" + decoded_uri + + "\"\n"; + } + // If the image cannot be loaded, keep uri as image->uri. + return true; + } + + if (img.empty()) { + if (warn) { + (*warn) += "Image data is empty for image[" + + std::to_string(image_idx) + "] name = \"" + image->name + + "\" \n"; + } + return false; + } +#endif + } + + if (*LoadImageData == nullptr) { + if (err) { + (*err) += "No LoadImageData callback specified.\n"; + } + return false; + } + return (*LoadImageData)(image, image_idx, err, warn, 0, 0, &img.at(0), + static_cast(img.size()), load_image_user_data); +} + +static bool ParseTexture(Texture *texture, std::string *err, + const detail::json &o, + bool store_original_json_for_extras_and_extensions, + const std::string &basedir) { + (void)basedir; + int sampler = -1; + int source = -1; + ParseIntegerProperty(&sampler, err, o, "sampler", false); + + ParseIntegerProperty(&source, err, o, "source", false); + + texture->sampler = sampler; + texture->source = source; + + ParseExtrasAndExtensions(texture, err, o, + store_original_json_for_extras_and_extensions); + + ParseStringProperty(&texture->name, err, o, "name", false); + + return true; +} + +static bool ParseTextureInfo( + TextureInfo *texinfo, std::string *err, const detail::json &o, + bool store_original_json_for_extras_and_extensions) { + if (texinfo == nullptr) { + return false; + } + + if (!ParseIntegerProperty(&texinfo->index, err, o, "index", + /* required */ true, "TextureInfo")) { + return false; + } + + ParseIntegerProperty(&texinfo->texCoord, err, o, "texCoord", false); + + ParseExtrasAndExtensions(texinfo, err, o, + store_original_json_for_extras_and_extensions); + + return true; +} + +static bool ParseNormalTextureInfo( + NormalTextureInfo *texinfo, std::string *err, const detail::json &o, + bool store_original_json_for_extras_and_extensions) { + if (texinfo == nullptr) { + return false; + } + + if (!ParseIntegerProperty(&texinfo->index, err, o, "index", + /* required */ true, "NormalTextureInfo")) { + return false; + } + + ParseIntegerProperty(&texinfo->texCoord, err, o, "texCoord", false); + ParseNumberProperty(&texinfo->scale, err, o, "scale", false); + + ParseExtrasAndExtensions(texinfo, err, o, + store_original_json_for_extras_and_extensions); + + return true; +} + +static bool ParseOcclusionTextureInfo( + OcclusionTextureInfo *texinfo, std::string *err, const detail::json &o, + bool store_original_json_for_extras_and_extensions) { + if (texinfo == nullptr) { + return false; + } + + if (!ParseIntegerProperty(&texinfo->index, err, o, "index", + /* required */ true, "NormalTextureInfo")) { + return false; + } + + ParseIntegerProperty(&texinfo->texCoord, err, o, "texCoord", false); + ParseNumberProperty(&texinfo->strength, err, o, "strength", false); + + ParseExtrasAndExtensions(texinfo, err, o, + store_original_json_for_extras_and_extensions); + + return true; +} + +static bool ParseBuffer(Buffer *buffer, std::string *err, const detail::json &o, + bool store_original_json_for_extras_and_extensions, + FsCallbacks *fs, const URICallbacks *uri_cb, + const std::string &basedir, + const size_t max_buffer_size, bool is_binary = false, + const unsigned char *bin_data = nullptr, + size_t bin_size = 0) { + size_t byteLength; + if (!ParseUnsignedProperty(&byteLength, err, o, "byteLength", true, + "Buffer")) { + return false; + } + + // In glTF 2.0, uri is not mandatory anymore + buffer->uri.clear(); + ParseStringProperty(&buffer->uri, err, o, "uri", false, "Buffer"); + + // having an empty uri for a non embedded image should not be valid + if (!is_binary && buffer->uri.empty()) { + if (err) { + (*err) += "'uri' is missing from non binary glTF file buffer.\n"; + } + } + + detail::json_const_iterator type; + if (detail::FindMember(o, "type", type)) { + std::string typeStr; + if (detail::GetString(detail::GetValue(type), typeStr)) { + if (typeStr.compare("arraybuffer") == 0) { + // buffer.type = "arraybuffer"; + } + } + } + + if (is_binary) { + // Still binary glTF accepts external dataURI. + if (!buffer->uri.empty()) { + // First try embedded data URI. + if (IsDataURI(buffer->uri)) { + std::string mime_type; + if (!DecodeDataURI(&buffer->data, mime_type, buffer->uri, byteLength, + true)) { + if (err) { + (*err) += + "Failed to decode 'uri' : " + buffer->uri + " in Buffer\n"; + } + return false; + } + } else { + // External .bin file. + std::string decoded_uri; + if (!uri_cb->decode(buffer->uri, &decoded_uri, uri_cb->user_data)) { + return false; + } + if (!LoadExternalFile(&buffer->data, err, /* warn */ nullptr, + decoded_uri, basedir, /* required */ true, + byteLength, /* checkSize */ true, + /* max_file_size */ max_buffer_size, fs)) { + return false; + } + } + } else { + // load data from (embedded) binary data + + if ((bin_size == 0) || (bin_data == nullptr)) { + if (err) { + (*err) += + "Invalid binary data in `Buffer', or GLB with empty BIN chunk.\n"; + } + return false; + } + + if (byteLength > bin_size) { + if (err) { + std::stringstream ss; + ss << "Invalid `byteLength'. Must be equal or less than binary size: " + "`byteLength' = " + << byteLength << ", binary size = " << bin_size << std::endl; + (*err) += ss.str(); + } + return false; + } + + // Read buffer data + buffer->data.resize(static_cast(byteLength)); + memcpy(&(buffer->data.at(0)), bin_data, static_cast(byteLength)); + } + + } else { + if (IsDataURI(buffer->uri)) { + std::string mime_type; + if (!DecodeDataURI(&buffer->data, mime_type, buffer->uri, byteLength, + true)) { + if (err) { + (*err) += "Failed to decode 'uri' : " + buffer->uri + " in Buffer\n"; + } + return false; + } + } else { + // Assume external .bin file. + std::string decoded_uri; + if (!uri_cb->decode(buffer->uri, &decoded_uri, uri_cb->user_data)) { + return false; + } + if (!LoadExternalFile(&buffer->data, err, /* warn */ nullptr, decoded_uri, + basedir, /* required */ true, byteLength, + /* checkSize */ true, + /* max file size */ max_buffer_size, fs)) { + return false; + } + } + } + + ParseStringProperty(&buffer->name, err, o, "name", false); + + ParseExtrasAndExtensions(buffer, err, o, + store_original_json_for_extras_and_extensions); + + return true; +} + +static bool ParseBufferView( + BufferView *bufferView, std::string *err, const detail::json &o, + bool store_original_json_for_extras_and_extensions) { + int buffer = -1; + if (!ParseIntegerProperty(&buffer, err, o, "buffer", true, "BufferView")) { + return false; + } + + size_t byteOffset = 0; + ParseUnsignedProperty(&byteOffset, err, o, "byteOffset", false); + + size_t byteLength = 1; + if (!ParseUnsignedProperty(&byteLength, err, o, "byteLength", true, + "BufferView")) { + return false; + } + + size_t byteStride = 0; + if (!ParseUnsignedProperty(&byteStride, err, o, "byteStride", false)) { + // Spec says: When byteStride of referenced bufferView is not defined, it + // means that accessor elements are tightly packed, i.e., effective stride + // equals the size of the element. + // We cannot determine the actual byteStride until Accessor are parsed, thus + // set 0(= tightly packed) here(as done in OpenGL's VertexAttribPoiner) + byteStride = 0; + } + + if ((byteStride > 252) || ((byteStride % 4) != 0)) { + if (err) { + std::stringstream ss; + ss << "Invalid `byteStride' value. `byteStride' must be the multiple of " + "4 : " + << byteStride << std::endl; + + (*err) += ss.str(); + } + return false; + } + + int target = 0; + ParseIntegerProperty(&target, err, o, "target", false); + if ((target == TINYGLTF_TARGET_ARRAY_BUFFER) || + (target == TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER)) { + // OK + } else { + target = 0; + } + bufferView->target = target; + + ParseStringProperty(&bufferView->name, err, o, "name", false); + + ParseExtrasAndExtensions(bufferView, err, o, + store_original_json_for_extras_and_extensions); + + bufferView->buffer = buffer; + bufferView->byteOffset = byteOffset; + bufferView->byteLength = byteLength; + bufferView->byteStride = byteStride; + return true; +} + +static bool ParseSparseAccessor( + Accessor::Sparse *sparse, std::string *err, const detail::json &o, + bool store_original_json_for_extras_and_extensions) { + sparse->isSparse = true; + + int count = 0; + if (!ParseIntegerProperty(&count, err, o, "count", true, "SparseAccessor")) { + return false; + } + + ParseExtrasAndExtensions(sparse, err, o, + store_original_json_for_extras_and_extensions); + + detail::json_const_iterator indices_iterator; + detail::json_const_iterator values_iterator; + if (!detail::FindMember(o, "indices", indices_iterator)) { + (*err) = "the sparse object of this accessor doesn't have indices"; + return false; + } + + if (!detail::FindMember(o, "values", values_iterator)) { + (*err) = "the sparse object of this accessor doesn't have values"; + return false; + } + + const detail::json &indices_obj = detail::GetValue(indices_iterator); + const detail::json &values_obj = detail::GetValue(values_iterator); + + int indices_buffer_view = 0, component_type = 0; + size_t indices_byte_offset = 0; + if (!ParseIntegerProperty(&indices_buffer_view, err, indices_obj, + "bufferView", true, "SparseAccessor")) { + return false; + } + ParseUnsignedProperty(&indices_byte_offset, err, indices_obj, "byteOffset", + false); + if (!ParseIntegerProperty(&component_type, err, indices_obj, "componentType", + true, "SparseAccessor")) { + return false; + } + + int values_buffer_view = 0; + size_t values_byte_offset = 0; + if (!ParseIntegerProperty(&values_buffer_view, err, values_obj, "bufferView", + true, "SparseAccessor")) { + return false; + } + ParseUnsignedProperty(&values_byte_offset, err, values_obj, "byteOffset", + false); + + sparse->count = count; + sparse->indices.bufferView = indices_buffer_view; + sparse->indices.byteOffset = indices_byte_offset; + sparse->indices.componentType = component_type; + ParseExtrasAndExtensions(&sparse->indices, err, indices_obj, + store_original_json_for_extras_and_extensions); + + sparse->values.bufferView = values_buffer_view; + sparse->values.byteOffset = values_byte_offset; + ParseExtrasAndExtensions(&sparse->values, err, values_obj, + store_original_json_for_extras_and_extensions); + + return true; +} + +static bool ParseAccessor(Accessor *accessor, std::string *err, + const detail::json &o, + bool store_original_json_for_extras_and_extensions) { + int bufferView = -1; + ParseIntegerProperty(&bufferView, err, o, "bufferView", false, "Accessor"); + + size_t byteOffset = 0; + ParseUnsignedProperty(&byteOffset, err, o, "byteOffset", false, "Accessor"); + + bool normalized = false; + ParseBooleanProperty(&normalized, err, o, "normalized", false, "Accessor"); + + size_t componentType = 0; + if (!ParseUnsignedProperty(&componentType, err, o, "componentType", true, + "Accessor")) { + return false; + } + + size_t count = 0; + if (!ParseUnsignedProperty(&count, err, o, "count", true, "Accessor")) { + return false; + } + + std::string type; + if (!ParseStringProperty(&type, err, o, "type", true, "Accessor")) { + return false; + } + + if (type.compare("SCALAR") == 0) { + accessor->type = TINYGLTF_TYPE_SCALAR; + } else if (type.compare("VEC2") == 0) { + accessor->type = TINYGLTF_TYPE_VEC2; + } else if (type.compare("VEC3") == 0) { + accessor->type = TINYGLTF_TYPE_VEC3; + } else if (type.compare("VEC4") == 0) { + accessor->type = TINYGLTF_TYPE_VEC4; + } else if (type.compare("MAT2") == 0) { + accessor->type = TINYGLTF_TYPE_MAT2; + } else if (type.compare("MAT3") == 0) { + accessor->type = TINYGLTF_TYPE_MAT3; + } else if (type.compare("MAT4") == 0) { + accessor->type = TINYGLTF_TYPE_MAT4; + } else { + std::stringstream ss; + ss << "Unsupported `type` for accessor object. Got \"" << type << "\"\n"; + if (err) { + (*err) += ss.str(); + } + return false; + } + + ParseStringProperty(&accessor->name, err, o, "name", false); + + accessor->minValues.clear(); + accessor->maxValues.clear(); + ParseNumberArrayProperty(&accessor->minValues, err, o, "min", false, + "Accessor"); + + ParseNumberArrayProperty(&accessor->maxValues, err, o, "max", false, + "Accessor"); + + accessor->count = count; + accessor->bufferView = bufferView; + accessor->byteOffset = byteOffset; + accessor->normalized = normalized; + { + if (componentType >= TINYGLTF_COMPONENT_TYPE_BYTE && + componentType <= TINYGLTF_COMPONENT_TYPE_DOUBLE) { + // OK + accessor->componentType = int(componentType); + } else { + std::stringstream ss; + ss << "Invalid `componentType` in accessor. Got " << componentType + << "\n"; + if (err) { + (*err) += ss.str(); + } + return false; + } + } + + ParseExtrasAndExtensions(accessor, err, o, + store_original_json_for_extras_and_extensions); + + // check if accessor has a "sparse" object: + detail::json_const_iterator iterator; + if (detail::FindMember(o, "sparse", iterator)) { + // here this accessor has a "sparse" subobject + return ParseSparseAccessor(&accessor->sparse, err, + detail::GetValue(iterator), + store_original_json_for_extras_and_extensions); + } + + return true; +} + +#ifdef TINYGLTF_ENABLE_DRACO + +static void DecodeIndexBuffer(draco::Mesh *mesh, size_t componentSize, + std::vector &outBuffer) { + if (componentSize == 4) { + assert(sizeof(mesh->face(draco::FaceIndex(0))[0]) == componentSize); + memcpy(outBuffer.data(), &mesh->face(draco::FaceIndex(0))[0], + outBuffer.size()); + } else { + size_t faceStride = componentSize * 3; + for (draco::FaceIndex f(0); f < mesh->num_faces(); ++f) { + const draco::Mesh::Face &face = mesh->face(f); + if (componentSize == 2) { + uint16_t indices[3] = {(uint16_t)face[0].value(), + (uint16_t)face[1].value(), + (uint16_t)face[2].value()}; + memcpy(outBuffer.data() + f.value() * faceStride, &indices[0], + faceStride); + } else { + uint8_t indices[3] = {(uint8_t)face[0].value(), + (uint8_t)face[1].value(), + (uint8_t)face[2].value()}; + memcpy(outBuffer.data() + f.value() * faceStride, &indices[0], + faceStride); + } + } + } +} + +template +static bool GetAttributeForAllPoints(draco::Mesh *mesh, + const draco::PointAttribute *pAttribute, + std::vector &outBuffer) { + size_t byteOffset = 0; + T values[4] = {0, 0, 0, 0}; + for (draco::PointIndex i(0); i < mesh->num_points(); ++i) { + const draco::AttributeValueIndex val_index = pAttribute->mapped_index(i); + if (!pAttribute->ConvertValue(val_index, pAttribute->num_components(), + values)) + return false; + + memcpy(outBuffer.data() + byteOffset, &values[0], + sizeof(T) * pAttribute->num_components()); + byteOffset += sizeof(T) * pAttribute->num_components(); + } + + return true; +} + +static bool GetAttributeForAllPoints(uint32_t componentType, draco::Mesh *mesh, + const draco::PointAttribute *pAttribute, + std::vector &outBuffer) { + bool decodeResult = false; + switch (componentType) { + case TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE: + decodeResult = + GetAttributeForAllPoints(mesh, pAttribute, outBuffer); + break; + case TINYGLTF_COMPONENT_TYPE_BYTE: + decodeResult = + GetAttributeForAllPoints(mesh, pAttribute, outBuffer); + break; + case TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT: + decodeResult = + GetAttributeForAllPoints(mesh, pAttribute, outBuffer); + break; + case TINYGLTF_COMPONENT_TYPE_SHORT: + decodeResult = + GetAttributeForAllPoints(mesh, pAttribute, outBuffer); + break; + case TINYGLTF_COMPONENT_TYPE_INT: + decodeResult = + GetAttributeForAllPoints(mesh, pAttribute, outBuffer); + break; + case TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT: + decodeResult = + GetAttributeForAllPoints(mesh, pAttribute, outBuffer); + break; + case TINYGLTF_COMPONENT_TYPE_FLOAT: + decodeResult = + GetAttributeForAllPoints(mesh, pAttribute, outBuffer); + break; + case TINYGLTF_COMPONENT_TYPE_DOUBLE: + decodeResult = + GetAttributeForAllPoints(mesh, pAttribute, outBuffer); + break; + default: + return false; + } + + return decodeResult; +} + +static bool ParseDracoExtension(Primitive *primitive, Model *model, + std::string *err, std::string *warn, + const Value &dracoExtensionValue, + ParseStrictness strictness) { + (void)err; + auto bufferViewValue = dracoExtensionValue.Get("bufferView"); + if (!bufferViewValue.IsInt()) return false; + auto attributesValue = dracoExtensionValue.Get("attributes"); + if (!attributesValue.IsObject()) return false; + + auto attributesObject = attributesValue.Get(); + int bufferView = bufferViewValue.Get(); + + BufferView &view = model->bufferViews[bufferView]; + Buffer &buffer = model->buffers[view.buffer]; + // BufferView has already been decoded + if (view.dracoDecoded) return true; + view.dracoDecoded = true; + + const char *bufferViewData = + reinterpret_cast(buffer.data.data() + view.byteOffset); + size_t bufferViewSize = view.byteLength; + + // decode draco + draco::DecoderBuffer decoderBuffer; + decoderBuffer.Init(bufferViewData, bufferViewSize); + draco::Decoder decoder; + auto decodeResult = decoder.DecodeMeshFromBuffer(&decoderBuffer); + if (!decodeResult.ok()) { + return false; + } + const std::unique_ptr &mesh = decodeResult.value(); + + // create new bufferView for indices + if (primitive->indices >= 0) { + if (strictness == ParseStrictness::Permissive) { + const draco::PointIndex::ValueType numPoint = mesh->num_points(); + // handle the situation where the stored component type does not match the + // required type for the actual number of stored points + int supposedComponentType = TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE; + if (numPoint < static_cast( + std::numeric_limits::max())) { + supposedComponentType = TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE; + } else if ( + numPoint < static_cast( + std::numeric_limits::max())) { + supposedComponentType = TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT; + } else { + supposedComponentType = TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT; + } + + if (supposedComponentType > model->accessors[primitive->indices].componentType) { + if (warn) { + (*warn) += + "GLTF component type " + std::to_string(model->accessors[primitive->indices].componentType) + + " is not sufficient for number of stored points," + " treating as " + std::to_string(supposedComponentType) + "\n"; + } + model->accessors[primitive->indices].componentType = supposedComponentType; + } + } + + int32_t componentSize = GetComponentSizeInBytes( + model->accessors[primitive->indices].componentType); + Buffer decodedIndexBuffer; + decodedIndexBuffer.data.resize(mesh->num_faces() * 3 * componentSize); + + DecodeIndexBuffer(mesh.get(), componentSize, decodedIndexBuffer.data); + + model->buffers.emplace_back(std::move(decodedIndexBuffer)); + + BufferView decodedIndexBufferView; + decodedIndexBufferView.buffer = int(model->buffers.size() - 1); + decodedIndexBufferView.byteLength = + int(mesh->num_faces() * 3 * componentSize); + decodedIndexBufferView.byteOffset = 0; + decodedIndexBufferView.byteStride = 0; + decodedIndexBufferView.target = TINYGLTF_TARGET_ARRAY_BUFFER; + model->bufferViews.emplace_back(std::move(decodedIndexBufferView)); + + model->accessors[primitive->indices].bufferView = + int(model->bufferViews.size() - 1); + model->accessors[primitive->indices].count = int(mesh->num_faces() * 3); + } + + for (const auto &attribute : attributesObject) { + if (!attribute.second.IsInt()) return false; + auto primitiveAttribute = primitive->attributes.find(attribute.first); + if (primitiveAttribute == primitive->attributes.end()) return false; + + int dracoAttributeIndex = attribute.second.Get(); + const auto pAttribute = mesh->GetAttributeByUniqueId(dracoAttributeIndex); + const auto componentType = + model->accessors[primitiveAttribute->second].componentType; + + // Create a new buffer for this decoded buffer + Buffer decodedBuffer; + size_t bufferSize = mesh->num_points() * pAttribute->num_components() * + GetComponentSizeInBytes(componentType); + decodedBuffer.data.resize(bufferSize); + + if (!GetAttributeForAllPoints(componentType, mesh.get(), pAttribute, + decodedBuffer.data)) + return false; + + model->buffers.emplace_back(std::move(decodedBuffer)); + + BufferView decodedBufferView; + decodedBufferView.buffer = int(model->buffers.size() - 1); + decodedBufferView.byteLength = bufferSize; + decodedBufferView.byteOffset = pAttribute->byte_offset(); + decodedBufferView.byteStride = pAttribute->byte_stride(); + decodedBufferView.target = primitive->indices >= 0 + ? TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER + : TINYGLTF_TARGET_ARRAY_BUFFER; + model->bufferViews.emplace_back(std::move(decodedBufferView)); + + model->accessors[primitiveAttribute->second].bufferView = + int(model->bufferViews.size() - 1); + model->accessors[primitiveAttribute->second].count = + int(mesh->num_points()); + } + + return true; +} +#endif + +static bool ParsePrimitive(Primitive *primitive, Model *model, + std::string *err, std::string *warn, + const detail::json &o, + bool store_original_json_for_extras_and_extensions, + ParseStrictness strictness) { + int material = -1; + ParseIntegerProperty(&material, err, o, "material", false); + primitive->material = material; + + int mode = TINYGLTF_MODE_TRIANGLES; + ParseIntegerProperty(&mode, err, o, "mode", false); + primitive->mode = mode; // Why only triangles were supported ? + + int indices = -1; + ParseIntegerProperty(&indices, err, o, "indices", false); + primitive->indices = indices; + if (!ParseStringIntegerProperty(&primitive->attributes, err, o, "attributes", + true, "Primitive")) { + return false; + } + + // Look for morph targets + detail::json_const_iterator targetsObject; + if (detail::FindMember(o, "targets", targetsObject) && + detail::IsArray(detail::GetValue(targetsObject))) { + auto targetsObjectEnd = detail::ArrayEnd(detail::GetValue(targetsObject)); + for (detail::json_const_array_iterator i = + detail::ArrayBegin(detail::GetValue(targetsObject)); + i != targetsObjectEnd; ++i) { + std::map targetAttribues; + + const detail::json &dict = *i; + if (detail::IsObject(dict)) { + detail::json_const_iterator dictIt(detail::ObjectBegin(dict)); + detail::json_const_iterator dictItEnd(detail::ObjectEnd(dict)); + + for (; dictIt != dictItEnd; ++dictIt) { + int iVal; + if (detail::GetInt(detail::GetValue(dictIt), iVal)) + targetAttribues[detail::GetKey(dictIt)] = iVal; + } + primitive->targets.emplace_back(std::move(targetAttribues)); + } + } + } + + ParseExtrasAndExtensions(primitive, err, o, + store_original_json_for_extras_and_extensions); + +#ifdef TINYGLTF_ENABLE_DRACO + auto dracoExtension = + primitive->extensions.find("KHR_draco_mesh_compression"); + if (dracoExtension != primitive->extensions.end()) { + ParseDracoExtension(primitive, model, err, warn, dracoExtension->second, strictness); + } +#else + (void)model; + (void)warn; + (void)strictness; +#endif + + return true; +} + +static bool ParseMesh(Mesh *mesh, Model *model, + std::string *err, std::string *warn, + const detail::json &o, + bool store_original_json_for_extras_and_extensions, + ParseStrictness strictness) { + ParseStringProperty(&mesh->name, err, o, "name", false); + + mesh->primitives.clear(); + detail::json_const_iterator primObject; + if (detail::FindMember(o, "primitives", primObject) && + detail::IsArray(detail::GetValue(primObject))) { + detail::json_const_array_iterator primEnd = + detail::ArrayEnd(detail::GetValue(primObject)); + for (detail::json_const_array_iterator i = + detail::ArrayBegin(detail::GetValue(primObject)); + i != primEnd; ++i) { + Primitive primitive; + if (ParsePrimitive(&primitive, model, err, warn, *i, + store_original_json_for_extras_and_extensions, + strictness)) { + // Only add the primitive if the parsing succeeds. + mesh->primitives.emplace_back(std::move(primitive)); + } + } + } + + // Should probably check if has targets and if dimensions fit + ParseNumberArrayProperty(&mesh->weights, err, o, "weights", false); + + ParseExtrasAndExtensions(mesh, err, o, + store_original_json_for_extras_and_extensions); + + return true; +} + +static bool ParseNode(Node *node, std::string *err, const detail::json &o, + bool store_original_json_for_extras_and_extensions) { + ParseStringProperty(&node->name, err, o, "name", false); + + int skin = -1; + ParseIntegerProperty(&skin, err, o, "skin", false); + node->skin = skin; + + // Matrix and T/R/S are exclusive + if (!ParseNumberArrayProperty(&node->matrix, err, o, "matrix", false)) { + ParseNumberArrayProperty(&node->rotation, err, o, "rotation", false); + ParseNumberArrayProperty(&node->scale, err, o, "scale", false); + ParseNumberArrayProperty(&node->translation, err, o, "translation", false); + } + + int camera = -1; + ParseIntegerProperty(&camera, err, o, "camera", false); + node->camera = camera; + + int mesh = -1; + ParseIntegerProperty(&mesh, err, o, "mesh", false); + node->mesh = mesh; + + node->children.clear(); + ParseIntegerArrayProperty(&node->children, err, o, "children", false); + + ParseNumberArrayProperty(&node->weights, err, o, "weights", false); + + ParseExtrasAndExtensions(node, err, o, + store_original_json_for_extras_and_extensions); + + // KHR_lights_punctual: parse light source reference + int light = -1; + if (node->extensions.count("KHR_lights_punctual") != 0) { + auto const &light_ext = node->extensions["KHR_lights_punctual"]; + if (light_ext.Has("light")) { + light = light_ext.Get("light").GetNumberAsInt(); + } else { + if (err) { + *err += + "Node has extension KHR_lights_punctual, but does not reference " + "a light source.\n"; + } + return false; + } + } + node->light = light; + + // KHR_audio: parse audio source reference + int emitter = -1; + if (node->extensions.count("KHR_audio") != 0) { + auto const &audio_ext = node->extensions["KHR_audio"]; + if (audio_ext.Has("emitter")) { + emitter = audio_ext.Get("emitter").GetNumberAsInt(); + } else { + if (err) { + *err += + "Node has extension KHR_audio, but does not reference " + "a audio emitter.\n"; + } + return false; + } + } + node->emitter = emitter; + + return true; +} + +static bool ParseScene(Scene *scene, std::string *err, const detail::json &o, + bool store_original_json_for_extras_and_extensions) { + ParseStringProperty(&scene->name, err, o, "name", false); + ParseIntegerArrayProperty(&scene->nodes, err, o, "nodes", false); + + ParseExtrasAndExtensions(scene, err, o, + store_original_json_for_extras_and_extensions); + + // Parse KHR_audio global emitters + if (scene->extensions.count("KHR_audio") != 0) { + auto const &audio_ext = scene->extensions["KHR_audio"]; + if (audio_ext.Has("emitters")) { + auto emittersArr = audio_ext.Get("emitters"); + for (size_t i = 0; i < emittersArr.ArrayLen(); ++i) { + scene->audioEmitters.emplace_back(emittersArr.Get(i).GetNumberAsInt()); + } + } else { + if (err) { + *err += + "Node has extension KHR_audio, but does not reference " + "a audio emitter.\n"; + } + return false; + } + } + + return true; +} + +static bool ParsePbrMetallicRoughness( + PbrMetallicRoughness *pbr, std::string *err, const detail::json &o, + bool store_original_json_for_extras_and_extensions) { + if (pbr == nullptr) { + return false; + } + + std::vector baseColorFactor; + if (ParseNumberArrayProperty(&baseColorFactor, err, o, "baseColorFactor", + /* required */ false)) { + if (baseColorFactor.size() != 4) { + if (err) { + (*err) += + "Array length of `baseColorFactor` parameter in " + "pbrMetallicRoughness must be 4, but got " + + std::to_string(baseColorFactor.size()) + "\n"; + } + return false; + } + pbr->baseColorFactor = baseColorFactor; + } + + { + detail::json_const_iterator it; + if (detail::FindMember(o, "baseColorTexture", it)) { + ParseTextureInfo(&pbr->baseColorTexture, err, detail::GetValue(it), + store_original_json_for_extras_and_extensions); + } + } + + { + detail::json_const_iterator it; + if (detail::FindMember(o, "metallicRoughnessTexture", it)) { + ParseTextureInfo(&pbr->metallicRoughnessTexture, err, + detail::GetValue(it), + store_original_json_for_extras_and_extensions); + } + } + + ParseNumberProperty(&pbr->metallicFactor, err, o, "metallicFactor", false); + ParseNumberProperty(&pbr->roughnessFactor, err, o, "roughnessFactor", false); + + ParseExtrasAndExtensions(pbr, err, o, + store_original_json_for_extras_and_extensions); + + return true; +} + +static bool ParseMaterial(Material *material, std::string *err, std::string *warn, + const detail::json &o, + bool store_original_json_for_extras_and_extensions, + ParseStrictness strictness) { + ParseStringProperty(&material->name, err, o, "name", /* required */ false); + + if (ParseNumberArrayProperty(&material->emissiveFactor, err, o, + "emissiveFactor", + /* required */ false)) { + if (strictness==ParseStrictness::Permissive && material->emissiveFactor.size() == 4) { + if (warn) { + (*warn) += + "Array length of `emissiveFactor` parameter in " + "material must be 3, but got 4\n"; + } + material->emissiveFactor.resize(3); + } + else if (material->emissiveFactor.size() != 3) { + if (err) { + (*err) += + "Array length of `emissiveFactor` parameter in " + "material must be 3, but got " + + std::to_string(material->emissiveFactor.size()) + "\n"; + } + return false; + } + } else { + // fill with default values + material->emissiveFactor = {0.0, 0.0, 0.0}; + } + + ParseStringProperty(&material->alphaMode, err, o, "alphaMode", + /* required */ false); + ParseNumberProperty(&material->alphaCutoff, err, o, "alphaCutoff", + /* required */ false); + ParseBooleanProperty(&material->doubleSided, err, o, "doubleSided", + /* required */ false); + + { + detail::json_const_iterator it; + if (detail::FindMember(o, "pbrMetallicRoughness", it)) { + ParsePbrMetallicRoughness(&material->pbrMetallicRoughness, err, + detail::GetValue(it), + store_original_json_for_extras_and_extensions); + } + } + + { + detail::json_const_iterator it; + if (detail::FindMember(o, "normalTexture", it)) { + ParseNormalTextureInfo(&material->normalTexture, err, + detail::GetValue(it), + store_original_json_for_extras_and_extensions); + } + } + + { + detail::json_const_iterator it; + if (detail::FindMember(o, "occlusionTexture", it)) { + ParseOcclusionTextureInfo(&material->occlusionTexture, err, + detail::GetValue(it), + store_original_json_for_extras_and_extensions); + } + } + + { + detail::json_const_iterator it; + if (detail::FindMember(o, "emissiveTexture", it)) { + ParseTextureInfo(&material->emissiveTexture, err, detail::GetValue(it), + store_original_json_for_extras_and_extensions); + } + } + + // Old code path. For backward compatibility, we still store material values + // as Parameter. This will create duplicated information for + // example(pbrMetallicRoughness), but should be negligible in terms of memory + // consumption. + // TODO(syoyo): Remove in the next major release. + material->values.clear(); + material->additionalValues.clear(); + + detail::json_const_iterator it(detail::ObjectBegin(o)); + detail::json_const_iterator itEnd(detail::ObjectEnd(o)); + + for (; it != itEnd; ++it) { + std::string key(detail::GetKey(it)); + if (key == "pbrMetallicRoughness") { + if (detail::IsObject(detail::GetValue(it))) { + const detail::json &values_object = detail::GetValue(it); + + detail::json_const_iterator itVal(detail::ObjectBegin(values_object)); + detail::json_const_iterator itValEnd(detail::ObjectEnd(values_object)); + + for (; itVal != itValEnd; ++itVal) { + Parameter param; + if (ParseParameterProperty(¶m, err, values_object, + detail::GetKey(itVal), false)) { + material->values.emplace(detail::GetKey(itVal), std::move(param)); + } + } + } + } else if (key == "extensions" || key == "extras") { + // done later, skip, otherwise poorly parsed contents will be saved in the + // parametermap and serialized again later + } else { + Parameter param; + if (ParseParameterProperty(¶m, err, o, key, false)) { + // names of materials have already been parsed. Putting it in this map + // doesn't correctly reflect the glTF specification + if (key != "name") + material->additionalValues.emplace(std::move(key), std::move(param)); + } + } + } + + material->extensions.clear(); // Note(agnat): Why? + ParseExtrasAndExtensions(material, err, o, + store_original_json_for_extras_and_extensions); + + return true; +} + +static bool ParseAnimationChannel( + AnimationChannel *channel, std::string *err, const detail::json &o, + bool store_original_json_for_extras_and_extensions) { + int samplerIndex = -1; + int targetIndex = -1; + if (!ParseIntegerProperty(&samplerIndex, err, o, "sampler", true, + "AnimationChannel")) { + if (err) { + (*err) += "`sampler` field is missing in animation channels\n"; + } + return false; + } + + detail::json_const_iterator targetIt; + if (detail::FindMember(o, "target", targetIt) && + detail::IsObject(detail::GetValue(targetIt))) { + const detail::json &target_object = detail::GetValue(targetIt); + + ParseIntegerProperty(&targetIndex, err, target_object, "node", false); + + if (!ParseStringProperty(&channel->target_path, err, target_object, "path", + true)) { + if (err) { + (*err) += "`path` field is missing in animation.channels.target\n"; + } + return false; + } + ParseExtensionsProperty(&channel->target_extensions, err, target_object); + ParseExtrasProperty(&channel->target_extras, target_object); + if (store_original_json_for_extras_and_extensions) { + { + detail::json_const_iterator it; + if (detail::FindMember(target_object, "extensions", it)) { + channel->target_extensions_json_string = + detail::JsonToString(detail::GetValue(it)); + } + } + { + detail::json_const_iterator it; + if (detail::FindMember(target_object, "extras", it)) { + channel->target_extras_json_string = + detail::JsonToString(detail::GetValue(it)); + } + } + } + } + + channel->sampler = samplerIndex; + channel->target_node = targetIndex; + + ParseExtrasAndExtensions(channel, err, o, + store_original_json_for_extras_and_extensions); + + return true; +} + +static bool ParseAnimation(Animation *animation, std::string *err, + const detail::json &o, + bool store_original_json_for_extras_and_extensions) { + { + detail::json_const_iterator channelsIt; + if (detail::FindMember(o, "channels", channelsIt) && + detail::IsArray(detail::GetValue(channelsIt))) { + detail::json_const_array_iterator channelEnd = + detail::ArrayEnd(detail::GetValue(channelsIt)); + for (detail::json_const_array_iterator i = + detail::ArrayBegin(detail::GetValue(channelsIt)); + i != channelEnd; ++i) { + AnimationChannel channel; + if (ParseAnimationChannel( + &channel, err, *i, + store_original_json_for_extras_and_extensions)) { + // Only add the channel if the parsing succeeds. + animation->channels.emplace_back(std::move(channel)); + } + } + } + } + + { + detail::json_const_iterator samplerIt; + if (detail::FindMember(o, "samplers", samplerIt) && + detail::IsArray(detail::GetValue(samplerIt))) { + const detail::json &sampler_array = detail::GetValue(samplerIt); + + detail::json_const_array_iterator it = detail::ArrayBegin(sampler_array); + detail::json_const_array_iterator itEnd = detail::ArrayEnd(sampler_array); + + for (; it != itEnd; ++it) { + const detail::json &s = *it; + + AnimationSampler sampler; + int inputIndex = -1; + int outputIndex = -1; + if (!ParseIntegerProperty(&inputIndex, err, s, "input", true)) { + if (err) { + (*err) += "`input` field is missing in animation.sampler\n"; + } + return false; + } + ParseStringProperty(&sampler.interpolation, err, s, "interpolation", + false); + if (!ParseIntegerProperty(&outputIndex, err, s, "output", true)) { + if (err) { + (*err) += "`output` field is missing in animation.sampler\n"; + } + return false; + } + sampler.input = inputIndex; + sampler.output = outputIndex; + ParseExtrasAndExtensions(&sampler, err, o, + store_original_json_for_extras_and_extensions); + + animation->samplers.emplace_back(std::move(sampler)); + } + } + } + + ParseStringProperty(&animation->name, err, o, "name", false); + + ParseExtrasAndExtensions(animation, err, o, + store_original_json_for_extras_and_extensions); + + return true; +} + +static bool ParseSampler(Sampler *sampler, std::string *err, + const detail::json &o, + bool store_original_json_for_extras_and_extensions) { + ParseStringProperty(&sampler->name, err, o, "name", false); + + int minFilter = -1; + int magFilter = -1; + int wrapS = TINYGLTF_TEXTURE_WRAP_REPEAT; + int wrapT = TINYGLTF_TEXTURE_WRAP_REPEAT; + // int wrapR = TINYGLTF_TEXTURE_WRAP_REPEAT; + ParseIntegerProperty(&minFilter, err, o, "minFilter", false); + ParseIntegerProperty(&magFilter, err, o, "magFilter", false); + ParseIntegerProperty(&wrapS, err, o, "wrapS", false); + ParseIntegerProperty(&wrapT, err, o, "wrapT", false); + // ParseIntegerProperty(&wrapR, err, o, "wrapR", false); // tinygltf + // extension + + // TODO(syoyo): Check the value is allowed one. + // (e.g. we allow 9728(NEAREST), but don't allow 9727) + + sampler->minFilter = minFilter; + sampler->magFilter = magFilter; + sampler->wrapS = wrapS; + sampler->wrapT = wrapT; + // sampler->wrapR = wrapR; + + ParseExtrasAndExtensions(sampler, err, o, + store_original_json_for_extras_and_extensions); + + return true; +} + +static bool ParseSkin(Skin *skin, std::string *err, const detail::json &o, + bool store_original_json_for_extras_and_extensions) { + ParseStringProperty(&skin->name, err, o, "name", false, "Skin"); + + std::vector joints; + if (!ParseIntegerArrayProperty(&joints, err, o, "joints", false, "Skin")) { + return false; + } + skin->joints = std::move(joints); + + int skeleton = -1; + ParseIntegerProperty(&skeleton, err, o, "skeleton", false, "Skin"); + skin->skeleton = skeleton; + + int invBind = -1; + ParseIntegerProperty(&invBind, err, o, "inverseBindMatrices", true, "Skin"); + skin->inverseBindMatrices = invBind; + + ParseExtrasAndExtensions(skin, err, o, + store_original_json_for_extras_and_extensions); + + return true; +} + +static bool ParsePerspectiveCamera( + PerspectiveCamera *camera, std::string *err, const detail::json &o, + bool store_original_json_for_extras_and_extensions) { + double yfov = 0.0; + if (!ParseNumberProperty(&yfov, err, o, "yfov", true, "OrthographicCamera")) { + return false; + } + + double znear = 0.0; + if (!ParseNumberProperty(&znear, err, o, "znear", true, + "PerspectiveCamera")) { + return false; + } + + double aspectRatio = 0.0; // = invalid + ParseNumberProperty(&aspectRatio, err, o, "aspectRatio", false, + "PerspectiveCamera"); + + double zfar = 0.0; // = invalid + ParseNumberProperty(&zfar, err, o, "zfar", false, "PerspectiveCamera"); + + camera->aspectRatio = aspectRatio; + camera->zfar = zfar; + camera->yfov = yfov; + camera->znear = znear; + + ParseExtrasAndExtensions(camera, err, o, + store_original_json_for_extras_and_extensions); + + // TODO(syoyo): Validate parameter values. + + return true; +} + +static bool ParseSpotLight(SpotLight *light, std::string *err, + const detail::json &o, + bool store_original_json_for_extras_and_extensions) { + ParseNumberProperty(&light->innerConeAngle, err, o, "innerConeAngle", false); + ParseNumberProperty(&light->outerConeAngle, err, o, "outerConeAngle", false); + + ParseExtrasAndExtensions(light, err, o, + store_original_json_for_extras_and_extensions); + + // TODO(syoyo): Validate parameter values. + + return true; +} + +static bool ParseOrthographicCamera( + OrthographicCamera *camera, std::string *err, const detail::json &o, + bool store_original_json_for_extras_and_extensions) { + double xmag = 0.0; + if (!ParseNumberProperty(&xmag, err, o, "xmag", true, "OrthographicCamera")) { + return false; + } + + double ymag = 0.0; + if (!ParseNumberProperty(&ymag, err, o, "ymag", true, "OrthographicCamera")) { + return false; + } + + double zfar = 0.0; + if (!ParseNumberProperty(&zfar, err, o, "zfar", true, "OrthographicCamera")) { + return false; + } + + double znear = 0.0; + if (!ParseNumberProperty(&znear, err, o, "znear", true, + "OrthographicCamera")) { + return false; + } + + ParseExtrasAndExtensions(camera, err, o, + store_original_json_for_extras_and_extensions); + + camera->xmag = xmag; + camera->ymag = ymag; + camera->zfar = zfar; + camera->znear = znear; + + // TODO(syoyo): Validate parameter values. + + return true; +} + +static bool ParseCamera(Camera *camera, std::string *err, const detail::json &o, + bool store_original_json_for_extras_and_extensions) { + if (!ParseStringProperty(&camera->type, err, o, "type", true, "Camera")) { + return false; + } + + if (camera->type.compare("orthographic") == 0) { + detail::json_const_iterator orthoIt; + if (!detail::FindMember(o, "orthographic", orthoIt)) { + if (err) { + std::stringstream ss; + ss << "Orthographic camera description not found." << std::endl; + (*err) += ss.str(); + } + return false; + } + + const detail::json &v = detail::GetValue(orthoIt); + if (!detail::IsObject(v)) { + if (err) { + std::stringstream ss; + ss << "\"orthographic\" is not a JSON object." << std::endl; + (*err) += ss.str(); + } + return false; + } + + if (!ParseOrthographicCamera( + &camera->orthographic, err, v, + store_original_json_for_extras_and_extensions)) { + return false; + } + } else if (camera->type.compare("perspective") == 0) { + detail::json_const_iterator perspIt; + if (!detail::FindMember(o, "perspective", perspIt)) { + if (err) { + std::stringstream ss; + ss << "Perspective camera description not found." << std::endl; + (*err) += ss.str(); + } + return false; + } + + const detail::json &v = detail::GetValue(perspIt); + if (!detail::IsObject(v)) { + if (err) { + std::stringstream ss; + ss << "\"perspective\" is not a JSON object." << std::endl; + (*err) += ss.str(); + } + return false; + } + + if (!ParsePerspectiveCamera( + &camera->perspective, err, v, + store_original_json_for_extras_and_extensions)) { + return false; + } + } else { + if (err) { + std::stringstream ss; + ss << "Invalid camera type: \"" << camera->type + << "\". Must be \"perspective\" or \"orthographic\"" << std::endl; + (*err) += ss.str(); + } + return false; + } + + ParseStringProperty(&camera->name, err, o, "name", false); + + ParseExtrasAndExtensions(camera, err, o, + store_original_json_for_extras_and_extensions); + + return true; +} + +static bool ParseLight(Light *light, std::string *err, const detail::json &o, + bool store_original_json_for_extras_and_extensions) { + if (!ParseStringProperty(&light->type, err, o, "type", true)) { + return false; + } + + if (light->type == "spot") { + detail::json_const_iterator spotIt; + if (!detail::FindMember(o, "spot", spotIt)) { + if (err) { + std::stringstream ss; + ss << "Spot light description not found." << std::endl; + (*err) += ss.str(); + } + return false; + } + + const detail::json &v = detail::GetValue(spotIt); + if (!detail::IsObject(v)) { + if (err) { + std::stringstream ss; + ss << "\"spot\" is not a JSON object." << std::endl; + (*err) += ss.str(); + } + return false; + } + + if (!ParseSpotLight(&light->spot, err, v, + store_original_json_for_extras_and_extensions)) { + return false; + } + } + + ParseStringProperty(&light->name, err, o, "name", false); + ParseNumberArrayProperty(&light->color, err, o, "color", false); + ParseNumberProperty(&light->range, err, o, "range", false); + ParseNumberProperty(&light->intensity, err, o, "intensity", false); + + ParseExtrasAndExtensions(light, err, o, + store_original_json_for_extras_and_extensions); + + return true; +} + +static bool ParsePositionalEmitter( + PositionalEmitter *positional, std::string *err, const detail::json &o, + bool store_original_json_for_extras_and_extensions) { + ParseNumberProperty(&positional->coneInnerAngle, err, o, "coneInnerAngle", + false); + ParseNumberProperty(&positional->coneOuterAngle, err, o, "coneOuterAngle", + false); + ParseNumberProperty(&positional->coneOuterGain, err, o, "coneOuterGain", + false); + ParseNumberProperty(&positional->maxDistance, err, o, "maxDistance", false); + ParseNumberProperty(&positional->refDistance, err, o, "refDistance", false); + ParseNumberProperty(&positional->rolloffFactor, err, o, "rolloffFactor", + false); + + ParseExtrasAndExtensions(positional, err, o, + store_original_json_for_extras_and_extensions); + + return true; +} + +static bool ParseAudioEmitter( + AudioEmitter *emitter, std::string *err, const detail::json &o, + bool store_original_json_for_extras_and_extensions) { + if (!ParseStringProperty(&emitter->type, err, o, "type", true)) { + return false; + } + + if (emitter->type == "positional") { + detail::json_const_iterator positionalIt; + if (!detail::FindMember(o, "positional", positionalIt)) { + if (err) { + std::stringstream ss; + ss << "Positional emitter description not found." << std::endl; + (*err) += ss.str(); + } + return false; + } + + const detail::json &v = detail::GetValue(positionalIt); + if (!detail::IsObject(v)) { + if (err) { + std::stringstream ss; + ss << "\"positional\" is not a JSON object." << std::endl; + (*err) += ss.str(); + } + return false; + } + + if (!ParsePositionalEmitter( + &emitter->positional, err, v, + store_original_json_for_extras_and_extensions)) { + return false; + } + } + + ParseStringProperty(&emitter->name, err, o, "name", false); + ParseNumberProperty(&emitter->gain, err, o, "gain", false); + ParseBooleanProperty(&emitter->loop, err, o, "loop", false); + ParseBooleanProperty(&emitter->playing, err, o, "playing", false); + ParseStringProperty(&emitter->distanceModel, err, o, "distanceModel", false); + ParseIntegerProperty(&emitter->source, err, o, "source", true); + + ParseExtrasAndExtensions(emitter, err, o, + store_original_json_for_extras_and_extensions); + + return true; +} + +static bool ParseAudioSource( + AudioSource *source, std::string *err, const detail::json &o, + bool store_original_json_for_extras_and_extensions) { + ParseStringProperty(&source->name, err, o, "name", false); + ParseStringProperty(&source->uri, err, o, "uri", false); + + if (source->uri.empty()) { + ParseIntegerProperty(&source->bufferView, err, o, "bufferView", true); + ParseStringProperty(&source->mimeType, err, o, "mimeType", true); + } + + ParseExtrasAndExtensions(source, err, o, + store_original_json_for_extras_and_extensions); + + return true; +} + +namespace detail { + +template +bool ForEachInArray(const detail::json &_v, const char *member, Callback &&cb) { + detail::json_const_iterator itm; + if (detail::FindMember(_v, member, itm) && + detail::IsArray(detail::GetValue(itm))) { + const detail::json &root = detail::GetValue(itm); + auto it = detail::ArrayBegin(root); + auto end = detail::ArrayEnd(root); + for (; it != end; ++it) { + if (!cb(*it)) return false; + } + } + return true; +}; + +} // end of namespace detail + +bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn, + const char *json_str, + unsigned int json_str_length, + const std::string &base_dir, + unsigned int check_sections) { + if (json_str_length < 4) { + if (err) { + (*err) = "JSON string too short.\n"; + } + return false; + } + + detail::JsonDocument v; + +#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || \ + defined(_CPPUNWIND)) && \ + !defined(TINYGLTF_NOEXCEPTION) + try { + detail::JsonParse(v, json_str, json_str_length, true); + + } catch (const std::exception &e) { + if (err) { + (*err) = e.what(); + } + return false; + } +#else + { + detail::JsonParse(v, json_str, json_str_length); + + if (!detail::IsObject(v)) { + // Assume parsing was failed. + if (err) { + (*err) = "Failed to parse JSON object\n"; + } + return false; + } + } +#endif + + if (!detail::IsObject(v)) { + // root is not an object. + if (err) { + (*err) = "Root element is not a JSON object\n"; + } + return false; + } + + { + bool version_found = false; + detail::json_const_iterator it; + if (detail::FindMember(v, "asset", it) && + detail::IsObject(detail::GetValue(it))) { + auto &itObj = detail::GetValue(it); + detail::json_const_iterator version_it; + std::string versionStr; + if (detail::FindMember(itObj, "version", version_it) && + detail::GetString(detail::GetValue(version_it), versionStr)) { + version_found = true; + } + } + if (version_found) { + // OK + } else if (check_sections & REQUIRE_VERSION) { + if (err) { + (*err) += "\"asset\" object not found in .gltf or not an object type\n"; + } + return false; + } + } + + // scene is not mandatory. + // FIXME Maybe a better way to handle it than removing the code + + auto IsArrayMemberPresent = [](const detail::json &_v, + const char *name) -> bool { + detail::json_const_iterator it; + return detail::FindMember(_v, name, it) && + detail::IsArray(detail::GetValue(it)); + }; + + { + if ((check_sections & REQUIRE_SCENES) && + !IsArrayMemberPresent(v, "scenes")) { + if (err) { + (*err) += "\"scenes\" object not found in .gltf or not an array type\n"; + } + return false; + } + } + + { + if ((check_sections & REQUIRE_NODES) && !IsArrayMemberPresent(v, "nodes")) { + if (err) { + (*err) += "\"nodes\" object not found in .gltf\n"; + } + return false; + } + } + + { + if ((check_sections & REQUIRE_ACCESSORS) && + !IsArrayMemberPresent(v, "accessors")) { + if (err) { + (*err) += "\"accessors\" object not found in .gltf\n"; + } + return false; + } + } + + { + if ((check_sections & REQUIRE_BUFFERS) && + !IsArrayMemberPresent(v, "buffers")) { + if (err) { + (*err) += "\"buffers\" object not found in .gltf\n"; + } + return false; + } + } + + { + if ((check_sections & REQUIRE_BUFFER_VIEWS) && + !IsArrayMemberPresent(v, "bufferViews")) { + if (err) { + (*err) += "\"bufferViews\" object not found in .gltf\n"; + } + return false; + } + } + + model->buffers.clear(); + model->bufferViews.clear(); + model->accessors.clear(); + model->meshes.clear(); + model->cameras.clear(); + model->nodes.clear(); + model->extensionsUsed.clear(); + model->extensionsRequired.clear(); + model->extensions.clear(); + model->defaultScene = -1; + + // 1. Parse Asset + { + detail::json_const_iterator it; + if (detail::FindMember(v, "asset", it) && + detail::IsObject(detail::GetValue(it))) { + const detail::json &root = detail::GetValue(it); + + ParseAsset(&model->asset, err, root, + store_original_json_for_extras_and_extensions_); + } + } + + using detail::ForEachInArray; + + // 2. Parse extensionUsed + { + ForEachInArray(v, "extensionsUsed", [&](const detail::json &o) { + std::string str; + detail::GetString(o, str); + model->extensionsUsed.emplace_back(std::move(str)); + return true; + }); + } + + { + ForEachInArray(v, "extensionsRequired", [&](const detail::json &o) { + std::string str; + detail::GetString(o, str); + model->extensionsRequired.emplace_back(std::move(str)); + return true; + }); + } + + // 3. Parse Buffer + { + bool success = ForEachInArray(v, "buffers", [&](const detail::json &o) { + if (!detail::IsObject(o)) { + if (err) { + (*err) += "`buffers' does not contain an JSON object."; + } + return false; + } + Buffer buffer; + if (!ParseBuffer(&buffer, err, o, + store_original_json_for_extras_and_extensions_, &fs, + &uri_cb, base_dir, max_external_file_size_, is_binary_, + bin_data_, bin_size_)) { + return false; + } + + model->buffers.emplace_back(std::move(buffer)); + return true; + }); + + if (!success) { + return false; + } + } + // 4. Parse BufferView + { + bool success = ForEachInArray(v, "bufferViews", [&](const detail::json &o) { + if (!detail::IsObject(o)) { + if (err) { + (*err) += "`bufferViews' does not contain an JSON object."; + } + return false; + } + BufferView bufferView; + if (!ParseBufferView(&bufferView, err, o, + store_original_json_for_extras_and_extensions_)) { + return false; + } + + model->bufferViews.emplace_back(std::move(bufferView)); + return true; + }); + + if (!success) { + return false; + } + } + + // 5. Parse Accessor + { + bool success = ForEachInArray(v, "accessors", [&](const detail::json &o) { + if (!detail::IsObject(o)) { + if (err) { + (*err) += "`accessors' does not contain an JSON object."; + } + return false; + } + Accessor accessor; + if (!ParseAccessor(&accessor, err, o, + store_original_json_for_extras_and_extensions_)) { + return false; + } + + model->accessors.emplace_back(std::move(accessor)); + return true; + }); + + if (!success) { + return false; + } + } + + // 6. Parse Mesh + { + bool success = ForEachInArray(v, "meshes", [&](const detail::json &o) { + if (!detail::IsObject(o)) { + if (err) { + (*err) += "`meshes' does not contain an JSON object."; + } + return false; + } + Mesh mesh; + if (!ParseMesh(&mesh, model, err, warn, o, + store_original_json_for_extras_and_extensions_, + strictness_)) { + return false; + } + + model->meshes.emplace_back(std::move(mesh)); + return true; + }); + + if (!success) { + return false; + } + } + + // Assign missing bufferView target types + // - Look for missing Mesh indices + // - Look for missing Mesh attributes + for (auto &mesh : model->meshes) { + for (auto &primitive : mesh.primitives) { + if (primitive.indices > + -1) // has indices from parsing step, must be Element Array Buffer + { + if (size_t(primitive.indices) >= model->accessors.size()) { + if (err) { + (*err) += "primitive indices accessor out of bounds"; + } + return false; + } + + const auto bufferView = + model->accessors[size_t(primitive.indices)].bufferView; + if (bufferView < 0) { + // skip, bufferView could be null(-1) for certain extensions + } else if (size_t(bufferView) >= model->bufferViews.size()) { + if (err) { + (*err) += "accessor[" + std::to_string(primitive.indices) + + "] invalid bufferView"; + } + return false; + } else { + model->bufferViews[size_t(bufferView)].target = + TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER; + // we could optionally check if accessors' bufferView type is Scalar, as + // it should be + } + } + + for (auto &attribute : primitive.attributes) { + const auto accessorsIndex = size_t(attribute.second); + if (accessorsIndex < model->accessors.size()) { + const auto bufferView = model->accessors[accessorsIndex].bufferView; + // bufferView could be null(-1) for sparse morph target + if (bufferView >= 0 && bufferView < (int)model->bufferViews.size()) { + model->bufferViews[size_t(bufferView)].target = + TINYGLTF_TARGET_ARRAY_BUFFER; + } + } + } + + for (auto &target : primitive.targets) { + for (auto &attribute : target) { + const auto accessorsIndex = size_t(attribute.second); + if (accessorsIndex < model->accessors.size()) { + const auto bufferView = model->accessors[accessorsIndex].bufferView; + // bufferView could be null(-1) for sparse morph target + if (bufferView >= 0 && + bufferView < (int)model->bufferViews.size()) { + model->bufferViews[size_t(bufferView)].target = + TINYGLTF_TARGET_ARRAY_BUFFER; + } + } + } + } + } + } + + // 7. Parse Node + { + bool success = ForEachInArray(v, "nodes", [&](const detail::json &o) { + if (!detail::IsObject(o)) { + if (err) { + (*err) += "`nodes' does not contain an JSON object."; + } + return false; + } + Node node; + if (!ParseNode(&node, err, o, + store_original_json_for_extras_and_extensions_)) { + return false; + } + + model->nodes.emplace_back(std::move(node)); + return true; + }); + + if (!success) { + return false; + } + } + + // 8. Parse scenes. + { + bool success = ForEachInArray(v, "scenes", [&](const detail::json &o) { + if (!detail::IsObject(o)) { + if (err) { + (*err) += "`scenes' does not contain an JSON object."; + } + return false; + } + + Scene scene; + if (!ParseScene(&scene, err, o, + store_original_json_for_extras_and_extensions_)) { + return false; + } + + model->scenes.emplace_back(std::move(scene)); + return true; + }); + + if (!success) { + return false; + } + } + + // 9. Parse default scenes. + { + detail::json_const_iterator rootIt; + int iVal; + if (detail::FindMember(v, "scene", rootIt) && + detail::GetInt(detail::GetValue(rootIt), iVal)) { + model->defaultScene = iVal; + } + } + + // 10. Parse Material + { + bool success = ForEachInArray(v, "materials", [&](const detail::json &o) { + if (!detail::IsObject(o)) { + if (err) { + (*err) += "`materials' does not contain an JSON object."; + } + return false; + } + Material material; + ParseStringProperty(&material.name, err, o, "name", false); + + if (!ParseMaterial(&material, err, warn, o, + store_original_json_for_extras_and_extensions_, + strictness_)) { + return false; + } + + model->materials.emplace_back(std::move(material)); + return true; + }); + + if (!success) { + return false; + } + } + + // 11. Parse Image + void *load_image_user_data{nullptr}; + + LoadImageDataOption load_image_option; + + if (user_image_loader_) { + // Use user supplied pointer + load_image_user_data = load_image_user_data_; + } else { + load_image_option.preserve_channels = preserve_image_channels_; + load_image_user_data = reinterpret_cast(&load_image_option); + } + + { + int idx = 0; + bool success = ForEachInArray(v, "images", [&](const detail::json &o) { + if (!detail::IsObject(o)) { + if (err) { + (*err) += "image[" + std::to_string(idx) + "] is not a JSON object."; + } + return false; + } + Image image; + if (!ParseImage(&image, idx, err, warn, o, + store_original_json_for_extras_and_extensions_, base_dir, + max_external_file_size_, &fs, &uri_cb, + &this->LoadImageData, load_image_user_data)) { + return false; + } + + if (image.bufferView != -1) { + // Load image from the buffer view. + if (size_t(image.bufferView) >= model->bufferViews.size()) { + if (err) { + std::stringstream ss; + ss << "image[" << idx << "] bufferView \"" << image.bufferView + << "\" not found in the scene." << std::endl; + (*err) += ss.str(); + } + return false; + } + + const BufferView &bufferView = + model->bufferViews[size_t(image.bufferView)]; + if (size_t(bufferView.buffer) >= model->buffers.size()) { + if (err) { + std::stringstream ss; + ss << "image[" << idx << "] buffer \"" << bufferView.buffer + << "\" not found in the scene." << std::endl; + (*err) += ss.str(); + } + return false; + } + const Buffer &buffer = model->buffers[size_t(bufferView.buffer)]; + + if (*LoadImageData == nullptr) { + if (err) { + (*err) += "No LoadImageData callback specified.\n"; + } + return false; + } + bool ret = LoadImageData( + &image, idx, err, warn, image.width, image.height, + &buffer.data[bufferView.byteOffset], + static_cast(bufferView.byteLength), load_image_user_data); + if (!ret) { + return false; + } + } + + model->images.emplace_back(std::move(image)); + ++idx; + return true; + }); + + if (!success) { + return false; + } + } + + // 12. Parse Texture + { + bool success = ForEachInArray(v, "textures", [&](const detail::json &o) { + if (!detail::IsObject(o)) { + if (err) { + (*err) += "`textures' does not contain an JSON object."; + } + return false; + } + Texture texture; + if (!ParseTexture(&texture, err, o, + store_original_json_for_extras_and_extensions_, + base_dir)) { + return false; + } + + model->textures.emplace_back(std::move(texture)); + return true; + }); + + if (!success) { + return false; + } + } + + // 13. Parse Animation + { + bool success = ForEachInArray(v, "animations", [&](const detail::json &o) { + if (!detail::IsObject(o)) { + if (err) { + (*err) += "`animations' does not contain an JSON object."; + } + return false; + } + Animation animation; + if (!ParseAnimation(&animation, err, o, + store_original_json_for_extras_and_extensions_)) { + return false; + } + + model->animations.emplace_back(std::move(animation)); + return true; + }); + + if (!success) { + return false; + } + } + + // 14. Parse Skin + { + bool success = ForEachInArray(v, "skins", [&](const detail::json &o) { + if (!detail::IsObject(o)) { + if (err) { + (*err) += "`skins' does not contain an JSON object."; + } + return false; + } + Skin skin; + if (!ParseSkin(&skin, err, o, + store_original_json_for_extras_and_extensions_)) { + return false; + } + + model->skins.emplace_back(std::move(skin)); + return true; + }); + + if (!success) { + return false; + } + } + + // 15. Parse Sampler + { + bool success = ForEachInArray(v, "samplers", [&](const detail::json &o) { + if (!detail::IsObject(o)) { + if (err) { + (*err) += "`samplers' does not contain an JSON object."; + } + return false; + } + Sampler sampler; + if (!ParseSampler(&sampler, err, o, + store_original_json_for_extras_and_extensions_)) { + return false; + } + + model->samplers.emplace_back(std::move(sampler)); + return true; + }); + + if (!success) { + return false; + } + } + + // 16. Parse Camera + { + bool success = ForEachInArray(v, "cameras", [&](const detail::json &o) { + if (!detail::IsObject(o)) { + if (err) { + (*err) += "`cameras' does not contain an JSON object."; + } + return false; + } + Camera camera; + if (!ParseCamera(&camera, err, o, + store_original_json_for_extras_and_extensions_)) { + return false; + } + + model->cameras.emplace_back(std::move(camera)); + return true; + }); + + if (!success) { + return false; + } + } + + // 17. Parse Extras & Extensions + ParseExtrasAndExtensions(model, err, v, + store_original_json_for_extras_and_extensions_); + + // 18. Specific extension implementations + { + detail::json_const_iterator rootIt; + if (detail::FindMember(v, "extensions", rootIt) && + detail::IsObject(detail::GetValue(rootIt))) { + const detail::json &root = detail::GetValue(rootIt); + + detail::json_const_iterator it(detail::ObjectBegin(root)); + detail::json_const_iterator itEnd(detail::ObjectEnd(root)); + for (; it != itEnd; ++it) { + // parse KHR_lights_punctual extension + std::string key(detail::GetKey(it)); + if ((key == "KHR_lights_punctual") && + detail::IsObject(detail::GetValue(it))) { + const detail::json &object = detail::GetValue(it); + detail::json_const_iterator itLight; + if (detail::FindMember(object, "lights", itLight)) { + const detail::json &lights = detail::GetValue(itLight); + if (!detail::IsArray(lights)) { + continue; + } + + auto arrayIt(detail::ArrayBegin(lights)); + auto arrayItEnd(detail::ArrayEnd(lights)); + for (; arrayIt != arrayItEnd; ++arrayIt) { + Light light; + if (!ParseLight(&light, err, *arrayIt, + store_original_json_for_extras_and_extensions_)) { + return false; + } + model->lights.emplace_back(std::move(light)); + } + } + } + // parse KHR_audio extension + if ((key == "KHR_audio") && detail::IsObject(detail::GetValue(it))) { + const detail::json &object = detail::GetValue(it); + detail::json_const_iterator itKhrAudio; + if (detail::FindMember(object, "emitters", itKhrAudio)) { + const detail::json &emitters = detail::GetValue(itKhrAudio); + if (!detail::IsArray(emitters)) { + continue; + } + + auto arrayIt(detail::ArrayBegin(emitters)); + auto arrayItEnd(detail::ArrayEnd(emitters)); + for (; arrayIt != arrayItEnd; ++arrayIt) { + AudioEmitter emitter; + if (!ParseAudioEmitter( + &emitter, err, *arrayIt, + store_original_json_for_extras_and_extensions_)) { + return false; + } + model->audioEmitters.emplace_back(std::move(emitter)); + } + } + + if (detail::FindMember(object, "sources", itKhrAudio)) { + const detail::json &sources = detail::GetValue(itKhrAudio); + if (!detail::IsArray(sources)) { + continue; + } + + auto arrayIt(detail::ArrayBegin(sources)); + auto arrayItEnd(detail::ArrayEnd(sources)); + for (; arrayIt != arrayItEnd; ++arrayIt) { + AudioSource source; + if (!ParseAudioSource( + &source, err, *arrayIt, + store_original_json_for_extras_and_extensions_)) { + return false; + } + model->audioSources.emplace_back(std::move(source)); + } + } + } + } + } + } + + return true; +} + +bool TinyGLTF::LoadASCIIFromString(Model *model, std::string *err, + std::string *warn, const char *str, + unsigned int length, + const std::string &base_dir, + unsigned int check_sections) { + is_binary_ = false; + bin_data_ = nullptr; + bin_size_ = 0; + + return LoadFromString(model, err, warn, str, length, base_dir, + check_sections); +} + +bool TinyGLTF::LoadASCIIFromFile(Model *model, std::string *err, + std::string *warn, const std::string &filename, + unsigned int check_sections) { + std::stringstream ss; + + if (fs.ReadWholeFile == nullptr) { + // Programmer error, assert() ? + ss << "Failed to read file: " << filename + << ": one or more FS callback not set" << std::endl; + if (err) { + (*err) = ss.str(); + } + return false; + } + + std::vector data; + std::string fileerr; + bool fileread = fs.ReadWholeFile(&data, &fileerr, filename, fs.user_data); + if (!fileread) { + ss << "Failed to read file: " << filename << ": " << fileerr << std::endl; + if (err) { + (*err) = ss.str(); + } + return false; + } + + size_t sz = data.size(); + if (sz == 0) { + if (err) { + (*err) = "Empty file."; + } + return false; + } + + std::string basedir = GetBaseDir(filename); + + bool ret = LoadASCIIFromString( + model, err, warn, reinterpret_cast(&data.at(0)), + static_cast(data.size()), basedir, check_sections); + + return ret; +} + +bool TinyGLTF::LoadBinaryFromMemory(Model *model, std::string *err, + std::string *warn, + const unsigned char *bytes, + unsigned int size, + const std::string &base_dir, + unsigned int check_sections) { + if (size < 20) { + if (err) { + (*err) = "Too short data size for glTF Binary."; + } + return false; + } + + if (bytes[0] == 'g' && bytes[1] == 'l' && bytes[2] == 'T' && + bytes[3] == 'F') { + // ok + } else { + if (err) { + (*err) = "Invalid magic."; + } + return false; + } + + unsigned int version; // 4 bytes + unsigned int length; // 4 bytes + unsigned int chunk0_length; // 4 bytes + unsigned int chunk0_format; // 4 bytes; + + memcpy(&version, bytes + 4, 4); + swap4(&version); + memcpy(&length, bytes + 8, 4); + swap4(&length); + memcpy(&chunk0_length, bytes + 12, 4); // JSON data length + swap4(&chunk0_length); + memcpy(&chunk0_format, bytes + 16, 4); + swap4(&chunk0_format); + + // https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#binary-gltf-layout + // + // In case the Bin buffer is not present, the size is exactly 20 + size of + // JSON contents, + // so use "greater than" operator. + // + // https://github.com/syoyo/tinygltf/issues/372 + // Use 64bit uint to avoid integer overflow. + uint64_t header_and_json_size = 20ull + uint64_t(chunk0_length); + + if (header_and_json_size > (std::numeric_limits::max)()) { + // Do not allow 4GB or more GLB data. + if (err) { + (*err) = "Invalid glTF binary. GLB data exceeds 4GB."; + } + return false; + } + + if ((header_and_json_size > uint64_t(size)) || (chunk0_length < 1) || + (length > size) || (header_and_json_size > uint64_t(length)) || + (chunk0_format != 0x4E4F534A)) { // 0x4E4F534A = JSON format. + if (err) { + (*err) = "Invalid glTF binary."; + } + return false; + } + + // Padding check + // The start and the end of each chunk must be aligned to a 4-byte boundary. + // No padding check for chunk0 start since its 4byte-boundary is ensured. + if ((header_and_json_size % 4) != 0) { + if (err) { + (*err) = "JSON Chunk end does not aligned to a 4-byte boundary."; + } + return false; + } + + // std::cout << "header_and_json_size = " << header_and_json_size << "\n"; + // std::cout << "length = " << length << "\n"; + + // Chunk1(BIN) data + // The spec says: When the binary buffer is empty or when it is stored by + // other means, this chunk SHOULD be omitted. So when header + JSON data == + // binary size, Chunk1 is omitted. + if (header_and_json_size == uint64_t(length)) { + bin_data_ = nullptr; + bin_size_ = 0; + } else { + // Read Chunk1 info(BIN data) + // At least Chunk1 should have 12 bytes(8 bytes(header) + 4 bytes(bin + // payload could be 1~3 bytes, but need to be aligned to 4 bytes) + if ((header_and_json_size + 12ull) > uint64_t(length)) { + if (err) { + (*err) = + "Insufficient storage space for Chunk1(BIN data). At least Chunk1 " + "Must have 4 or more bytes, but got " + + std::to_string((header_and_json_size + 8ull) - uint64_t(length)) + + ".\n"; + } + return false; + } + + unsigned int chunk1_length; // 4 bytes + unsigned int chunk1_format; // 4 bytes; + memcpy(&chunk1_length, bytes + header_and_json_size, + 4); // JSON data length + swap4(&chunk1_length); + memcpy(&chunk1_format, bytes + header_and_json_size + 4, 4); + swap4(&chunk1_format); + + // std::cout << "chunk1_length = " << chunk1_length << "\n"; + + if (chunk1_length < 4) { + if (err) { + (*err) = "Insufficient Chunk1(BIN) data size."; + } + return false; + } + + if ((chunk1_length % 4) != 0) { + if (strictness_==ParseStrictness::Permissive) { + if (warn) { + (*warn) += "BIN Chunk end is not aligned to a 4-byte boundary.\n"; + } + } + else { + if (err) { + (*err) = "BIN Chunk end is not aligned to a 4-byte boundary."; + } + return false; + } + } + + if (uint64_t(chunk1_length) + header_and_json_size > uint64_t(length)) { + if (err) { + (*err) = "BIN Chunk data length exceeds the GLB size."; + } + return false; + } + + if (chunk1_format != 0x004e4942) { + if (err) { + (*err) = "Invalid type for chunk1 data."; + } + return false; + } + + // std::cout << "chunk1_length = " << chunk1_length << "\n"; + + bin_data_ = bytes + header_and_json_size + + 8; // 4 bytes (bin_buffer_length) + 4 bytes(bin_buffer_format) + + bin_size_ = size_t(chunk1_length); + } + + is_binary_ = true; + + bool ret = LoadFromString(model, err, warn, + reinterpret_cast(&bytes[20]), + chunk0_length, base_dir, check_sections); + if (!ret) { + return ret; + } + + return true; +} + +bool TinyGLTF::LoadBinaryFromFile(Model *model, std::string *err, + std::string *warn, + const std::string &filename, + unsigned int check_sections) { + std::stringstream ss; + + if (fs.ReadWholeFile == nullptr) { + // Programmer error, assert() ? + ss << "Failed to read file: " << filename + << ": one or more FS callback not set" << std::endl; + if (err) { + (*err) = ss.str(); + } + return false; + } + + std::vector data; + std::string fileerr; + bool fileread = fs.ReadWholeFile(&data, &fileerr, filename, fs.user_data); + if (!fileread) { + ss << "Failed to read file: " << filename << ": " << fileerr << std::endl; + if (err) { + (*err) = ss.str(); + } + return false; + } + + std::string basedir = GetBaseDir(filename); + + bool ret = LoadBinaryFromMemory(model, err, warn, &data.at(0), + static_cast(data.size()), + basedir, check_sections); + + return ret; +} + +/////////////////////// +// GLTF Serialization +/////////////////////// +namespace detail { +detail::json JsonFromString(const char *s) { +#ifdef TINYGLTF_USE_RAPIDJSON + return detail::json(s, detail::GetAllocator()); +#else + return detail::json(s); +#endif +} + +void JsonAssign(detail::json &dest, const detail::json &src) { +#ifdef TINYGLTF_USE_RAPIDJSON + dest.CopyFrom(src, detail::GetAllocator()); +#else + dest = src; +#endif +} + +void JsonAddMember(detail::json &o, const char *key, detail::json &&value) { +#ifdef TINYGLTF_USE_RAPIDJSON + if (!o.IsObject()) { + o.SetObject(); + } + + // Issue 420. + // AddMember may create duplicated key, so use [] API when a key already + // exists. + // https://github.com/Tencent/rapidjson/issues/771#issuecomment-254386863 + detail::json_const_iterator it; + if (detail::FindMember(o, key, it)) { + o[key] = std::move(value); // replace + } else { + o.AddMember(detail::json(key, detail::GetAllocator()), std::move(value), + detail::GetAllocator()); + } +#else + o[key] = std::move(value); +#endif +} + +void JsonPushBack(detail::json &o, detail::json &&value) { +#ifdef TINYGLTF_USE_RAPIDJSON + o.PushBack(std::move(value), detail::GetAllocator()); +#else + o.push_back(std::move(value)); +#endif +} + +bool JsonIsNull(const detail::json &o) { +#ifdef TINYGLTF_USE_RAPIDJSON + return o.IsNull(); +#else + return o.is_null(); +#endif +} + +void JsonSetObject(detail::json &o) { +#ifdef TINYGLTF_USE_RAPIDJSON + o.SetObject(); +#else + o = o.object({}); +#endif +} + +void JsonReserveArray(detail::json &o, size_t s) { +#ifdef TINYGLTF_USE_RAPIDJSON + o.SetArray(); + o.Reserve(static_cast(s), detail::GetAllocator()); +#endif + (void)(o); + (void)(s); +} +} // namespace detail + +// typedef std::pair json_object_pair; + +template +static void SerializeNumberProperty(const std::string &key, T number, + detail::json &obj) { + // obj.insert( + // json_object_pair(key, detail::json(static_cast(number)))); + // obj[key] = static_cast(number); + detail::JsonAddMember(obj, key.c_str(), detail::json(number)); +} + +#ifdef TINYGLTF_USE_RAPIDJSON +template <> +void SerializeNumberProperty(const std::string &key, size_t number, + detail::json &obj) { + detail::JsonAddMember(obj, key.c_str(), + detail::json(static_cast(number))); +} +#endif + +template +static void SerializeNumberArrayProperty(const std::string &key, + const std::vector &value, + detail::json &obj) { + if (value.empty()) return; + + detail::json ary; + detail::JsonReserveArray(ary, value.size()); + for (const auto &s : value) { + detail::JsonPushBack(ary, detail::json(s)); + } + detail::JsonAddMember(obj, key.c_str(), std::move(ary)); +} + +static void SerializeStringProperty(const std::string &key, + const std::string &value, + detail::json &obj) { + detail::JsonAddMember(obj, key.c_str(), + detail::JsonFromString(value.c_str())); +} + +static void SerializeStringArrayProperty(const std::string &key, + const std::vector &value, + detail::json &obj) { + detail::json ary; + detail::JsonReserveArray(ary, value.size()); + for (auto &s : value) { + detail::JsonPushBack(ary, detail::JsonFromString(s.c_str())); + } + detail::JsonAddMember(obj, key.c_str(), std::move(ary)); +} + +static bool ValueToJson(const Value &value, detail::json *ret) { + detail::json obj; +#ifdef TINYGLTF_USE_RAPIDJSON + switch (value.Type()) { + case REAL_TYPE: + obj.SetDouble(value.Get()); + break; + case INT_TYPE: + obj.SetInt(value.Get()); + break; + case BOOL_TYPE: + obj.SetBool(value.Get()); + break; + case STRING_TYPE: + obj.SetString(value.Get().c_str(), detail::GetAllocator()); + break; + case ARRAY_TYPE: { + obj.SetArray(); + obj.Reserve(static_cast(value.ArrayLen()), + detail::GetAllocator()); + for (unsigned int i = 0; i < value.ArrayLen(); ++i) { + Value elementValue = value.Get(int(i)); + detail::json elementJson; + if (ValueToJson(value.Get(int(i)), &elementJson)) + obj.PushBack(std::move(elementJson), detail::GetAllocator()); + } + break; + } + case BINARY_TYPE: + // TODO + // obj = detail::json(value.Get>()); + return false; + break; + case OBJECT_TYPE: { + obj.SetObject(); + Value::Object objMap = value.Get(); + for (auto &it : objMap) { + detail::json elementJson; + if (ValueToJson(it.second, &elementJson)) { + obj.AddMember(detail::json(it.first.c_str(), detail::GetAllocator()), + std::move(elementJson), detail::GetAllocator()); + } + } + break; + } + case NULL_TYPE: + default: + return false; + } +#else + switch (value.Type()) { + case REAL_TYPE: + obj = detail::json(value.Get()); + break; + case INT_TYPE: + obj = detail::json(value.Get()); + break; + case BOOL_TYPE: + obj = detail::json(value.Get()); + break; + case STRING_TYPE: + obj = detail::json(value.Get()); + break; + case ARRAY_TYPE: { + for (unsigned int i = 0; i < value.ArrayLen(); ++i) { + Value elementValue = value.Get(int(i)); + detail::json elementJson; + if (ValueToJson(value.Get(int(i)), &elementJson)) + obj.push_back(elementJson); + } + break; + } + case BINARY_TYPE: + // TODO + // obj = json(value.Get>()); + return false; + break; + case OBJECT_TYPE: { + Value::Object objMap = value.Get(); + for (auto &it : objMap) { + detail::json elementJson; + if (ValueToJson(it.second, &elementJson)) obj[it.first] = elementJson; + } + break; + } + case NULL_TYPE: + default: + return false; + } +#endif + if (ret) *ret = std::move(obj); + return true; +} + +static void SerializeValue(const std::string &key, const Value &value, + detail::json &obj) { + detail::json ret; + if (ValueToJson(value, &ret)) { + detail::JsonAddMember(obj, key.c_str(), std::move(ret)); + } +} + +static void SerializeGltfBufferData(const std::vector &data, + detail::json &o) { + std::string header = "data:application/octet-stream;base64,"; + if (data.size() > 0) { + std::string encodedData = + base64_encode(&data[0], static_cast(data.size())); + SerializeStringProperty("uri", header + encodedData, o); + } else { + // Issue #229 + // size 0 is allowed. Just emit mime header. + SerializeStringProperty("uri", header, o); + } +} + +static bool SerializeGltfBufferData(const std::vector &data, + const std::string &binFilename) { +#ifdef _WIN32 +#if defined(__GLIBCXX__) // mingw + int file_descriptor = _wopen(UTF8ToWchar(binFilename).c_str(), + _O_CREAT | _O_WRONLY | _O_TRUNC | _O_BINARY); + __gnu_cxx::stdio_filebuf wfile_buf( + file_descriptor, std::ios_base::out | std::ios_base::binary); + std::ostream output(&wfile_buf); + if (!wfile_buf.is_open()) return false; +#elif defined(_MSC_VER) + std::ofstream output(UTF8ToWchar(binFilename).c_str(), std::ofstream::binary); + if (!output.is_open()) return false; +#else + std::ofstream output(binFilename.c_str(), std::ofstream::binary); + if (!output.is_open()) return false; +#endif +#else + std::ofstream output(binFilename.c_str(), std::ofstream::binary); + if (!output.is_open()) return false; +#endif + if (data.size() > 0) { + output.write(reinterpret_cast(&data[0]), + std::streamsize(data.size())); + } else { + // Issue #229 + // size 0 will be still valid buffer data. + // write empty file. + } + return true; +} + +#if 0 // FIXME(syoyo): not used. will be removed in the future release. +static void SerializeParameterMap(ParameterMap ¶m, detail::json &o) { + for (ParameterMap::iterator paramIt = param.begin(); paramIt != param.end(); + ++paramIt) { + if (paramIt->second.number_array.size()) { + SerializeNumberArrayProperty(paramIt->first, + paramIt->second.number_array, o); + } else if (paramIt->second.json_double_value.size()) { + detail::json json_double_value; + for (std::map::iterator it = + paramIt->second.json_double_value.begin(); + it != paramIt->second.json_double_value.end(); ++it) { + if (it->first == "index") { + json_double_value[it->first] = paramIt->second.TextureIndex(); + } else { + json_double_value[it->first] = it->second; + } + } + + o[paramIt->first] = json_double_value; + } else if (!paramIt->second.string_value.empty()) { + SerializeStringProperty(paramIt->first, paramIt->second.string_value, o); + } else if (paramIt->second.has_number_value) { + o[paramIt->first] = paramIt->second.number_value; + } else { + o[paramIt->first] = paramIt->second.bool_value; + } + } +} +#endif + +static void SerializeExtensionMap(const ExtensionMap &extensions, + detail::json &o) { + if (!extensions.size()) return; + + detail::json extMap; + for (ExtensionMap::const_iterator extIt = extensions.begin(); + extIt != extensions.end(); ++extIt) { + // Allow an empty object for extension(#97) + detail::json ret; + bool isNull = true; + if (ValueToJson(extIt->second, &ret)) { + isNull = detail::JsonIsNull(ret); + detail::JsonAddMember(extMap, extIt->first.c_str(), std::move(ret)); + } + if (isNull) { + if (!(extIt->first.empty())) { // name should not be empty, but for sure + // create empty object so that an extension name is still included in + // json. + detail::json empty; + detail::JsonSetObject(empty); + detail::JsonAddMember(extMap, extIt->first.c_str(), std::move(empty)); + } + } + } + detail::JsonAddMember(o, "extensions", std::move(extMap)); +} + +static void SerializeExtras(const Value &extras, detail::json &o) { + if (extras.Type() != NULL_TYPE) SerializeValue("extras", extras, o); +} + +template +void SerializeExtrasAndExtensions(const GltfType &obj, detail::json &o) { + SerializeExtensionMap(obj.extensions, o); + SerializeExtras(obj.extras, o); +} + +static void SerializeGltfAccessor(const Accessor &accessor, detail::json &o) { + if (accessor.bufferView >= 0) + SerializeNumberProperty("bufferView", accessor.bufferView, o); + + if (accessor.byteOffset != 0) + SerializeNumberProperty("byteOffset", accessor.byteOffset, o); + + SerializeNumberProperty("componentType", accessor.componentType, o); + SerializeNumberProperty("count", accessor.count, o); + + if ((accessor.componentType == TINYGLTF_COMPONENT_TYPE_FLOAT) || + (accessor.componentType == TINYGLTF_COMPONENT_TYPE_DOUBLE)) { + SerializeNumberArrayProperty("min", accessor.minValues, o); + SerializeNumberArrayProperty("max", accessor.maxValues, o); + } else { + // Issue #301. Serialize as integer. + // Assume int value is within [-2**31-1, 2**31-1] + { + std::vector values; + std::transform(accessor.minValues.begin(), accessor.minValues.end(), + std::back_inserter(values), + [](double v) { return static_cast(v); }); + + SerializeNumberArrayProperty("min", values, o); + } + + { + std::vector values; + std::transform(accessor.maxValues.begin(), accessor.maxValues.end(), + std::back_inserter(values), + [](double v) { return static_cast(v); }); + + SerializeNumberArrayProperty("max", values, o); + } + } + + if (accessor.normalized) + SerializeValue("normalized", Value(accessor.normalized), o); + std::string type; + switch (accessor.type) { + case TINYGLTF_TYPE_SCALAR: + type = "SCALAR"; + break; + case TINYGLTF_TYPE_VEC2: + type = "VEC2"; + break; + case TINYGLTF_TYPE_VEC3: + type = "VEC3"; + break; + case TINYGLTF_TYPE_VEC4: + type = "VEC4"; + break; + case TINYGLTF_TYPE_MAT2: + type = "MAT2"; + break; + case TINYGLTF_TYPE_MAT3: + type = "MAT3"; + break; + case TINYGLTF_TYPE_MAT4: + type = "MAT4"; + break; + } + + SerializeStringProperty("type", type, o); + if (!accessor.name.empty()) SerializeStringProperty("name", accessor.name, o); + + SerializeExtrasAndExtensions(accessor, o); + + // sparse + if (accessor.sparse.isSparse) { + detail::json sparse; + SerializeNumberProperty("count", accessor.sparse.count, sparse); + { + detail::json indices; + SerializeNumberProperty("bufferView", + accessor.sparse.indices.bufferView, indices); + SerializeNumberProperty("byteOffset", + accessor.sparse.indices.byteOffset, indices); + SerializeNumberProperty( + "componentType", accessor.sparse.indices.componentType, indices); + SerializeExtrasAndExtensions(accessor.sparse.indices, indices); + detail::JsonAddMember(sparse, "indices", std::move(indices)); + } + { + detail::json values; + SerializeNumberProperty("bufferView", + accessor.sparse.values.bufferView, values); + SerializeNumberProperty("byteOffset", + accessor.sparse.values.byteOffset, values); + SerializeExtrasAndExtensions(accessor.sparse.values, values); + detail::JsonAddMember(sparse, "values", std::move(values)); + } + SerializeExtrasAndExtensions(accessor.sparse, sparse); + detail::JsonAddMember(o, "sparse", std::move(sparse)); + } +} + +static void SerializeGltfAnimationChannel(const AnimationChannel &channel, + detail::json &o) { + SerializeNumberProperty("sampler", channel.sampler, o); + { + detail::json target; + + if (channel.target_node >= 0) { + SerializeNumberProperty("node", channel.target_node, target); + } + + SerializeStringProperty("path", channel.target_path, target); + + SerializeExtensionMap(channel.target_extensions, target); + SerializeExtras(channel.target_extras, target); + + detail::JsonAddMember(o, "target", std::move(target)); + } + + SerializeExtrasAndExtensions(channel, o); +} + +static void SerializeGltfAnimationSampler(const AnimationSampler &sampler, + detail::json &o) { + SerializeNumberProperty("input", sampler.input, o); + SerializeNumberProperty("output", sampler.output, o); + SerializeStringProperty("interpolation", sampler.interpolation, o); + + SerializeExtrasAndExtensions(sampler, o); +} + +static void SerializeGltfAnimation(const Animation &animation, + detail::json &o) { + if (!animation.name.empty()) + SerializeStringProperty("name", animation.name, o); + + { + detail::json channels; + detail::JsonReserveArray(channels, animation.channels.size()); + for (unsigned int i = 0; i < animation.channels.size(); ++i) { + detail::json channel; + AnimationChannel gltfChannel = animation.channels[i]; + SerializeGltfAnimationChannel(gltfChannel, channel); + detail::JsonPushBack(channels, std::move(channel)); + } + + detail::JsonAddMember(o, "channels", std::move(channels)); + } + + { + detail::json samplers; + detail::JsonReserveArray(samplers, animation.samplers.size()); + for (unsigned int i = 0; i < animation.samplers.size(); ++i) { + detail::json sampler; + AnimationSampler gltfSampler = animation.samplers[i]; + SerializeGltfAnimationSampler(gltfSampler, sampler); + detail::JsonPushBack(samplers, std::move(sampler)); + } + detail::JsonAddMember(o, "samplers", std::move(samplers)); + } + + SerializeExtrasAndExtensions(animation, o); +} + +static void SerializeGltfAsset(const Asset &asset, detail::json &o) { + if (!asset.generator.empty()) { + SerializeStringProperty("generator", asset.generator, o); + } + + if (!asset.copyright.empty()) { + SerializeStringProperty("copyright", asset.copyright, o); + } + + auto version = asset.version; + if (version.empty()) { + // Just in case + // `version` must be defined + version = "2.0"; + } + + // TODO(syoyo): Do we need to check if `version` is greater or equal to 2.0? + SerializeStringProperty("version", version, o); + + SerializeExtrasAndExtensions(asset, o); +} + +static void SerializeGltfBufferBin(const Buffer &buffer, detail::json &o, + std::vector &binBuffer) { + SerializeNumberProperty("byteLength", buffer.data.size(), o); + binBuffer = buffer.data; + + if (buffer.name.size()) SerializeStringProperty("name", buffer.name, o); + + SerializeExtrasAndExtensions(buffer, o); +} + +static void SerializeGltfBuffer(const Buffer &buffer, detail::json &o) { + SerializeNumberProperty("byteLength", buffer.data.size(), o); + SerializeGltfBufferData(buffer.data, o); + + if (buffer.name.size()) SerializeStringProperty("name", buffer.name, o); + + SerializeExtrasAndExtensions(buffer, o); +} + +static bool SerializeGltfBuffer(const Buffer &buffer, detail::json &o, + const std::string &binFilename, + const std::string &binUri) { + if (!SerializeGltfBufferData(buffer.data, binFilename)) return false; + SerializeNumberProperty("byteLength", buffer.data.size(), o); + SerializeStringProperty("uri", binUri, o); + + if (buffer.name.size()) SerializeStringProperty("name", buffer.name, o); + + SerializeExtrasAndExtensions(buffer, o); + return true; +} + +static void SerializeGltfBufferView(const BufferView &bufferView, + detail::json &o) { + SerializeNumberProperty("buffer", bufferView.buffer, o); + SerializeNumberProperty("byteLength", bufferView.byteLength, o); + + // byteStride is optional, minimum allowed is 4 + if (bufferView.byteStride >= 4) { + SerializeNumberProperty("byteStride", bufferView.byteStride, o); + } + // byteOffset is optional, default is 0 + if (bufferView.byteOffset > 0) { + SerializeNumberProperty("byteOffset", bufferView.byteOffset, o); + } + // Target is optional, check if it contains a valid value + if (bufferView.target == TINYGLTF_TARGET_ARRAY_BUFFER || + bufferView.target == TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER) { + SerializeNumberProperty("target", bufferView.target, o); + } + if (bufferView.name.size()) { + SerializeStringProperty("name", bufferView.name, o); + } + + SerializeExtrasAndExtensions(bufferView, o); +} + +static void SerializeGltfImage(const Image &image, const std::string &uri, + detail::json &o) { + // From 2.7.0, we look for `uri` parameter, not `Image.uri` + // if uri is empty, the mimeType and bufferview should be set + if (uri.empty()) { + SerializeStringProperty("mimeType", image.mimeType, o); + SerializeNumberProperty("bufferView", image.bufferView, o); + } else { + SerializeStringProperty("uri", uri, o); + } + + if (image.name.size()) { + SerializeStringProperty("name", image.name, o); + } + + SerializeExtrasAndExtensions(image, o); +} + +static void SerializeGltfTextureInfo(const TextureInfo &texinfo, + detail::json &o) { + SerializeNumberProperty("index", texinfo.index, o); + + if (texinfo.texCoord != 0) { + SerializeNumberProperty("texCoord", texinfo.texCoord, o); + } + + SerializeExtrasAndExtensions(texinfo, o); +} + +static void SerializeGltfNormalTextureInfo(const NormalTextureInfo &texinfo, + detail::json &o) { + SerializeNumberProperty("index", texinfo.index, o); + + if (texinfo.texCoord != 0) { + SerializeNumberProperty("texCoord", texinfo.texCoord, o); + } + + if (!TINYGLTF_DOUBLE_EQUAL(texinfo.scale, 1.0)) { + SerializeNumberProperty("scale", texinfo.scale, o); + } + + SerializeExtrasAndExtensions(texinfo, o); +} + +static void SerializeGltfOcclusionTextureInfo( + const OcclusionTextureInfo &texinfo, detail::json &o) { + SerializeNumberProperty("index", texinfo.index, o); + + if (texinfo.texCoord != 0) { + SerializeNumberProperty("texCoord", texinfo.texCoord, o); + } + + if (!TINYGLTF_DOUBLE_EQUAL(texinfo.strength, 1.0)) { + SerializeNumberProperty("strength", texinfo.strength, o); + } + + SerializeExtrasAndExtensions(texinfo, o); +} + +static void SerializeGltfPbrMetallicRoughness(const PbrMetallicRoughness &pbr, + detail::json &o) { + std::vector default_baseColorFactor = {1.0, 1.0, 1.0, 1.0}; + if (!Equals(pbr.baseColorFactor, default_baseColorFactor)) { + SerializeNumberArrayProperty("baseColorFactor", pbr.baseColorFactor, + o); + } + + if (!TINYGLTF_DOUBLE_EQUAL(pbr.metallicFactor, 1.0)) { + SerializeNumberProperty("metallicFactor", pbr.metallicFactor, o); + } + + if (!TINYGLTF_DOUBLE_EQUAL(pbr.roughnessFactor, 1.0)) { + SerializeNumberProperty("roughnessFactor", pbr.roughnessFactor, o); + } + + if (pbr.baseColorTexture.index > -1) { + detail::json texinfo; + SerializeGltfTextureInfo(pbr.baseColorTexture, texinfo); + detail::JsonAddMember(o, "baseColorTexture", std::move(texinfo)); + } + + if (pbr.metallicRoughnessTexture.index > -1) { + detail::json texinfo; + SerializeGltfTextureInfo(pbr.metallicRoughnessTexture, texinfo); + detail::JsonAddMember(o, "metallicRoughnessTexture", std::move(texinfo)); + } + + SerializeExtrasAndExtensions(pbr, o); +} + +static void SerializeGltfMaterial(const Material &material, detail::json &o) { + if (material.name.size()) { + SerializeStringProperty("name", material.name, o); + } + + // QUESTION(syoyo): Write material parameters regardless of its default value? + + if (!TINYGLTF_DOUBLE_EQUAL(material.alphaCutoff, 0.5)) { + SerializeNumberProperty("alphaCutoff", material.alphaCutoff, o); + } + + if (material.alphaMode.compare("OPAQUE") != 0) { + SerializeStringProperty("alphaMode", material.alphaMode, o); + } + + if (material.doubleSided != false) + detail::JsonAddMember(o, "doubleSided", detail::json(material.doubleSided)); + + if (material.normalTexture.index > -1) { + detail::json texinfo; + SerializeGltfNormalTextureInfo(material.normalTexture, texinfo); + detail::JsonAddMember(o, "normalTexture", std::move(texinfo)); + } + + if (material.occlusionTexture.index > -1) { + detail::json texinfo; + SerializeGltfOcclusionTextureInfo(material.occlusionTexture, texinfo); + detail::JsonAddMember(o, "occlusionTexture", std::move(texinfo)); + } + + if (material.emissiveTexture.index > -1) { + detail::json texinfo; + SerializeGltfTextureInfo(material.emissiveTexture, texinfo); + detail::JsonAddMember(o, "emissiveTexture", std::move(texinfo)); + } + + std::vector default_emissiveFactor = {0.0, 0.0, 0.0}; + if (!Equals(material.emissiveFactor, default_emissiveFactor)) { + SerializeNumberArrayProperty("emissiveFactor", + material.emissiveFactor, o); + } + + { + detail::json pbrMetallicRoughness; + SerializeGltfPbrMetallicRoughness(material.pbrMetallicRoughness, + pbrMetallicRoughness); + // Issue 204 + // Do not serialize `pbrMetallicRoughness` if pbrMetallicRoughness has all + // default values(json is null). Otherwise it will serialize to + // `pbrMetallicRoughness : null`, which cannot be read by other glTF + // importers (and validators). + // + if (!detail::JsonIsNull(pbrMetallicRoughness)) { + detail::JsonAddMember(o, "pbrMetallicRoughness", + std::move(pbrMetallicRoughness)); + } + } + +#if 0 // legacy way. just for the record. + if (material.values.size()) { + detail::json pbrMetallicRoughness; + SerializeParameterMap(material.values, pbrMetallicRoughness); + detail::JsonAddMember(o, "pbrMetallicRoughness", std::move(pbrMetallicRoughness)); + } + + SerializeParameterMap(material.additionalValues, o); +#else + +#endif + + SerializeExtrasAndExtensions(material, o); +} + +static void SerializeGltfMesh(const Mesh &mesh, detail::json &o) { + detail::json primitives; + detail::JsonReserveArray(primitives, mesh.primitives.size()); + for (unsigned int i = 0; i < mesh.primitives.size(); ++i) { + detail::json primitive; + const Primitive &gltfPrimitive = mesh.primitives[i]; // don't make a copy + { + detail::json attributes; + for (auto attrIt = gltfPrimitive.attributes.begin(); + attrIt != gltfPrimitive.attributes.end(); ++attrIt) { + SerializeNumberProperty(attrIt->first, attrIt->second, attributes); + } + + detail::JsonAddMember(primitive, "attributes", std::move(attributes)); + } + + // Indices is optional + if (gltfPrimitive.indices > -1) { + SerializeNumberProperty("indices", gltfPrimitive.indices, primitive); + } + // Material is optional + if (gltfPrimitive.material > -1) { + SerializeNumberProperty("material", gltfPrimitive.material, + primitive); + } + SerializeNumberProperty("mode", gltfPrimitive.mode, primitive); + + // Morph targets + if (gltfPrimitive.targets.size()) { + detail::json targets; + detail::JsonReserveArray(targets, gltfPrimitive.targets.size()); + for (unsigned int k = 0; k < gltfPrimitive.targets.size(); ++k) { + detail::json targetAttributes; + std::map targetData = gltfPrimitive.targets[k]; + for (std::map::iterator attrIt = targetData.begin(); + attrIt != targetData.end(); ++attrIt) { + SerializeNumberProperty(attrIt->first, attrIt->second, + targetAttributes); + } + detail::JsonPushBack(targets, std::move(targetAttributes)); + } + detail::JsonAddMember(primitive, "targets", std::move(targets)); + } + + SerializeExtrasAndExtensions(gltfPrimitive, primitive); + + detail::JsonPushBack(primitives, std::move(primitive)); + } + + detail::JsonAddMember(o, "primitives", std::move(primitives)); + + if (mesh.weights.size()) { + SerializeNumberArrayProperty("weights", mesh.weights, o); + } + + if (mesh.name.size()) { + SerializeStringProperty("name", mesh.name, o); + } + + SerializeExtrasAndExtensions(mesh, o); +} + +static void SerializeSpotLight(const SpotLight &spot, detail::json &o) { + SerializeNumberProperty("innerConeAngle", spot.innerConeAngle, o); + SerializeNumberProperty("outerConeAngle", spot.outerConeAngle, o); + SerializeExtrasAndExtensions(spot, o); +} + +static void SerializeGltfLight(const Light &light, detail::json &o) { + if (!light.name.empty()) SerializeStringProperty("name", light.name, o); + SerializeNumberProperty("intensity", light.intensity, o); + if (light.range > 0.0) { + SerializeNumberProperty("range", light.range, o); + } + SerializeNumberArrayProperty("color", light.color, o); + SerializeStringProperty("type", light.type, o); + if (light.type == "spot") { + detail::json spot; + SerializeSpotLight(light.spot, spot); + detail::JsonAddMember(o, "spot", std::move(spot)); + } + SerializeExtrasAndExtensions(light, o); +} + +static void SerializeGltfPositionalEmitter(const PositionalEmitter &positional, + detail::json &o) { + if (!TINYGLTF_DOUBLE_EQUAL(positional.coneInnerAngle, 6.283185307179586)) + SerializeNumberProperty("coneInnerAngle", positional.coneInnerAngle, o); + if (!TINYGLTF_DOUBLE_EQUAL(positional.coneOuterAngle, 6.283185307179586)) + SerializeNumberProperty("coneOuterAngle", positional.coneOuterAngle, o); + if (positional.coneOuterGain > 0.0) + SerializeNumberProperty("coneOuterGain", positional.coneOuterGain, o); + if (!TINYGLTF_DOUBLE_EQUAL(positional.maxDistance, 100.0)) + SerializeNumberProperty("maxDistance", positional.maxDistance, o); + if (!TINYGLTF_DOUBLE_EQUAL(positional.refDistance, 1.0)) + SerializeNumberProperty("refDistance", positional.refDistance, o); + if (!TINYGLTF_DOUBLE_EQUAL(positional.rolloffFactor, 1.0)) + SerializeNumberProperty("rolloffFactor", positional.rolloffFactor, o); + + SerializeExtrasAndExtensions(positional, o); +} + +static void SerializeGltfAudioEmitter(const AudioEmitter &emitter, + detail::json &o) { + if (!emitter.name.empty()) SerializeStringProperty("name", emitter.name, o); + if (!TINYGLTF_DOUBLE_EQUAL(emitter.gain, 1.0)) + SerializeNumberProperty("gain", emitter.gain, o); + if (emitter.loop) SerializeNumberProperty("loop", emitter.loop, o); + if (emitter.playing) SerializeNumberProperty("playing", emitter.playing, o); + if (!emitter.type.empty()) SerializeStringProperty("type", emitter.type, o); + if (!emitter.distanceModel.empty()) + SerializeStringProperty("distanceModel", emitter.distanceModel, o); + if (emitter.type == "positional") { + detail::json positional; + SerializeGltfPositionalEmitter(emitter.positional, positional); + detail::JsonAddMember(o, "positional", std::move(positional)); + } + SerializeNumberProperty("source", emitter.source, o); + SerializeExtrasAndExtensions(emitter, o); +} + +static void SerializeGltfAudioSource(const AudioSource &source, + detail::json &o) { + std::string name; + std::string uri; + std::string mimeType; // (required if no uri) ["audio/mp3", "audio/ogg", + // "audio/wav", "audio/m4a"] + + if (!source.name.empty()) SerializeStringProperty("name", source.name, o); + if (source.uri.empty()) { + SerializeStringProperty("mimeType", source.mimeType, o); + SerializeNumberProperty("bufferView", source.bufferView, o); + } else { + SerializeStringProperty("uri", source.uri, o); + } + SerializeExtrasAndExtensions(source, o); +} + +static void SerializeGltfNode(const Node &node, detail::json &o) { + if (node.translation.size() > 0) { + SerializeNumberArrayProperty("translation", node.translation, o); + } + if (node.rotation.size() > 0) { + SerializeNumberArrayProperty("rotation", node.rotation, o); + } + if (node.scale.size() > 0) { + SerializeNumberArrayProperty("scale", node.scale, o); + } + if (node.matrix.size() > 0) { + SerializeNumberArrayProperty("matrix", node.matrix, o); + } + if (node.mesh != -1) { + SerializeNumberProperty("mesh", node.mesh, o); + } + + if (node.skin != -1) { + SerializeNumberProperty("skin", node.skin, o); + } + + if (node.camera != -1) { + SerializeNumberProperty("camera", node.camera, o); + } + + if (node.weights.size() > 0) { + SerializeNumberArrayProperty("weights", node.weights, o); + } + + SerializeExtrasAndExtensions(node, o); + + // Note(agnat): If the asset was loaded from disk, the node may already + // contain the KHR_lights_punctual extension. If it was constructed in + // memory it does not. In any case we update the JSON property using + // the value from the struct. Last, if the node does not have a light + // reference but the extension is still present, we remove it. + if (node.light != -1) { + detail::json_iterator it; + if (!detail::FindMember(o, "extensions", it)) { + detail::json extensions; + detail::JsonSetObject(extensions); + detail::JsonAddMember(o, "extensions", std::move(extensions)); + detail::FindMember(o, "extensions", it); + } + auto &extensions = detail::GetValue(it); + if (!detail::FindMember(extensions, "KHR_lights_punctual", it)) { + detail::json lights_punctual; + detail::JsonSetObject(lights_punctual); + detail::JsonAddMember(extensions, "KHR_lights_punctual", + std::move(lights_punctual)); + detail::FindMember(extensions, "KHR_lights_punctual", it); + } + SerializeNumberProperty("light", node.light, detail::GetValue(it)); + } else { + // node has no light ref (any longer)... so we clean up + detail::json_iterator ext_it; + if (detail::FindMember(o, "extensions", ext_it)) { + auto &extensions = detail::GetValue(ext_it); + detail::json_iterator lp_it; + if (detail::FindMember(extensions, "KHR_lights_punctual", lp_it)) { + detail::Erase(extensions, lp_it); + } + if (detail::IsEmpty(extensions)) { + detail::Erase(o, ext_it); + } + } + } + + // KHR_audio + if (node.emitter != -1) { + detail::json_iterator it; + if (!detail::FindMember(o, "extensions", it)) { + detail::json extensions; + detail::JsonSetObject(extensions); + detail::JsonAddMember(o, "extensions", std::move(extensions)); + detail::FindMember(o, "extensions", it); + } + auto &extensions = detail::GetValue(it); + if (!detail::FindMember(extensions, "KHR_audio", it)) { + detail::json audio; + detail::JsonSetObject(audio); + detail::JsonAddMember(extensions, "KHR_audio", std::move(audio)); + detail::FindMember(o, "KHR_audio", it); + } + SerializeNumberProperty("emitter", node.emitter, detail::GetValue(it)); + } else { + detail::json_iterator ext_it; + if (detail::FindMember(o, "extensions", ext_it)) { + auto &extensions = detail::GetValue(ext_it); + detail::json_iterator lp_it; + if (detail::FindMember(extensions, "KHR_audio", lp_it)) { + detail::Erase(extensions, lp_it); + } + if (detail::IsEmpty(extensions)) { + detail::Erase(o, ext_it); + } + } + } + + if (!node.name.empty()) SerializeStringProperty("name", node.name, o); + SerializeNumberArrayProperty("children", node.children, o); +} + +static void SerializeGltfSampler(const Sampler &sampler, detail::json &o) { + if (!sampler.name.empty()) { + SerializeStringProperty("name", sampler.name, o); + } + if (sampler.magFilter != -1) { + SerializeNumberProperty("magFilter", sampler.magFilter, o); + } + if (sampler.minFilter != -1) { + SerializeNumberProperty("minFilter", sampler.minFilter, o); + } + // SerializeNumberProperty("wrapR", sampler.wrapR, o); + SerializeNumberProperty("wrapS", sampler.wrapS, o); + SerializeNumberProperty("wrapT", sampler.wrapT, o); + + SerializeExtrasAndExtensions(sampler, o); +} + +static void SerializeGltfOrthographicCamera(const OrthographicCamera &camera, + detail::json &o) { + SerializeNumberProperty("zfar", camera.zfar, o); + SerializeNumberProperty("znear", camera.znear, o); + SerializeNumberProperty("xmag", camera.xmag, o); + SerializeNumberProperty("ymag", camera.ymag, o); + + SerializeExtrasAndExtensions(camera, o); +} + +static void SerializeGltfPerspectiveCamera(const PerspectiveCamera &camera, + detail::json &o) { + SerializeNumberProperty("zfar", camera.zfar, o); + SerializeNumberProperty("znear", camera.znear, o); + if (camera.aspectRatio > 0) { + SerializeNumberProperty("aspectRatio", camera.aspectRatio, o); + } + + if (camera.yfov > 0) { + SerializeNumberProperty("yfov", camera.yfov, o); + } + + SerializeExtrasAndExtensions(camera, o); +} + +static void SerializeGltfCamera(const Camera &camera, detail::json &o) { + SerializeStringProperty("type", camera.type, o); + if (!camera.name.empty()) { + SerializeStringProperty("name", camera.name, o); + } + + if (camera.type.compare("orthographic") == 0) { + detail::json orthographic; + SerializeGltfOrthographicCamera(camera.orthographic, orthographic); + detail::JsonAddMember(o, "orthographic", std::move(orthographic)); + } else if (camera.type.compare("perspective") == 0) { + detail::json perspective; + SerializeGltfPerspectiveCamera(camera.perspective, perspective); + detail::JsonAddMember(o, "perspective", std::move(perspective)); + } else { + // ??? + } + + SerializeExtrasAndExtensions(camera, o); +} + +static void SerializeGltfScene(const Scene &scene, detail::json &o) { + SerializeNumberArrayProperty("nodes", scene.nodes, o); + + if (scene.name.size()) { + SerializeStringProperty("name", scene.name, o); + } + SerializeExtrasAndExtensions(scene, o); + + // KHR_audio + if (!scene.audioEmitters.empty()) { + detail::json_iterator it; + if (!detail::FindMember(o, "extensions", it)) { + detail::json extensions; + detail::JsonSetObject(extensions); + detail::JsonAddMember(o, "extensions", std::move(extensions)); + detail::FindMember(o, "extensions", it); + } + auto &extensions = detail::GetValue(it); + if (!detail::FindMember(extensions, "KHR_audio", it)) { + detail::json audio; + detail::JsonSetObject(audio); + detail::JsonAddMember(extensions, "KHR_audio", std::move(audio)); + detail::FindMember(o, "KHR_audio", it); + } + SerializeNumberArrayProperty("emitters", scene.audioEmitters, + detail::GetValue(it)); + } else { + detail::json_iterator ext_it; + if (detail::FindMember(o, "extensions", ext_it)) { + auto &extensions = detail::GetValue(ext_it); + detail::json_iterator lp_it; + if (detail::FindMember(extensions, "KHR_audio", lp_it)) { + detail::Erase(extensions, lp_it); + } + if (detail::IsEmpty(extensions)) { + detail::Erase(o, ext_it); + } + } + } +} + +static void SerializeGltfSkin(const Skin &skin, detail::json &o) { + // required + SerializeNumberArrayProperty("joints", skin.joints, o); + + if (skin.inverseBindMatrices >= 0) { + SerializeNumberProperty("inverseBindMatrices", skin.inverseBindMatrices, o); + } + + if (skin.skeleton >= 0) { + SerializeNumberProperty("skeleton", skin.skeleton, o); + } + + if (skin.name.size()) { + SerializeStringProperty("name", skin.name, o); + } + + SerializeExtrasAndExtensions(skin, o); +} + +static void SerializeGltfTexture(const Texture &texture, detail::json &o) { + if (texture.sampler > -1) { + SerializeNumberProperty("sampler", texture.sampler, o); + } + if (texture.source > -1) { + SerializeNumberProperty("source", texture.source, o); + } + if (texture.name.size()) { + SerializeStringProperty("name", texture.name, o); + } + SerializeExtrasAndExtensions(texture, o); +} + +/// +/// Serialize all properties except buffers and images. +/// +static void SerializeGltfModel(const Model *model, detail::json &o) { + // ACCESSORS + if (model->accessors.size()) { + detail::json accessors; + detail::JsonReserveArray(accessors, model->accessors.size()); + for (unsigned int i = 0; i < model->accessors.size(); ++i) { + detail::json accessor; + SerializeGltfAccessor(model->accessors[i], accessor); + detail::JsonPushBack(accessors, std::move(accessor)); + } + detail::JsonAddMember(o, "accessors", std::move(accessors)); + } + + // ANIMATIONS + if (model->animations.size()) { + detail::json animations; + detail::JsonReserveArray(animations, model->animations.size()); + for (unsigned int i = 0; i < model->animations.size(); ++i) { + if (model->animations[i].channels.size()) { + detail::json animation; + SerializeGltfAnimation(model->animations[i], animation); + detail::JsonPushBack(animations, std::move(animation)); + } + } + + detail::JsonAddMember(o, "animations", std::move(animations)); + } + + // ASSET + detail::json asset; + SerializeGltfAsset(model->asset, asset); + detail::JsonAddMember(o, "asset", std::move(asset)); + + // BUFFERVIEWS + if (model->bufferViews.size()) { + detail::json bufferViews; + detail::JsonReserveArray(bufferViews, model->bufferViews.size()); + for (unsigned int i = 0; i < model->bufferViews.size(); ++i) { + detail::json bufferView; + SerializeGltfBufferView(model->bufferViews[i], bufferView); + detail::JsonPushBack(bufferViews, std::move(bufferView)); + } + detail::JsonAddMember(o, "bufferViews", std::move(bufferViews)); + } + + // Extensions required + if (model->extensionsRequired.size()) { + SerializeStringArrayProperty("extensionsRequired", + model->extensionsRequired, o); + } + + // MATERIALS + if (model->materials.size()) { + detail::json materials; + detail::JsonReserveArray(materials, model->materials.size()); + for (unsigned int i = 0; i < model->materials.size(); ++i) { + detail::json material; + SerializeGltfMaterial(model->materials[i], material); + + if (detail::JsonIsNull(material)) { + // Issue 294. + // `material` does not have any required parameters + // so the result may be null(unmodified) when all material parameters + // have default value. + // + // null is not allowed thus we create an empty JSON object. + detail::JsonSetObject(material); + } + detail::JsonPushBack(materials, std::move(material)); + } + detail::JsonAddMember(o, "materials", std::move(materials)); + } + + // MESHES + if (model->meshes.size()) { + detail::json meshes; + detail::JsonReserveArray(meshes, model->meshes.size()); + for (unsigned int i = 0; i < model->meshes.size(); ++i) { + detail::json mesh; + SerializeGltfMesh(model->meshes[i], mesh); + detail::JsonPushBack(meshes, std::move(mesh)); + } + detail::JsonAddMember(o, "meshes", std::move(meshes)); + } + + // NODES + if (model->nodes.size()) { + detail::json nodes; + detail::JsonReserveArray(nodes, model->nodes.size()); + for (unsigned int i = 0; i < model->nodes.size(); ++i) { + detail::json node; + SerializeGltfNode(model->nodes[i], node); + + if (detail::JsonIsNull(node)) { + // Issue 457. + // `node` does not have any required parameters, + // so the result may be null(unmodified) when all node parameters + // have default value. + // + // null is not allowed thus we create an empty JSON object. + detail::JsonSetObject(node); + } + detail::JsonPushBack(nodes, std::move(node)); + } + detail::JsonAddMember(o, "nodes", std::move(nodes)); + } + + // SCENE + if (model->defaultScene > -1) { + SerializeNumberProperty("scene", model->defaultScene, o); + } + + // SCENES + if (model->scenes.size()) { + detail::json scenes; + detail::JsonReserveArray(scenes, model->scenes.size()); + for (unsigned int i = 0; i < model->scenes.size(); ++i) { + detail::json currentScene; + SerializeGltfScene(model->scenes[i], currentScene); + if (detail::JsonIsNull(currentScene)) { + // Issue 464. + // `scene` does not have any required parameters, + // so the result may be null(unmodified) when all scene parameters + // have default value. + // + // null is not allowed thus we create an empty JSON object. + detail::JsonSetObject(currentScene); + } + detail::JsonPushBack(scenes, std::move(currentScene)); + } + detail::JsonAddMember(o, "scenes", std::move(scenes)); + } + + // SKINS + if (model->skins.size()) { + detail::json skins; + detail::JsonReserveArray(skins, model->skins.size()); + for (unsigned int i = 0; i < model->skins.size(); ++i) { + detail::json skin; + SerializeGltfSkin(model->skins[i], skin); + detail::JsonPushBack(skins, std::move(skin)); + } + detail::JsonAddMember(o, "skins", std::move(skins)); + } + + // TEXTURES + if (model->textures.size()) { + detail::json textures; + detail::JsonReserveArray(textures, model->textures.size()); + for (unsigned int i = 0; i < model->textures.size(); ++i) { + detail::json texture; + SerializeGltfTexture(model->textures[i], texture); + detail::JsonPushBack(textures, std::move(texture)); + } + detail::JsonAddMember(o, "textures", std::move(textures)); + } + + // SAMPLERS + if (model->samplers.size()) { + detail::json samplers; + detail::JsonReserveArray(samplers, model->samplers.size()); + for (unsigned int i = 0; i < model->samplers.size(); ++i) { + detail::json sampler; + SerializeGltfSampler(model->samplers[i], sampler); + detail::JsonPushBack(samplers, std::move(sampler)); + } + detail::JsonAddMember(o, "samplers", std::move(samplers)); + } + + // CAMERAS + if (model->cameras.size()) { + detail::json cameras; + detail::JsonReserveArray(cameras, model->cameras.size()); + for (unsigned int i = 0; i < model->cameras.size(); ++i) { + detail::json camera; + SerializeGltfCamera(model->cameras[i], camera); + detail::JsonPushBack(cameras, std::move(camera)); + } + detail::JsonAddMember(o, "cameras", std::move(cameras)); + } + + // EXTRAS & EXTENSIONS + SerializeExtrasAndExtensions(*model, o); + + auto extensionsUsed = model->extensionsUsed; + + // LIGHTS as KHR_lights_punctual + if (model->lights.size()) { + detail::json lights; + detail::JsonReserveArray(lights, model->lights.size()); + for (unsigned int i = 0; i < model->lights.size(); ++i) { + detail::json light; + SerializeGltfLight(model->lights[i], light); + detail::JsonPushBack(lights, std::move(light)); + } + detail::json khr_lights_cmn; + detail::JsonAddMember(khr_lights_cmn, "lights", std::move(lights)); + detail::json ext_j; + + { + detail::json_const_iterator it; + if (detail::FindMember(o, "extensions", it)) { + detail::JsonAssign(ext_j, detail::GetValue(it)); + } + } + + detail::JsonAddMember(ext_j, "KHR_lights_punctual", + std::move(khr_lights_cmn)); + + detail::JsonAddMember(o, "extensions", std::move(ext_j)); + + // Also add "KHR_lights_punctual" to `extensionsUsed` + { + auto has_khr_lights_punctual = + std::find_if(extensionsUsed.begin(), extensionsUsed.end(), + [](const std::string &s) { + return (s.compare("KHR_lights_punctual") == 0); + }); + + if (has_khr_lights_punctual == extensionsUsed.end()) { + extensionsUsed.push_back("KHR_lights_punctual"); + } + } + } + + // KHR_audio + if (!model->audioEmitters.empty() || !model->audioSources.empty()) { + detail::json emitters; + detail::JsonReserveArray(emitters, model->audioEmitters.size()); + for (unsigned int i = 0; i < model->audioEmitters.size(); ++i) { + detail::json emitter; + SerializeGltfAudioEmitter(model->audioEmitters[i], emitter); + detail::JsonPushBack(emitters, std::move(emitter)); + } + detail::json khr_audio_cmn; + detail::JsonAddMember(khr_audio_cmn, "emitters", std::move(emitters)); + + detail::json sources; + detail::JsonReserveArray(sources, model->audioSources.size()); + for (unsigned int i = 0; i < model->audioSources.size(); ++i) { + detail::json source; + SerializeGltfAudioSource(model->audioSources[i], source); + detail::JsonPushBack(sources, std::move(source)); + } + detail::JsonAddMember(khr_audio_cmn, "sources", std::move(sources)); + + detail::json ext_j; + { + detail::json_const_iterator it; + if (detail::FindMember(o, "extensions", it)) { + detail::JsonAssign(ext_j, detail::GetValue(it)); + } + } + + detail::JsonAddMember(ext_j, "KHR_audio", std::move(khr_audio_cmn)); + + detail::JsonAddMember(o, "extensions", std::move(ext_j)); + + // Also add "KHR_audio" to `extensionsUsed` + { + auto has_khr_audio = std::find_if( + extensionsUsed.begin(), extensionsUsed.end(), + [](const std::string &s) { return (s.compare("KHR_audio") == 0); }); + + if (has_khr_audio == extensionsUsed.end()) { + extensionsUsed.push_back("KHR_audio"); + } + } + } + + // Extensions used + if (extensionsUsed.size()) { + SerializeStringArrayProperty("extensionsUsed", extensionsUsed, o); + } +} + +static bool WriteGltfStream(std::ostream &stream, const std::string &content) { + stream << content << std::endl; + return stream.good(); +} + +static bool WriteGltfFile(const std::string &output, + const std::string &content) { +#ifdef _WIN32 +#if defined(_MSC_VER) + std::ofstream gltfFile(UTF8ToWchar(output).c_str()); +#elif defined(__GLIBCXX__) + int file_descriptor = _wopen(UTF8ToWchar(output).c_str(), + _O_CREAT | _O_WRONLY | _O_TRUNC | _O_BINARY); + __gnu_cxx::stdio_filebuf wfile_buf( + file_descriptor, std::ios_base::out | std::ios_base::binary); + std::ostream gltfFile(&wfile_buf); + if (!wfile_buf.is_open()) return false; +#else + std::ofstream gltfFile(output.c_str()); + if (!gltfFile.is_open()) return false; +#endif +#else + std::ofstream gltfFile(output.c_str()); + if (!gltfFile.is_open()) return false; +#endif + return WriteGltfStream(gltfFile, content); +} + +static bool WriteBinaryGltfStream(std::ostream &stream, + const std::string &content, + const std::vector &binBuffer) { + const std::string header = "glTF"; + const int version = 2; + + const uint32_t content_size = uint32_t(content.size()); + const uint32_t binBuffer_size = uint32_t(binBuffer.size()); + // determine number of padding bytes required to ensure 4 byte alignment + const uint32_t content_padding_size = + content_size % 4 == 0 ? 0 : 4 - content_size % 4; + const uint32_t bin_padding_size = + binBuffer_size % 4 == 0 ? 0 : 4 - binBuffer_size % 4; + + // 12 bytes for header, JSON content length, 8 bytes for JSON chunk info. + // Chunk data must be located at 4-byte boundary, which may require padding + const uint32_t length = + 12 + 8 + content_size + content_padding_size + + (binBuffer_size ? (8 + binBuffer_size + bin_padding_size) : 0); + + stream.write(header.c_str(), std::streamsize(header.size())); + stream.write(reinterpret_cast(&version), sizeof(version)); + stream.write(reinterpret_cast(&length), sizeof(length)); + + // JSON chunk info, then JSON data + const uint32_t model_length = uint32_t(content.size()) + content_padding_size; + const uint32_t model_format = 0x4E4F534A; + stream.write(reinterpret_cast(&model_length), + sizeof(model_length)); + stream.write(reinterpret_cast(&model_format), + sizeof(model_format)); + stream.write(content.c_str(), std::streamsize(content.size())); + + // Chunk must be multiplies of 4, so pad with spaces + if (content_padding_size > 0) { + const std::string padding = std::string(size_t(content_padding_size), ' '); + stream.write(padding.c_str(), std::streamsize(padding.size())); + } + if (binBuffer.size() > 0) { + // BIN chunk info, then BIN data + const uint32_t bin_length = uint32_t(binBuffer.size()) + bin_padding_size; + const uint32_t bin_format = 0x004e4942; + stream.write(reinterpret_cast(&bin_length), + sizeof(bin_length)); + stream.write(reinterpret_cast(&bin_format), + sizeof(bin_format)); + stream.write(reinterpret_cast(binBuffer.data()), + std::streamsize(binBuffer.size())); + // Chunksize must be multiplies of 4, so pad with zeroes + if (bin_padding_size > 0) { + const std::vector padding = + std::vector(size_t(bin_padding_size), 0); + stream.write(reinterpret_cast(padding.data()), + std::streamsize(padding.size())); + } + } + + stream.flush(); + return stream.good(); +} + +static bool WriteBinaryGltfFile(const std::string &output, + const std::string &content, + const std::vector &binBuffer) { +#ifdef _WIN32 +#if defined(_MSC_VER) + std::ofstream gltfFile(UTF8ToWchar(output).c_str(), std::ios::binary); +#elif defined(__GLIBCXX__) + int file_descriptor = _wopen(UTF8ToWchar(output).c_str(), + _O_CREAT | _O_WRONLY | _O_TRUNC | _O_BINARY); + __gnu_cxx::stdio_filebuf wfile_buf( + file_descriptor, std::ios_base::out | std::ios_base::binary); + std::ostream gltfFile(&wfile_buf); +#else + std::ofstream gltfFile(output.c_str(), std::ios::binary); +#endif +#else + std::ofstream gltfFile(output.c_str(), std::ios::binary); +#endif + return WriteBinaryGltfStream(gltfFile, content, binBuffer); +} + +bool TinyGLTF::WriteGltfSceneToStream(const Model *model, std::ostream &stream, + bool prettyPrint = true, + bool writeBinary = false) { + detail::JsonDocument output; + + /// Serialize all properties except buffers and images. + SerializeGltfModel(model, output); + + // BUFFERS + std::vector binBuffer; + if (model->buffers.size()) { + detail::json buffers; + detail::JsonReserveArray(buffers, model->buffers.size()); + for (unsigned int i = 0; i < model->buffers.size(); ++i) { + detail::json buffer; + if (writeBinary && i == 0 && model->buffers[i].uri.empty()) { + SerializeGltfBufferBin(model->buffers[i], buffer, binBuffer); + } else { + SerializeGltfBuffer(model->buffers[i], buffer); + } + detail::JsonPushBack(buffers, std::move(buffer)); + } + detail::JsonAddMember(output, "buffers", std::move(buffers)); + } + + // IMAGES + if (model->images.size()) { + detail::json images; + detail::JsonReserveArray(images, model->images.size()); + for (unsigned int i = 0; i < model->images.size(); ++i) { + detail::json image; + + std::string dummystring; + // UpdateImageObject need baseDir but only uses it if embeddedImages is + // enabled, since we won't write separate images when writing to a stream + // we + std::string uri; + if (!UpdateImageObject(model->images[i], dummystring, int(i), true, + &uri_cb, &this->WriteImageData, + this->write_image_user_data_, &uri)) { + return false; + } + SerializeGltfImage(model->images[i], uri, image); + detail::JsonPushBack(images, std::move(image)); + } + detail::JsonAddMember(output, "images", std::move(images)); + } + + if (writeBinary) { + return WriteBinaryGltfStream(stream, detail::JsonToString(output), + binBuffer); + } else { + return WriteGltfStream(stream, + detail::JsonToString(output, prettyPrint ? 2 : -1)); + } +} + +bool TinyGLTF::WriteGltfSceneToFile(const Model *model, + const std::string &filename, + bool embedImages = false, + bool embedBuffers = false, + bool prettyPrint = true, + bool writeBinary = false) { + detail::JsonDocument output; + std::string defaultBinFilename = GetBaseFilename(filename); + std::string defaultBinFileExt = ".bin"; + std::string::size_type pos = + defaultBinFilename.rfind('.', defaultBinFilename.length()); + + if (pos != std::string::npos) { + defaultBinFilename = defaultBinFilename.substr(0, pos); + } + std::string baseDir = GetBaseDir(filename); + if (baseDir.empty()) { + baseDir = "./"; + } + /// Serialize all properties except buffers and images. + SerializeGltfModel(model, output); + + // BUFFERS + std::vector usedFilenames; + std::vector binBuffer; + if (model->buffers.size()) { + detail::json buffers; + detail::JsonReserveArray(buffers, model->buffers.size()); + for (unsigned int i = 0; i < model->buffers.size(); ++i) { + detail::json buffer; + if (writeBinary && i == 0 && model->buffers[i].uri.empty()) { + SerializeGltfBufferBin(model->buffers[i], buffer, binBuffer); + } else if (embedBuffers) { + SerializeGltfBuffer(model->buffers[i], buffer); + } else { + std::string binSavePath; + std::string binFilename; + std::string binUri; + if (!model->buffers[i].uri.empty() && + !IsDataURI(model->buffers[i].uri)) { + binUri = model->buffers[i].uri; + if (!uri_cb.decode(binUri, &binFilename, uri_cb.user_data)) { + return false; + } + } else { + binFilename = defaultBinFilename + defaultBinFileExt; + bool inUse = true; + int numUsed = 0; + while (inUse) { + inUse = false; + for (const std::string &usedName : usedFilenames) { + if (binFilename.compare(usedName) != 0) continue; + inUse = true; + binFilename = defaultBinFilename + std::to_string(numUsed++) + + defaultBinFileExt; + break; + } + } + + if (uri_cb.encode) { + if (!uri_cb.encode(binFilename, "buffer", &binUri, + uri_cb.user_data)) { + return false; + } + } else { + binUri = binFilename; + } + } + usedFilenames.push_back(binFilename); + binSavePath = JoinPath(baseDir, binFilename); + if (!SerializeGltfBuffer(model->buffers[i], buffer, binSavePath, + binUri)) { + return false; + } + } + detail::JsonPushBack(buffers, std::move(buffer)); + } + detail::JsonAddMember(output, "buffers", std::move(buffers)); + } + + // IMAGES + if (model->images.size()) { + detail::json images; + detail::JsonReserveArray(images, model->images.size()); + for (unsigned int i = 0; i < model->images.size(); ++i) { + detail::json image; + + std::string uri; + if (!UpdateImageObject(model->images[i], baseDir, int(i), embedImages, + &uri_cb, &this->WriteImageData, + this->write_image_user_data_, &uri)) { + return false; + } + SerializeGltfImage(model->images[i], uri, image); + detail::JsonPushBack(images, std::move(image)); + } + detail::JsonAddMember(output, "images", std::move(images)); + } + + if (writeBinary) { + return WriteBinaryGltfFile(filename, detail::JsonToString(output), + binBuffer); + } else { + return WriteGltfFile(filename, + detail::JsonToString(output, (prettyPrint ? 2 : -1))); + } +} + +} // namespace tinygltf + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#endif // TINYGLTF_IMPLEMENTATION \ No newline at end of file diff --git a/tools/dkr_assets_tool_classes/libs/zip_file.hpp b/tools/dkr_assets_tool_src/libs/zip_file.hpp similarity index 100% rename from tools/dkr_assets_tool_classes/libs/zip_file.hpp rename to tools/dkr_assets_tool_src/libs/zip_file.hpp diff --git a/tools/dkr_assets_tool_src/main.cpp b/tools/dkr_assets_tool_src/main.cpp new file mode 100644 index 00000000..cf1b8e36 --- /dev/null +++ b/tools/dkr_assets_tool_src/main.cpp @@ -0,0 +1,96 @@ +#include +#include + +#include "libs/argparse.hpp" + +#include "helpers/jsonHelper.h" +#include "helpers/debugHelper.h" + +#include "misc/settings.hpp" + +#include "extract/extractor.h" +#include "builder/builder.h" +#include "prebuild/prebuild.h" +#include "test/test.h" + +/*******************************************************************************************************/ + +int main(int argc, char *argv[]) { + argparse::ArgumentParser args(DKRAT_NAME, DKRAT_VERSION); + + DkrAssetsSettings settings; + + /*** Extract tool ***/ + argparse::ArgumentParser extract("extract"); + + /*** Build tool ***/ + argparse::ArgumentParser builder("build"); + + /*** Pre-Build tool ***/ + argparse::ArgumentParser prebuild("prebuild"); + + /*** Test tool (For testing functionality) ***/ + argparse::ArgumentParser tester("test"); + + builder.add_argument("-i", "--input") + .required() + .help("Input JSON filepath."); + + builder.add_argument("-o", "--output") + .required() + .help("Output path."); + + args.add_subparser(extract); + args.add_subparser(builder); + args.add_subparser(prebuild); + args.add_subparser(tester); + + args.add_argument("-dkrv", "--dkr_version") + .default_value(settings.dkrVersion) + .help("Which version of DKR to use. Overrides default."); + + args.add_argument("-vb", "--verbose") + .default_value(DEFAULT_VERBOSE_VALUE) + .implicit_value(true) + .help("Which version of DKR to use. Overrides default."); + + try { + args.parse_args(argc, argv); + } catch (const std::exception &err) { + if(args.is_subcommand_used(extract)) { + std::cout << extract << std::endl; + } else if(args.is_subcommand_used(builder)) { + std::cout << builder << std::endl; + } + DebugHelper::error(err.what()); + } + + settings.dkrVersion = args.get("-dkrv"); + DebugHelper::get().set_verbose(args.get("-vb")); + DebugHelper::get().set_asserts(USING_ASSERTS); + + if(args.is_subcommand_used(extract)) { + //settings.print(); + DkrExtract extract(settings); + return 0; + } + if(args.is_subcommand_used(builder)) { + std::string inputPath = builder.get("-i"); + std::string outputPath = builder.get("-o"); + //settings.print(); + DkrAssetBuilder builder(settings, inputPath, outputPath); + return 0; + } + if(args.is_subcommand_used(tester)) { + //settings.print(); + TestDKRAT test(settings); + return 0; + } + if(args.is_subcommand_used(prebuild)) { + //settings.print(); + PreBuild prebuild(settings); + return 0; + } + + return 0; +} diff --git a/tools/dkr_assets_tool_src/misc/constants.hpp b/tools/dkr_assets_tool_src/misc/constants.hpp new file mode 100644 index 00000000..2f7ffd67 --- /dev/null +++ b/tools/dkr_assets_tool_src/misc/constants.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include + +const std::string DKRAT_NAME = "DKR Assets Tool"; +const std::string DKRAT_VERSION = "Revision 4"; +const int DKRAT_REVISION_MAJOR = 4; +const int DKRAT_REVISION_MINOR = 0; + +const std::string DKRAT_SETTINGS_FILE = "dkr_assets_tool_settings.json"; + +const std::string DEFAULT_DKR_VERSION = "us_1.0"; +const std::string DEFAULT_BASEROMS_SUBPATH = "baseroms/"; +const std::string DEFAULT_ASSETS_SUBPATH = "assets/"; +const std::string DEFAULT_CONFIGS_SUBPATH = "extract-ver/"; +const std::string DEFAULT_INCLUDE_SUBPATH = "include/"; +const std::string DEFAULT_ASM_SUBPATH = "asm/"; +const std::string DEFAULT_SRC_SUBPATH = "src/"; +const std::string DEFAULT_LIB_ASM_SUBPATH = "lib/asm/"; +const std::string DEFAULT_LIB_SRC_SUBPATH = "lib/src/"; +const std::string DEFAULT_DATA_SUBPATH = "data/"; +const std::string DEFAULT_BUILD_SUBPATH = "build/"; +const std::string DEFAULT_CACHE_SUBPATH = ".cache/"; +const std::string DEFAULT_MODS_SUBPATH = "mods/"; +const std::string DEFAULT_MOD_ASSETS_SUBPATH = "assets/"; + +// Debugging stuff +const bool DEFAULT_VERBOSE_VALUE = true; +const bool USING_ASSERTS = true; + +const double DEFAULT_MODEL_SCALE_GLTF = 1.0 / 1000.0; diff --git a/tools/dkr_assets_tool_src/misc/settings.hpp b/tools/dkr_assets_tool_src/misc/settings.hpp new file mode 100644 index 00000000..c56f2cff --- /dev/null +++ b/tools/dkr_assets_tool_src/misc/settings.hpp @@ -0,0 +1,190 @@ +#pragma once + +#include +#include +#include +#include +#include "helpers/fileHelper.h" +#include "helpers/debugHelper.h" +#include "helpers/jsonHelper.h" +#include "misc/constants.hpp" + +// Some paths to find if a directory is considered to be the "root" of the decomp. +const std::vector REPO_ROOT_FIND_PATHS = { + "src", + "lib", + "include", + "baseroms", + "README.md" +}; + +struct DkrAssetsSettings { + std::string dkrVersion; + + // TODO: Maybe redo this? Feels like it could be better. + fs::path pathToRepo; + fs::path pathToBaseroms; + fs::path pathToAssets; + fs::path pathToConfigs; + fs::path pathToInclude; + fs::path pathToAsm; + fs::path pathToSrc; + fs::path pathToLibAsm; + fs::path pathToLibSrc; + fs::path pathToData; + fs::path pathToBuild; + fs::path pathToCache; + fs::path pathToMods; + fs::path pathToModAssets; + + double modelScale; + size_t threadCount; + + // Keep binary copies of uncompressed data. (For comparison). + bool debugExtractKeepUncompressed; + bool debugBuildKeepUncompressed; + + void print() { + DebugHelper::info( + "\n--------------- Settings ---------------", + "\n DKR Version: ", dkrVersion, + "\n Repo Path: ", pathToRepo, + "\n Baseroms Path: ", pathToBaseroms, + "\n Assets Path: ", pathToAssets, + "\n Configs Path: ", pathToConfigs, + "\n Include Path: ", pathToInclude, + "\n ASM Path: ", pathToAsm, + "\n Src Path: ", pathToSrc, + "\n Lib ASM Path: ", pathToLibAsm, + "\n Lib Src Path: ", pathToLibSrc, + "\n Data Path: ", pathToData, + "\n Build Path: ", pathToBuild, + "\n Model Scale: ", modelScale, + "\n Mods Path: ", pathToMods, + "\n Mod Assets Path: ", pathToModAssets, + "\n Threads: ", threadCount, + "\n----------------------------------------" + ); + } + + template + double adjust_to_model_scale(T val) { + return ((double)val) * modelScale; + } + + template + double adjust_from_model_scale(T val) { + return std::round(((double)val) * (1.0 / modelScale)); + } + + fs::path find_repo_root() { + fs::path start = fs::absolute("."); + fs::path cur = start; + + while(cur.has_parent_path()) { + bool foundIt = true; + for(const fs::path &findFile : REPO_ROOT_FIND_PATHS) { + if(!FileHelper::path_exists(cur / findFile)) { + foundIt = false; + break; + } + } + if(foundIt) { + return fs::relative(cur, start); + } + cur = cur.parent_path(); // Go up one level. + } + + DebugHelper::error("Could not find the DKR repo path from: ", start); + return ""; + } + + void load_from_json(const std::string &jsonPath) { + _settingsFileExists = JsonHelper::get().get_file(jsonPath, &_settingsJson); + + _load_string_from_ptr(dkrVersion, "/default_dkr_version", DEFAULT_DKR_VERSION); + + _load_bool_from_ptr(debugExtractKeepUncompressed, "/debug/keep-uncompressed", false); + _load_bool_from_ptr(debugBuildKeepUncompressed, "/debug/keep-uncompressed", false); + + _load_path_from_ptr(pathToRepo, "/repo_path", find_repo_root()); + + // Internal cache directory to be used for this tool only. + _load_path_from_ptr(pathToCache, "/cache", DEFAULT_CACHE_SUBPATH); + + // Load subpaths + _load_subpath_from_ptr(pathToBaseroms, "/baseroms_subpath", DEFAULT_BASEROMS_SUBPATH); + _load_subpath_from_ptr(pathToAssets, "/assets_subpath" , DEFAULT_ASSETS_SUBPATH); + _load_subpath_from_ptr(pathToConfigs, "/configs_subpath" , DEFAULT_CONFIGS_SUBPATH); + _load_subpath_from_ptr(pathToInclude, "/include_subpath" , DEFAULT_INCLUDE_SUBPATH); + _load_subpath_from_ptr(pathToMods, "/mods_subpath", DEFAULT_MODS_SUBPATH); + + std::string localAsmPath; + std::string localSrcPath; + std::string localLibAsmPath; + std::string localLibSrcPath; + std::string localModAssetsPath; + + _load_string_from_ptr(localAsmPath, "/asm_subpath", DEFAULT_ASM_SUBPATH); + _load_string_from_ptr(localSrcPath, "/src_subpath", DEFAULT_SRC_SUBPATH); + _load_string_from_ptr(localLibAsmPath, "/lib_asm_subpath", DEFAULT_LIB_ASM_SUBPATH); + _load_string_from_ptr(localLibSrcPath, "/lib_src_subpath", DEFAULT_LIB_SRC_SUBPATH); + _load_string_from_ptr(localModAssetsPath, "/mod_assets_subpath", DEFAULT_MOD_ASSETS_SUBPATH); + + _format_subpath(pathToAsm, pathToRepo, localAsmPath); + _format_subpath(pathToSrc, pathToRepo, localSrcPath); + _format_subpath(pathToLibAsm, pathToRepo, localLibAsmPath); + _format_subpath(pathToLibSrc, pathToRepo, localLibSrcPath); + _format_subpath(pathToModAssets, pathToMods, localModAssetsPath); + + // Build subdirectories + _load_subpath_from_ptr(pathToBuild, "/build_subpath", DEFAULT_BUILD_SUBPATH); + + _load_subpath_from_ptr(pathToData, "/data_subpath", DEFAULT_DATA_SUBPATH); + + _load_float_ptr(modelScale, "/model_scale", DEFAULT_MODEL_SCALE_GLTF); + + _load_size_ptr(threadCount, "/threads", (size_t)std::thread::hardware_concurrency()); + } + + DkrAssetsSettings() { + pathToRepo = find_repo_root(); + load_from_json(pathToRepo / "tools" / DKRAT_SETTINGS_FILE); + } + +private: + bool _settingsFileExists; + JsonFile *_settingsJson; + + void _format_subpath(fs::path &pathVar, fs::path &parent, std::string &child) { + pathVar = parent / fs::path(child); + FileHelper::format_folder_string(pathVar); + } + + void _load_subpath_from_ptr(fs::path &pathVar, const char *ptr, const std::string defaultValue) { + pathVar = pathToRepo; + pathVar /= (_settingsFileExists) ? _settingsJson->get_string(ptr, defaultValue) : defaultValue; + FileHelper::format_folder_string(pathVar); + } + + void _load_path_from_ptr(fs::path &pathVar, const char *ptr, const std::string defaultValue) { + pathVar = (_settingsFileExists) ? _settingsJson->get_string(ptr, defaultValue) : defaultValue; + FileHelper::format_folder_string(pathVar); + } + + void _load_string_from_ptr(std::string &strVar, const char *ptr, const std::string defaultValue) { + strVar = (_settingsFileExists) ? _settingsJson->get_string(ptr, defaultValue) : defaultValue; + } + + void _load_bool_from_ptr(bool &strVar, const char *ptr, const bool defaultValue) { + strVar = (_settingsFileExists) ? _settingsJson->get_bool(ptr, defaultValue) : defaultValue; + } + + void _load_float_ptr(double &doubleVar, const char *ptr, const double defaultValue) { + doubleVar = (_settingsFileExists) ? _settingsJson->get_float(ptr, defaultValue) : defaultValue; + } + + void _load_size_ptr(size_t &sizeVar, const char *ptr, const size_t defaultValue) { + sizeVar = (_settingsFileExists) ? _settingsJson->get_int(ptr, defaultValue) : defaultValue; + } +}; diff --git a/tools/dkr_assets_tool_src/prebuild/compileAssets/compile.cpp b/tools/dkr_assets_tool_src/prebuild/compileAssets/compile.cpp new file mode 100644 index 00000000..260cec49 --- /dev/null +++ b/tools/dkr_assets_tool_src/prebuild/compileAssets/compile.cpp @@ -0,0 +1,214 @@ +#include "compile.h" + +#include "helpers/dataHelper.h" +#include "libs/zip_file.hpp" + +CompileAssets::CompileAssets(DkrAssetsSettings &settings) : _settings(settings) { + _vanillaAssetsPath = _settings.pathToAssets / ".vanilla" / settings.dkrVersion; + _outAssetsPath = _settings.pathToAssets / settings.dkrVersion; + + _statFile = new StatJsonFile(_settings.pathToCache / "compileAssetsCache.json"); + + // Load order.json + DebugHelper::assert_(JsonHelper::get().get_file(_settings.pathToModAssets / "order.json", &_modOrderFile), + "Failed to get order.json for compiling!"); + + _modOrderCount = _modOrderFile->length_of_array("/order"); + + bool doCompile = + _compile_check_assets_exist() || + _compile_check_order_size(); + + if(!doCompile && (_modOrderCount > 0)) { + // Only do these checks if there are any entries in the order.json file. + doCompile = _compile_check_order_of_mods() || + _compile_check_order_files_updated(); + } + + if(doCompile) { + _compile_assets(); + _update_last_mod_order(); + _statFile->save(); + } +} + +CompileAssets::~CompileAssets() { + delete _statFile; +} + +void CompileAssets::_check_mod_path(fs::path &modPath) { + if(!FileHelper::path_exists(modPath)) { + // This might just be a zip file. See if adding .zip as the extension will find it. + fs::path tryZipPath = modPath; + tryZipPath.replace_extension(".zip"); + if(FileHelper::path_exists(tryZipPath)) { + modPath = tryZipPath; + } else { + DebugHelper::error("(CompileAssets::_check_mod_path) Path ", modPath, " does not exist!"); + } + } +} + +// Check if the main assets folder exists. +bool CompileAssets::_compile_check_assets_exist() { + return !FileHelper::path_exists(_outAssetsPath); +} + +// Check if the number of mods has changed. +bool CompileAssets::_compile_check_order_size() { + size_t lastOrderCount = _statFile->get_value("/last-order-size", 0); + return _modOrderCount != lastOrderCount; +} + +// Check if the order of the mods was changed. +bool CompileAssets::_compile_check_order_of_mods() { + if(_modOrderCount < 2) { + return false; + } + for(size_t i = 0; i < _modOrderCount; i++) { + std::string modName = _modOrderFile->get_string("/order/" + std::to_string(i)); + std::string lastModName = _statFile->get_value("/last-mod-order/" + std::to_string(i) , ""); + if(modName != lastModName) { + return true; + } + } + + return false; +} + +void CompileAssets::_update_last_mod_order() { + for(size_t i = 0; i < _modOrderCount; i++) { + std::string modName = _modOrderFile->get_string("/order/" + std::to_string(i)); + _statFile->set_value("/last-mod-order/" + std::to_string(i), modName); + } +} + +// Check if any of the mod files have been updated. +bool CompileAssets::_compile_check_order_files_updated() { + for(size_t i = 0; i < _modOrderCount; i++) { + std::string modFolderName = _modOrderFile->get_string("/order/" + std::to_string(i)); + + if(modFolderName.empty()) { + continue; + } + + fs::path modPath = _settings.pathToModAssets / modFolderName; + + // Make sure the path is valid. + _check_mod_path(modPath); + + // is_zip_file() checks the first 4 bytes to see if the file contains the standard .zip signature. + if(FileHelper::is_zip_file(modPath)) { + // If it is a zip file, then we only care about the archive file itself. Not it's contents + _lastModifiedDates[modPath] = FileHelper::get_last_modified_timestamp(modPath); + } else { + // Insert the timestamps from all the files in modPath into _lastModifiedDates + FileHelper::insert_timestamps_from_directory(modPath, _lastModifiedDates); + } + } + + _modFilesModified.clear(); + + for(auto &pair : _lastModifiedDates) { + std::string statModifiedDate = _statFile->get_entry(pair.first); + + // If the file isn't on record, or if the modified date has changed, then we should compile! + if(statModifiedDate.empty() || (statModifiedDate != pair.second)) { + _statFile->set_entry(pair.first, pair.second); + _modFilesModified.push_back(pair.first); + } + } + + return _modFilesModified.size() > 0; +} + +void CompileAssets::_compile_assets() { + DebugHelper::info("Compiling assets..."); + + _statFile->set_value("/last-order-size", _modOrderCount); + + // First copy the vanilla path to the out path. + // This seems to be the slowest part, mainly limited by IO speed (copying thousands of small files). + FileHelper::copy(_vanillaAssetsPath, _outAssetsPath, true); + + if(_modOrderCount == 0) { + DebugHelper::info("Done! (Vanilla)"); + return; + } + + _merge_and_copy_files(); + + DebugHelper::info("Done! (", _modOrderCount, (_modOrderCount == 1) ? " mod)" : " mods)"); +} + +void CompileAssets::_merge_and_copy_files() { + std::vector modDirectories(_modOrderCount); + + for(size_t i = 0; i < _modOrderCount; i++) { + std::string modFolderName = _modOrderFile->get_string("/order/" + std::to_string(i)); + + if(modFolderName.empty()) { + continue; + } + + modDirectories[i] = _settings.pathToModAssets / modFolderName; + + // Make sure the path exists. + _check_mod_path(modDirectories[i]); + } + + for(fs::path &modDir : modDirectories) { + if(FileHelper::is_zip_file(modDir)) { + DebugHelper::info_verbose("Applying Asset Mod: ", modDir, " (zip archive)"); + + fs::path modName = modDir.stem(); + + fs::path extractedDir = _settings.pathToModAssets / ".extracted"; + + const bool zipFileHasChanged = DataHelper::vector_has(_modFilesModified, modDir); + + // Only extract if the zip file changed or if the mod's extracted folder does not exist. + if(zipFileHasChanged || !FileHelper::path_exists(extractedDir / modName)) { + DebugHelper::info_verbose("Extracting: ", modDir); + + miniz_cpp::zip_file file(modDir); + // Make sure a subdirectory with the name of the mod exists in the .extracted directory. + if(file.has_file("meta.json")) { + extractedDir /= modName; + } + FileHelper::write_folder_if_it_does_not_exist(extractedDir); + file.extractall(extractedDir); + } + + modDir = _settings.pathToModAssets / ".extracted" / modName; + + DebugHelper::assert_(FileHelper::path_exists(modDir), + "(CompileAssets::_merge_and_copy_files) Path ", modDir, " does not exist!"); + } else { + DebugHelper::info_verbose("Applying Asset Mod: ", modDir); + } + + FileHelper::append_files_from_directory_relative(modDir, _modFiles[modDir]); + for(fs::path &path : _modFiles[modDir]) { + if(FileHelper::does_filename_equal(path, "meta.json")) { + // Don't copy meta.json over. + continue; + } + _merge_or_copy_file(modDir, path); + } + } +} + +void CompileAssets::_merge_or_copy_file(fs::path &modDir, fs::path &path) { + fs::path modPath = modDir / path; + fs::path outPath = _outAssetsPath / path; + + bool copyFile = (path.extension() != ".json") || !FileHelper::path_exists(outPath); + + if(copyFile) { + FileHelper::copy(modPath, outPath); + } else { // Merge file + JsonHelper::get().patch_json(outPath, modPath); + } + +} \ No newline at end of file diff --git a/tools/dkr_assets_tool_src/prebuild/compileAssets/compile.h b/tools/dkr_assets_tool_src/prebuild/compileAssets/compile.h new file mode 100644 index 00000000..a485441a --- /dev/null +++ b/tools/dkr_assets_tool_src/prebuild/compileAssets/compile.h @@ -0,0 +1,39 @@ +#pragma once + +#include +#include + +#include "helpers/jsonHelper.h" +#include "helpers/fileHelper.h" + +#include "misc/settings.hpp" + +class CompileAssets { +public: + CompileAssets(DkrAssetsSettings &settings); + ~CompileAssets(); +private: + DkrAssetsSettings &_settings; + fs::path _outAssetsPath; + fs::path _vanillaAssetsPath; + StatJsonFile *_statFile; + JsonFile *_modOrderFile; + size_t _modOrderCount; + + std::unordered_map _lastModifiedDates; + std::unordered_map> _modFiles; + std::vector _modFilesModified; + + void _check_mod_path(fs::path &modPath); + + bool _compile_check_assets_exist(); + bool _compile_check_order_size(); + bool _compile_check_order_of_mods(); + bool _compile_check_order_files_updated(); + + void _update_last_mod_order(); + + void _compile_assets(); + void _merge_and_copy_files(); + void _merge_or_copy_file(fs::path &modDir, fs::path &path); +}; diff --git a/tools/dkr_assets_tool_src/prebuild/linker/ld.cpp b/tools/dkr_assets_tool_src/prebuild/linker/ld.cpp new file mode 100644 index 00000000..18f2319a --- /dev/null +++ b/tools/dkr_assets_tool_src/prebuild/linker/ld.cpp @@ -0,0 +1,79 @@ +#include "ld.h" + +#include "helpers/fileHelper.h" + +const size_t INDENT_AMOUNT = 4; // Indent by 4 spaces + +WritableLD::WritableLD(DkrAssetsSettings &settings) : _settings(settings) { +} + +WritableLD::~WritableLD() { +} + +void WritableLD::write_comment(const char *text) { + _out << _indent << "/* " << text << " */" << std::endl; +} + +void WritableLD::write_include(const char *text) { + _out << _indent << "#include \"" << text << "\"" << std::endl; +} + +void WritableLD::write_arch(const char *archName) { + _out << _indent << "OUTPUT_ARCH (" << archName << ")" << std::endl; +} + +void WritableLD::write_rom_pos_at(const char *value) { + _out << _indent << "romPos = " << value << ";" << std::endl; +} + +void WritableLD::write_add_to_rom_pos(const char *value) { + _out << _indent << "romPos += " << value << ";" << std::endl; +} + +void WritableLD::write_assignment(const char *var, const char *value) { + _out << _indent << var << " = " << value << ";" << std::endl; +} + +void WritableLD::write_section_header(const char *name, const char *ramPos, const char *romPos, const LD_SUBALIGN subalign) { + _out << _indent << "." << name << " " << ramPos << " : AT(" << romPos << ")"; + if(subalign != LD_SUBALIGN::NONE) { + _out << " SUBALIGN(" << subalign << ")"; + } + _out << std::endl; +} + +void WritableLD::write_raw(const char *text) { + _out << _indent << text; +} + +void WritableLD::write_raw_line(const char *text) { + _out << _indent << text << std::endl; +} + +void WritableLD::write_raw_line(const std::string text) { + write_raw_line(text.c_str()); +} + +void WritableLD::write_open_brace() { + _out << _indent << "{" << std::endl; + _indent.append(INDENT_AMOUNT, ' '); // Add 4 spaces to the indent +} + +void WritableLD::write_close_brace() { + if (_indent.size() > INDENT_AMOUNT) { + _indent.resize(_indent.size() - INDENT_AMOUNT); // Remove 4 spaces from the indent + } else { + _indent.clear(); + } + _out << _indent << "}" << std::endl; +} + +void WritableLD::write_newline() { + _out << std::endl; +} + +void WritableLD::save(const std::string &filepath) { + std::string ldText = _out.str(); + FileHelper::write_text_file(ldText, filepath, true); +} + diff --git a/tools/dkr_assets_tool_src/prebuild/linker/ld.h b/tools/dkr_assets_tool_src/prebuild/linker/ld.h new file mode 100644 index 00000000..ddbc17d0 --- /dev/null +++ b/tools/dkr_assets_tool_src/prebuild/linker/ld.h @@ -0,0 +1,46 @@ +#pragma once + +#include +#include + +#include "misc/settings.hpp" + +enum LD_SUBALIGN { + NONE = 0, + ALIGN4 = 4, + ALIGN8 = 8, + ALIGN16 = 16 +}; + +// Creates a read-only linker +class WritableLD { +public: + WritableLD(DkrAssetsSettings &settings); + ~WritableLD(); + + void write_comment(const char *text); + void write_include(const char *text); + void write_arch(const char *archName); + void write_raw(const char *text); + void write_raw_line(const char *text); + void write_raw_line(const std::string text); + + void write_assignment(const char *var, const char *value); + + void write_rom_pos_at(const char *value); + void write_add_to_rom_pos(const char *value); + + void write_section_header(const char *name, const char *ramPos, const char *romPos, const LD_SUBALIGN subalign); + + void write_open_brace(); + void write_close_brace(); + void write_newline(); + + + void save(const std::string &filepath); +private: + DkrAssetsSettings &_settings; + + std::string _indent; + std::stringstream _out; +}; \ No newline at end of file diff --git a/tools/dkr_assets_tool_src/prebuild/makeIncludes/assetEnums.cpp b/tools/dkr_assets_tool_src/prebuild/makeIncludes/assetEnums.cpp new file mode 100644 index 00000000..98d4cd74 --- /dev/null +++ b/tools/dkr_assets_tool_src/prebuild/makeIncludes/assetEnums.cpp @@ -0,0 +1,104 @@ +#include "assetEnums.h" + +#include "helpers/assetsHelper.h" +#include "helpers/stringHelper.h" +#include "helpers/c/cEnumsHelper.h" + +AssetEnums::AssetEnums(DkrAssetsSettings &settings) : _settings(settings) { + _outFilepath = _settings.pathToInclude / "/asset_enums.h"; + + _cHeader.write_comment("This file is automatically generated. Any changes you make to this file will get overwritten."); + _cHeader.write_newline(); + + _cHeader.write_raw_text_line("#ifndef _ASSET_ENUMS_H"); + _cHeader.write_raw_text_line("#define _ASSET_ENUMS_H"); + _cHeader.write_newline(); + + _cHeader.write_header_comment("Asset Sections"); + _write_asset_section_enums(); + _cHeader.write_newline(); + + _cHeader.write_raw_text_line("#endif"); + + _cHeader.save(_outFilepath); +} + +AssetEnums::~AssetEnums() { + +} + +void AssetEnums::_write_asset_section_enums() { + JsonFile *mainJson = AssetsHelper::get_main_json(_settings); + + std::vector mainOrder; + mainJson->get_array("/assets/order", mainOrder); + + _write_main_asset_enum(mainOrder); + + for(std::string §ionId : mainOrder) { + JsonFile *sectionJson = AssetsHelper::get_asset_section_json(_settings, sectionId); + + if(sectionJson != nullptr) { + if(sectionJson->has("/files")) { + _cHeader.write_newline(); + _cHeader.write_header_comment(sectionId.c_str()); + _write_asset_section_enums(sectionId, sectionJson); + } + continue; + } + + std::string sectionPtr = "/assets/sections/" + sectionId; + + bool isDeferred = mainJson->get_bool(sectionPtr + "/deferred"); + + if(isDeferred) { + std::string deferInfoPtr = sectionPtr + "/defer-info"; + _cHeader.write_newline(); + _cHeader.write_header_comment(sectionId.c_str()); + _write_deferred_asset_section_enums(sectionId, mainJson, deferInfoPtr); + } + } +} + +void AssetEnums::_write_main_asset_enum(std::vector &mainOrder) { + WriteableCEnum mainEnum("AssetSectionsEnum"); + for(std::string §ionId : mainOrder) { + mainEnum.add_symbol(sectionId); + } + _cHeader.write_raw_text(mainEnum.to_string()); +} + +void AssetEnums::_write_asset_section_enums(const std::string §ionId, JsonFile *sectionJson) { + std::string sectionEnumName = StringHelper::upper_snake_case_to_pascal_case(sectionId) + "Enum"; + WriteableCEnum sectionEnum(sectionEnumName); + + std::vector sectionOrder; + sectionJson->get_array("/files/order", sectionOrder); + + for(std::string &assetBuildId : sectionOrder) { + sectionEnum.add_symbol(assetBuildId); + } + + _cHeader.write_raw_text(sectionEnum.to_string()); +} + +void AssetEnums::_write_deferred_asset_section_enums(const std::string §ionId, JsonFile *mainJson, const std::string &deferInfoPtr) { + std::string sectionEnumName = StringHelper::upper_snake_case_to_pascal_case(sectionId) + "Enum"; + WriteableCEnum sectionEnum(sectionEnumName); + + std::string fromSectionId = mainJson->get_string(deferInfoPtr + "/from-section"); + std::string idPostfix = mainJson->get_string(deferInfoPtr + "/id-postfix"); + + JsonFile *fromSectionJson = AssetsHelper::get_asset_section_json(_settings, fromSectionId); + + std::vector sectionOrder; + fromSectionJson->get_array("/files/order", sectionOrder); + + for(std::string &assetBuildId : sectionOrder) { + // TODO: This only works for LevelNames. + // Will need to be modified later since Object Animations aren't one-to-one with Object Models. + sectionEnum.add_symbol(assetBuildId + idPostfix); + } + + _cHeader.write_raw_text(sectionEnum.to_string()); +} diff --git a/tools/dkr_assets_tool_src/prebuild/makeIncludes/assetEnums.h b/tools/dkr_assets_tool_src/prebuild/makeIncludes/assetEnums.h new file mode 100644 index 00000000..d0165a4a --- /dev/null +++ b/tools/dkr_assets_tool_src/prebuild/makeIncludes/assetEnums.h @@ -0,0 +1,26 @@ +#pragma once + +#include +#include + +#include "misc/settings.hpp" +#include "helpers/fileHelper.h" +#include "helpers/jsonHelper.h" +#include "helpers/c/cHeader.h" + +class AssetEnums { +public: + AssetEnums(DkrAssetsSettings &settings); + ~AssetEnums(); +private: + DkrAssetsSettings &_settings; + WritableCHeader _cHeader; + fs::path _outFilepath; + + void _write_asset_section_enums(); + void _write_main_asset_enum(std::vector &mainOrder); + void _write_asset_section_enums(const std::string §ionId, JsonFile *sectionJson); + + void _write_deferred_asset_section_enums(const std::string §ionId, JsonFile *mainJson, + const std::string &deferInfoPtr); +}; \ No newline at end of file diff --git a/tools/dkr_assets_tool_src/prebuild/makeIncludes/assetsAsm.cpp b/tools/dkr_assets_tool_src/prebuild/makeIncludes/assetsAsm.cpp new file mode 100644 index 00000000..533759c9 --- /dev/null +++ b/tools/dkr_assets_tool_src/prebuild/makeIncludes/assetsAsm.cpp @@ -0,0 +1,318 @@ +#include "assetsAsm.h" + +#include +#include +#include + +#include "helpers/assetsHelper.h" +#include "helpers/debugHelper.h" +#include "helpers/stringHelper.h" + +#include "helpers/c/cEnumsHelper.h" + +const std::string ASSETS_START_LABEL = "ASSETS_START"; +const std::string ASSETS_END_LABEL = "ASSETS_END"; +const std::string ASSETS_SIZE_LABEL = ASSETS_END_LABEL + " - " + ASSETS_START_LABEL; + +const std::string sectionsPtr = "/assets/sections"; + +AssetsAsm::AssetsAsm(DkrAssetsSettings &settings) : _settings(settings) { + _preload_c_context(); + + _outFilepath = _settings.pathToAsm / "assets/assets.s"; + + _outPrefix = _settings.pathToBuild / _settings.dkrVersion / "assets/"; + + _write(); +} + +AssetsAsm::~AssetsAsm() { + +} + +void AssetsAsm::_write() { + _asm.write_comment("This file is automatically generated. Any changes you make to this file will get overwritten."); + + // Includes + _asm.write_newline(); + _asm.write_include("macros.inc"); + _asm.write_newline(); + + _write_asset_sections(); + + _asm.save(_outFilepath); +} + +void AssetsAsm::_write_asset_sections() { + JsonFile *mainJson = AssetsHelper::get_main_json(_settings); + + std::vector mainOrder; + mainJson->get_array("/assets/order", mainOrder); + + _write_main_table(mainOrder); + + _asm.write_header_comment("Asset Sections Table"); + _asm.write_global_label(ASSETS_START_LABEL, true); + _asm.write_newline(); + + for(std::string §ionId : mainOrder) { + _asm.write_header_comment(sectionId.c_str()); + _asm.write_global_label(sectionId, true); + + _write_asset_section(mainJson, sectionId); + + _asm.write_global_label(sectionId + "_END"); + _asm.write_newline(); + } + + _asm.write_global_label(ASSETS_END_LABEL, true); +} + +void AssetsAsm::_write_asset_section(JsonFile *mainJson, std::string §ionId) { + std::string sectionPtr = sectionsPtr + "/" + sectionId; + + bool isDeferred = mainJson->get_bool(sectionPtr + "/deferred"); + std::string type = mainJson->get_string(sectionPtr + "/type"); + + DebugHelper::assert(!type.empty(), "(AssetsAsm::_write_asset_sections) [", sectionPtr, + "] does not have a type in the main json file!"); + + if(isDeferred) { + _write_deferred_asset(mainJson, sectionPtr); + return; + } + + if(type == "Empty") { + // TODO + return; + } + + // Tables are handeled differently. + if(type == "Table") { + std::string forSectionId = mainJson->get_string(sectionPtr + "/for"); + DebugHelper::assert(!forSectionId.empty(), "(AssetsAsm::_write_asset_sections) [", sectionPtr, + "] table does not have a \"for\" property!"); + std::string forSectionPtr = sectionsPtr + "/" + forSectionId; + bool isForDeferred = mainJson->get_bool(forSectionPtr + "/deferred"); + if(isForDeferred) { + _write_deferred_asset_table(mainJson, forSectionPtr, forSectionId); + } else { + _write_asset_table(forSectionId); + } + std::string forType = mainJson->get_string(forSectionPtr + "/type"); + + if(forType == "TTGhost") { + _asm.write_two_words("0xFFFF0000", forSectionId + "_END - " + forSectionId); + _asm.write_two_words("0xFFFF0000", "0xFFFFFFFF"); + } else { + if(forType == "Miscellaneous") { + _asm.write_word("(" + forSectionId + "_END - " + forSectionId + ") / 4"); + } else { + _asm.write_word(forSectionId + "_END - " + forSectionId); + } + _asm.write_word("0xFFFFFFFF"); + } + return; + } + + // Not deferred, so write them out normally. + + std::string filename = mainJson->get_string(sectionPtr + "/filename"); + + DebugHelper::assert(!filename.empty(), "(AssetsAsm::_write_asset_sections) [", sectionPtr, + "] does not have a filename set in the main json file!"); + + JsonFile *assetSectionJson = AssetsHelper::get_asset_section_json(_settings, sectionId); + + DebugHelper::assert(assetSectionJson != nullptr, + "(AssetsAsm::_write_asset) [", sectionPtr, "] Could not get section json!"); + + _write_asset(assetSectionJson); +} + +void AssetsAsm::_write_main_table(std::vector &mainOrder) { + _asm.write_header_comment("Asset Sections Table"); + + std::string numEntries = std::to_string(mainOrder.size()); + _asm.write_word_with_comment(numEntries, "Number of entries in the table"); + + for(std::string §ionId : mainOrder) { + std::string entry = sectionId + " - " + ASSETS_START_LABEL; + _asm.write_word(entry); + } + + _asm.write_word(ASSETS_SIZE_LABEL); + + _asm.write_newline(); +} + +void AssetsAsm::_write_deferred_asset(JsonFile *mainJson, const std::string §ionPtr) { + std::string deferInfoPtr = sectionPtr + "/defer-info"; + + std::string fromSectionId = mainJson->get_string(deferInfoPtr + "/from-section"); + std::string idPostfix = mainJson->get_string(deferInfoPtr + "/id-postfix"); + fs::path outputLocalPath = mainJson->get_path(deferInfoPtr + "/output-path"); + + JsonFile *fromSectionJson = AssetsHelper::get_asset_section_json(_settings, fromSectionId); + + std::vector sectionOrder; + fromSectionJson->get_array("/files/order", sectionOrder); + + fs::path fromSectionFolder = fromSectionJson->get_path("/folder"); + + for(std::string &assetBuildId : sectionOrder) { + std::string fileSectionPtr = "/files/sections/"+assetBuildId; + fs::path filename = fromSectionJson->get_string(fileSectionPtr+"/filename"); + filename.replace_extension(".bin"); + + // TODO: This only works for LevelNames. + // Will need to be modified later since Object Animations aren't one-to-one with Object Models. + _asm.write_global_label(assetBuildId + idPostfix); + _asm.write_binary_include(_outPrefix / fromSectionFolder / outputLocalPath / filename); + } +} + +void AssetsAsm::_write_asset(JsonFile *assetSectionJson) { + fs::path folder = assetSectionJson->get_path("/folder"); + + if(!assetSectionJson->has("/files")) { + // Single file asset. + if(assetSectionJson->has("/filename")) { + std::string filename = assetSectionJson->get_string("/filename"); + fs::path localFilepath = folder / filename; + localFilepath.replace_extension(".bin"); + _asm.write_binary_include(_outPrefix / localFilepath); + } + return; + } + + std::vector sectionOrder; + assetSectionJson->get_array("/files/order", sectionOrder); + + for(std::string &assetBuildId : sectionOrder) { + std::string fileSectionPtr = "/files/sections/"+assetBuildId; + std::string filename = assetSectionJson->get_string(fileSectionPtr+"/filename"); + DebugHelper::assert(!filename.empty(), "(AssetsAsm::_write_asset) [", + fileSectionPtr,"] does not define a filename!"); + fs::path localFolder = assetSectionJson->get_string(fileSectionPtr+"/folder"); + fs::path localFilepath = folder; + if(!localFolder.empty()) { + localFilepath /= localFolder; + } + localFilepath /= filename; + + localFilepath.replace_extension(".bin"); + + _asm.write_global_label(assetBuildId); + _asm.write_binary_include(_outPrefix / localFilepath); + } +} + +void AssetsAsm::_write_asset_table(const std::string &assetSectionId) { + JsonFile *targetSectionJson = AssetsHelper::get_asset_section_json(_settings, assetSectionId); + + if(targetSectionJson == nullptr) { + return; + } + + if(!targetSectionJson->has("/files")) { + return; + } + + std::string targetType = targetSectionJson->get_string("/type"); + + if(targetType == "MenuText") { + // Write the number of entries in each language. + JsonFile *menuTextSection = AssetsHelper::get_asset_section_json(_settings, "ASSET_MENU_TEXT"); + size_t numberOfTextEntries = menuTextSection->length_of_array("/menu-text-build-ids"); + _asm.write_word(std::to_string(numberOfTextEntries)); + } + + bool first = true; + + std::vector sectionOrder; + targetSectionJson->get_array("/files/order", sectionOrder); + for(std::string &assetBuildId : sectionOrder) { + + if(first && targetType == "Audio") { + _asm.write_comment("For whatever reason, the first table entry in the audio table is not set."); + first = false; + continue; + } + + std::string tableEntry = assetBuildId + " - " + assetSectionId; + if(targetType == "Miscellaneous") { + tableEntry = "(" + tableEntry + ") / 4"; + } else if (targetType == "GameText") { + JsonFile *gameTextEntry = AssetsHelper::get_asset_json(_settings, assetSectionId, assetBuildId); + bool isDialog = gameTextEntry->get_string("/text-type") == "Dialog"; + if(isDialog) { + // Upper-most bit of the entry signifies that it is a dialog instead of a textbox. + tableEntry = "(" + tableEntry + ") | 0x80000000"; + } + } + + if(targetType == "TTGhost") { + JsonFile *ghostJson = AssetsHelper::get_asset_json(_settings, assetSectionId, assetBuildId); + std::string ghostInfo = _get_ghost_level_and_vehicle(ghostJson); + _asm.write_two_words(ghostInfo, tableEntry); + continue; + } + + _asm.write_word(tableEntry); + } +} + +std::string AssetsAsm::_get_ghost_level_and_vehicle(JsonFile *ghostJson) { + std::string levelId = ghostJson->get_string("/header/level"); + std::string vehicleId = ghostJson->get_string("/header/vehicle"); + + uint32_t levelIndex = (uint32_t)AssetsHelper::get_asset_index(_settings, "ASSET_LEVEL_HEADERS", levelId); + uint32_t vehicleIndex = (uint32_t)_c_context.get_int_value_of_symbol(vehicleId); + + // First byte is the level index, second is the vehicle index. Bytes 3 & 4 are always zero. + uint32_t word = ((levelIndex << 24) | (vehicleIndex << 16)) & 0xFFFF0000; + + std::stringstream ss; + + // Set formatting + ss << "0x" << std::hex << std::uppercase << std::setfill('0') << std::setw(8); + + ss << word; + + return ss.str(); +} + + +void AssetsAsm::_write_deferred_asset_table(JsonFile *mainJson, const std::string §ionPtr, const std::string &assetSectionId) { + std::string deferInfoPtr = sectionPtr + "/defer-info"; + + std::string fromSectionId = mainJson->get_string(deferInfoPtr + "/from-section"); + std::string idPostfix = mainJson->get_string(deferInfoPtr + "/id-postfix"); + //fs::path outputLocalPath = mainJson->get_path(deferInfoPtr + "/output-path"); + + JsonFile *fromSectionJson = AssetsHelper::get_asset_section_json(_settings, fromSectionId); + + std::vector sectionOrder; + fromSectionJson->get_array("/files/order", sectionOrder); + for(std::string &assetBuildId : sectionOrder) { + // TODO: This only works for LevelNames. + // Will need to be modified later since Object Animations aren't one-to-one with Object Models. + _asm.write_word(assetBuildId + idPostfix + " - " + assetSectionId); + } +} + +void AssetsAsm::_preload_c_context() { + fs::path includeFolder = _settings.pathToRepo / "include/"; + + // No structs are needed. + + // Only need enums.h + fs::path enumPaths[] = { + includeFolder / "enums.h" + }; + + for(fs::path enumPath : enumPaths) { + CEnumsHelper::load_enums_from_file(&_c_context, enumPath); + } +} diff --git a/tools/dkr_assets_tool_src/prebuild/makeIncludes/assetsAsm.h b/tools/dkr_assets_tool_src/prebuild/makeIncludes/assetsAsm.h new file mode 100644 index 00000000..10c0f619 --- /dev/null +++ b/tools/dkr_assets_tool_src/prebuild/makeIncludes/assetsAsm.h @@ -0,0 +1,36 @@ +#pragma once + +#include +#include "misc/settings.hpp" + +#include "helpers/fileHelper.h" +#include "helpers/asmHeader.h" +#include "helpers/jsonHelper.h" +#include "helpers/c/cContext.h" + +class AssetsAsm { +public: + AssetsAsm(DkrAssetsSettings &settings); + ~AssetsAsm(); +private: + CContext _c_context; + + DkrAssetsSettings &_settings; + fs::path _outFilepath; + fs::path _outPrefix; + WritableAsmInclude _asm; + + void _write(); + void _write_asset_sections(); + void _write_asset_section(JsonFile *mainJson, std::string §ionId); + + void _write_main_table(std::vector &mainOrder); + + void _write_deferred_asset(JsonFile *mainJson, const std::string §ionPtr); + void _write_asset(JsonFile *assetSectionJson); + void _write_asset_table(const std::string &assetSectionId); + std::string _get_ghost_level_and_vehicle(JsonFile *ghostJson); + void _write_deferred_asset_table(JsonFile *mainJson, const std::string §ionPtr, const std::string &assetSectionId); + + void _preload_c_context(); +}; \ No newline at end of file diff --git a/tools/dkr_assets_tool_src/prebuild/prebuild.cpp b/tools/dkr_assets_tool_src/prebuild/prebuild.cpp new file mode 100644 index 00000000..6f03b574 --- /dev/null +++ b/tools/dkr_assets_tool_src/prebuild/prebuild.cpp @@ -0,0 +1,382 @@ +#include "prebuild.h" + +#include "libs/ThreadPool.h" + +#include "helpers/debugHelper.h" +#include "helpers/regexHelper.h" +#include "helpers/dataHelper.h" +#include "helpers/stringHelper.h" + +#include "prebuild/makeIncludes/assetsAsm.h" +#include "prebuild/makeIncludes/assetEnums.h" +#include "prebuild/compileAssets/compile.h" + +const std::string SECTION_TEXT = "text"; +const std::string SECTION_DATA = "data"; +const std::string SECTION_RODATA = "rodata"; +const std::string SECTION_BSS = "bss"; + +PreBuild::PreBuild(DkrAssetsSettings &settings) : _settings(settings) { + _buildFolder = _settings.pathToBuild / _settings.dkrVersion; + + // Gets rid of the starting "./" from the path. + _buildFolder = fs::relative(_buildFolder); + + _buildAsm = _buildFolder / "asm"; + _buildSrc = _buildFolder / "src"; + _buildLibAsm = _buildFolder / "lib/asm"; + _buildLibSrc = _buildFolder / "lib/src"; + + CompileAssets compileAssets(_settings); + + _settings.pathToAssets /= _settings.dkrVersion; + + AssetsAsm assetsAsm(_settings); // Generate asm/assets/assets.s + AssetEnums assetEnums(_settings); // Generate include/asset_enums.h + + _generate_ld(); + _generate_ucode_files(); +} + +PreBuild::~PreBuild() { +} + +void PreBuild::_append_files(const std::string inPath, const std::string extension, const std::string outPath) { + std::vector files = FileHelper::get_files_from_directory_with_extension(fs::path(inPath), extension); + for(auto &p : files) { + DebugHelper::info(p); + } +} + +const std::string _RAM_POS_REGEX = R"([\/][*]+[ \t]*RAM_POS:[ \t]*((?:0x)[0-9a-fA-F]+|(?:[Aa][Uu][Tt][Oo]))[ \t]*(?:if[ \t]*([^*]*))?[*][\/])"; + +void PreBuild::_check_file_for_ram_pos(fs::path &filepath) { + // Only load the first 256 bytes of the file for speed reasons. + + std::string file = FileHelper::read_text_file(filepath, 256); + RegexMatch *match = RegexHelper::get_first_match(file, _RAM_POS_REGEX); + if(match == nullptr) { + return; + } + + std::string ramPos = match->get_group(1).get_text(); + std::string condition = match->get_group(2).get_text(); + + StringHelper::make_lowercase(ramPos); + + if(ramPos == "auto") { + ramPos = "0x800FFFF0"; + } + + if(!StringHelper::starts_with(ramPos, "0x")) { + ramPos.insert(0, "0x"); + } + + uint32_t address = static_cast(std::stoul(ramPos, nullptr, 0)); + + fs::path outFilepath = filepath.lexically_relative(_settings.pathToRepo); + outFilepath.replace_extension(".o"); + + outFilepath = _buildFolder / outFilepath; + + _codeFilesMutex.lock(); + while(_codeFiles.find(address) != _codeFiles.end()) { + address++; // Make sure each address is unique. + } + _codeFiles[address] = { + outFilepath, + condition + }; + _codeFilesMutex.unlock(); +} + +void PreBuild::_get_code_files() { + std::vector allFiles; + + FileHelper::append_files_from_directory_with_extension(_settings.pathToAsm, ".s", allFiles); + FileHelper::append_files_from_directory_with_extension(_settings.pathToSrc, ".c", allFiles); + FileHelper::append_files_from_directory_with_extension(_settings.pathToLibAsm, ".s", allFiles); + FileHelper::append_files_from_directory_with_extension(_settings.pathToLibSrc, ".c", allFiles); + + { + ThreadPool pool(_settings.threadCount); + for(fs::path &filepath : allFiles) { + pool.enqueue([this, &filepath = filepath] { + _check_file_for_ram_pos(filepath); + }); + } + } +} + +void PreBuild::_populate_filepaths() { + _lateDataFiles = { + _buildLibSrc / "al/alCopy.o", + _buildLibSrc / "libc/xprintf.o", + _buildLibSrc / "os/osTimer.o", + _buildLibSrc / "os/piacs.o", + }; + _bssLibOrderFiles = { + _buildLibSrc / "os/osViMgr.o", + _buildLibSrc / "os/osSetEventMesg.o", + _buildLibSrc / "os/controller.o", + _buildLibSrc / "os/siacs.o", + }; +} + +void PreBuild::_write_files_to_section(WritableLD &ld, const std::string §ionName) { + bool isDataSection = (sectionName == "data") || (sectionName == "rodata"); + bool isBssSection = (sectionName == "bss"); + + for (auto &file : _codeFiles) { + std::string &path = file.second.path; + + if(isDataSection && DataHelper::vector_has(_lateDataFiles, path)) { + continue; + } else if(isBssSection && DataHelper::vector_has(_bssLibOrderFiles, path)) { + continue; + } + + std::string &condition = file.second.condition; + if(!condition.empty()) { + ld.write_raw_line("#if " + condition); + } + ld.write_raw_line(path + "(." + sectionName + ");"); + if(!condition.empty()) { + ld.write_raw_line("#endif"); + } + } + if(isDataSection) { + for(fs::path &path : _lateDataFiles) { + ld.write_raw_line(std::string(path) + "(." + sectionName + ");"); + } + } else if(isBssSection) { + for(fs::path &path : _bssLibOrderFiles) { + ld.write_raw_line(std::string(path) + "(." + sectionName + ");"); + } + } +} + +void PreBuild::_write_ld_boot_section(WritableLD &ld) { + ld.write_section_header("boot", "0", "romPos", LD_SUBALIGN::NONE); + ld.write_open_brace(); // Open .boot + + // TODO: Refactor to remove hardcoding. + ld.write_raw_line(_buildFolder / "asm/boot/rom_header.o(.text);"); + ld.write_raw_line(_buildFolder / "asm/boot/rom_boot.o(.text);"); + + ld.write_close_brace(); // Close .boot + ld.write_add_to_rom_pos("SIZEOF(.boot)"); + ld.write_newline(); +} + +void PreBuild::_write_main_section(WritableLD &ld) { + ld.write_section_header("main", "__FUNC_RAM_START", "romPos", LD_SUBALIGN::ALIGN16); + ld.write_open_brace(); // Open .main + + _write_files_to_section(ld, SECTION_TEXT); + + ld.write_close_brace(); // Close .main + ld.write_add_to_rom_pos("SIZEOF(.main)"); + ld.write_newline(); +} + +void PreBuild::_write_ucode_text_section(WritableLD &ld) { + ld.write_section_header("ucodeText", ".", "romPos", LD_SUBALIGN::NONE); + ld.write_open_brace(); // Open .ucodeText + + // TODO: Refactor to remove hardcoding. + ld.write_raw_line(_buildFolder / "asm/assets/ucode_text.o(.text);"); + + ld.write_close_brace(); // Close .ucodeText + ld.write_add_to_rom_pos("SIZEOF(.ucodeText)"); + ld.write_newline(); +} + +void PreBuild::_write_data_section(WritableLD &ld) { + ld.write_section_header("data", ".", "romPos", LD_SUBALIGN::ALIGN16); + ld.write_open_brace(); // Open .data + + _write_files_to_section(ld, SECTION_DATA); + + ld.write_close_brace(); // Close .data + ld.write_add_to_rom_pos("SIZEOF(.data)"); + ld.write_newline(); +} + +void PreBuild::_write_rodata_section(WritableLD &ld) { + ld.write_section_header("rodata", ".", "romPos", LD_SUBALIGN::ALIGN16); + ld.write_open_brace(); // Open .rodata + + _write_files_to_section(ld, SECTION_RODATA); + + ld.write_close_brace(); // Close .rodata + ld.write_add_to_rom_pos("SIZEOF(.rodata)"); + ld.write_newline(); +} + +void PreBuild::_write_ucode_data_section(WritableLD &ld) { + ld.write_section_header("ucodeData", ".", "romPos", LD_SUBALIGN::NONE); + ld.write_open_brace(); // Open .ucodeData + + // TODO: Refactor to remove hardcoding. + ld.write_raw_line(_buildFolder / "asm/assets/ucode_data.o(.text);"); + + ld.write_close_brace(); // Close .ucodeData + ld.write_add_to_rom_pos("SIZEOF(.ucodeData)"); + ld.write_newline(); +} + +void PreBuild::_write_bss_section(WritableLD &ld) { + // TODO: add this to ld file + ld.write_raw_line(".bss.noload . (NOLOAD): SUBALIGN(4)"); + ld.write_open_brace(); // Open .bss + + _write_files_to_section(ld, SECTION_BSS); + + ld.write_close_brace(); // Close .bss + ld.write_newline(); +} + +void PreBuild::_write_assets_section(WritableLD &ld) { + ld.write_section_header("assets", "0", "romPos", LD_SUBALIGN::NONE); + ld.write_open_brace(); // Open .assets + + // TODO: Refactor to remove hardcoding. + ld.write_raw_line(_buildFolder / "asm/assets/assets.o(.text);"); + + + ld.write_close_brace(); // Close .assets + ld.write_add_to_rom_pos("SIZEOF(.assets)"); + ld.write_newline(); +} + +void PreBuild::_write_discard_section(WritableLD &ld) { + ld.write_comment("Discard everything not specifically mentioned above."); + + // TODO: add this to ld file + ld.write_raw_line("/DISCARD/ :"); + ld.write_open_brace(); // Open discard + ld.write_raw_line("*(*);"); + ld.write_close_brace(); // Close discard + ld.write_newline(); +} + +void PreBuild::_generate_ld() { + _get_code_files(); + _populate_filepaths(); + + fs::path outputPath = _settings.pathToRepo / "dkr.ld"; + WritableLD ld(_settings); + + ld.write_comment("This file is automatically generated. Any changes you make to this file will get overwritten."); + ld.write_newline(); + + ld.write_include("config.h"); + ld.write_newline(); + + ld.write_arch("mips"); + ld.write_newline(); + + ld.write_raw_line("SECTIONS"); + ld.write_open_brace(); // Open SECTIONS + + ld.write_rom_pos_at("0"); + + // .boot section + _write_ld_boot_section(ld); + + ld.write_assignment("__FUNC_RAM_START", "0x80000400"); + ld.write_assignment("__FUNC_ROM_START", "0x00001000"); + ld.write_assignment("__RAM_TO_ROM", "__FUNC_RAM_START - __FUNC_ROM_START"); + ld.write_newline(); + + // .main section + _write_main_section(ld); + + // .ucodeText section + _write_ucode_text_section(ld); + + // .data section + _write_data_section(ld); + + // .rodata section + _write_rodata_section(ld); + + // .ucodeData section + _write_ucode_data_section(ld); + + ld.write_assignment("__BSS_SECTION_SIZE", "SIZEOF(.bss.noload) - 16"); + ld.write_newline(); + + // .bss.noload section + _write_bss_section(ld); + + ld.write_assignment("__ASSETS_LUT_START", "romPos"); + // TODO: Turn `0xD0` into sizeof main asset table. + ld.write_assignment("__ASSETS_LUT_END", "__ASSETS_LUT_START + 0xD0"); + ld.write_newline(); + + // .assets section + _write_assets_section(ld); + + ld.write_assignment("__ROM_END", "romPos"); + ld.write_newline(); + + _write_discard_section(ld); + + ld.write_close_brace(); // Close SECTIONS + + ld.save(outputPath); +} + +void PreBuild::_write_ucode_file_glabel(WritableAsmInclude &asmInc, std::string label, std::string path) { + asmInc.write_global_label(label); + asmInc.write_binary_include(_buildFolder / path); +} + +void PreBuild::_generate_ucode_text_file() { + fs::path ucodeTextPath = _settings.pathToAsm / "assets/ucode_text.s"; + WritableAsmInclude text; + + text.write_comment("This file is automatically generated. Any changes you make to this file will get overwritten."); + text.write_newline(); + + text.write_include("macros.inc"); + text.write_newline(); + + // TODO: Refactor this! + _write_ucode_file_glabel(text, "aspMainTextStart", "ucode/ucode_audio.bin"); + _write_ucode_file_glabel(text, "rspF3DDKRBootStart", "ucode/ucode_boot.bin"); + _write_ucode_file_glabel(text, "rspF3DDKRDramStart", "ucode/ucode_f3ddkr_dram.bin"); + _write_ucode_file_glabel(text, "rspF3DDKRFifoStart", "ucode/ucode_f3ddkr_fifo.bin"); + _write_ucode_file_glabel(text, "rspF3DDKRXbusStart", "ucode/ucode_f3ddkr_xbus.bin"); + _write_ucode_file_glabel(text, "rspUnknown2Start", "ucode/ucode_unknown_2.bin"); + + text.save(ucodeTextPath); +} + +void PreBuild::_generate_ucode_data_file() { + fs::path ucodeDataPath = _settings.pathToAsm / "assets/ucode_data.s"; + WritableAsmInclude data; + + data.write_comment("This file is automatically generated. Any changes you make to this file will get overwritten."); + data.write_newline(); + + data.write_include("macros.inc"); + data.write_newline(); + + // TODO: Refactor this! + _write_ucode_file_glabel(data, "aspMainDataStart", "ucode/data_audio.bin"); + _write_ucode_file_glabel(data, "rspF3DDKRDataDramStart", "ucode/data_f3ddkr_dram.bin"); + _write_ucode_file_glabel(data, "rspF3DDKRDataFifoStart", "ucode/data_f3ddkr_fifo.bin"); + _write_ucode_file_glabel(data, "rspF3DDKRDataXbusStart", "ucode/data_f3ddkr_xbus.bin"); + _write_ucode_file_glabel(data, "rspUnknown2DataStart", "ucode/data_unknown_2.bin"); + + data.save(ucodeDataPath); +} + +void PreBuild::_generate_ucode_files() { + _generate_ucode_text_file(); + _generate_ucode_data_file(); +} + diff --git a/tools/dkr_assets_tool_src/prebuild/prebuild.h b/tools/dkr_assets_tool_src/prebuild/prebuild.h new file mode 100644 index 00000000..6dea5f9e --- /dev/null +++ b/tools/dkr_assets_tool_src/prebuild/prebuild.h @@ -0,0 +1,54 @@ +#pragma once + +#include +#include +#include + +#include "misc/settings.hpp" +#include "prebuild/linker/ld.h" + +#include "helpers/fileHelper.h" +#include "helpers/asmHeader.h" + +struct LDCodeFile { + std::string path; + std::string condition; +}; + +class PreBuild { +public: + PreBuild(DkrAssetsSettings &settings); + ~PreBuild(); +private: + DkrAssetsSettings &_settings; + + std::vector _lateDataFiles; + std::vector _bssLibOrderFiles; + std::map _codeFiles; // Sorted by ram address + std::mutex _codeFilesMutex; + + fs::path _buildFolder, _buildAsm, _buildSrc, _buildLibAsm, _buildLibSrc; + + void _write_files_to_section(WritableLD &ld, const std::string §ionName); + + void _write_ld_boot_section(WritableLD &ld); + void _write_main_section(WritableLD &ld); + void _write_ucode_text_section(WritableLD &ld); + void _write_data_section(WritableLD &ld); + void _write_rodata_section(WritableLD &ld); + void _write_ucode_data_section(WritableLD &ld); + void _write_bss_section(WritableLD &ld); + void _write_assets_section(WritableLD &ld); + void _write_discard_section(WritableLD &ld); + + void _append_files(const std::string inPath, const std::string extension, const std::string outPath); + void _check_file_for_ram_pos(fs::path &filepath); + void _get_code_files(); + void _populate_filepaths(); + + void _generate_ld(); + void _write_ucode_file_glabel(WritableAsmInclude &asmInc, std::string label, std::string path); + void _generate_ucode_text_file(); + void _generate_ucode_data_file(); + void _generate_ucode_files(); +}; diff --git a/tools/dkr_assets_tool_src/test/test.cpp b/tools/dkr_assets_tool_src/test/test.cpp new file mode 100644 index 00000000..9dece2de --- /dev/null +++ b/tools/dkr_assets_tool_src/test/test.cpp @@ -0,0 +1,503 @@ +#include "test.h" + +#include +#include + +#include "helpers/regexHelper.h" +#include "helpers/debugHelper.h" +#include "helpers/stringHelper.h" +#include "helpers/fileHelper.h" + +#include "helpers/c/cStructHelper.h" +#include "helpers/c/cContext.h" + +void test_string_helper() { + DebugHelper::DebugTimer timer; + + std::string testString = "Hello World!"; + + StringHelper::make_uppercase(testString); + DebugHelper::assert(testString == "HELLO WORLD!", "(String Helper) Uppercase Test: Failed"); + StringHelper::make_lowercase(testString); + DebugHelper::assert(testString == "hello world!", "(String Helper) Lowercase Test: Failed"); + + const std::string trimTestString = " Foo "; + + testString = trimTestString; + StringHelper::rtrim(testString); + DebugHelper::assert(testString == " Foo", "(String Helper) Right Trim Test: Failed"); + testString = trimTestString; + StringHelper::ltrim(testString); + DebugHelper::assert(testString == "Foo ", "(String Helper) Left Trim Test: Failed"); + testString = trimTestString; + StringHelper::trim(testString); + DebugHelper::assert(testString == "Foo", "(String Helper) Trim Test: Failed"); + + const std::string splitStringInput = " **x[2],*y , z[3] "; + + testString = splitStringInput; + std::vector testStringSplitted; + + StringHelper::split(testString, ',', testStringSplitted); + + DebugHelper::assert(testString == splitStringInput, "(String Helper) Split Test: input was modified."); + DebugHelper::assert(testStringSplitted.size() == 3, "(String Helper) Split Test: size incorrect"); + DebugHelper::assert(testStringSplitted[0] == " **x[2]", "(String Helper) Split Test: Failed (index 0)"); + DebugHelper::assert(testStringSplitted[1] == "*y ", "(String Helper) Split Test: Failed (index 1)"); + DebugHelper::assert(testStringSplitted[2] == " z[3] ", "(String Helper) Split Test: Failed (index 2)"); + + testStringSplitted.clear(); + + StringHelper::split_and_trim(testString, ',', testStringSplitted); + + DebugHelper::assert(testString == splitStringInput, "(String Helper) Split & Trim Test: input was modified."); + DebugHelper::assert(testStringSplitted.size() == 3, "(String Helper) Split & Trim Test: size incorrect"); + DebugHelper::assert(testStringSplitted[0] == "**x[2]", "(String Helper) Splitt & Trim Test: Failed (index 0)"); + DebugHelper::assert(testStringSplitted[1] == "*y", "(String Helper) Splitt & Trim Test: Failed (index 1)"); + DebugHelper::assert(testStringSplitted[2] == "z[3]", "(String Helper) Splitt & Trim Test: Failed (index 2)"); + + DebugHelper::info(GREEN_TEXT, "String Helper passed all tests!", RESET_TEXT, " Took ", timer.elapsed()); +} + +void test_regex_engine_match(int testMajor, int testMinor, RegexMatchGroup &group, std::string expectedText, int expectedOffset) { + std::string groupText = group.get_text(); + int groupOffset = group.get_offset(); + DebugHelper::assert(groupText == expectedText, + "(Regex Helper) ", testMajor, ",", testMinor, " Test Failed!\nText did not match!\n", + "text = \"", groupText, "\"\n", + "expected = \"", expectedText, "\""); + DebugHelper::assert(groupOffset == expectedOffset, + "(Regex Helper) ", testMajor, ",", testMinor, " Test Failed!\nOffset did not match!\n", + "offset = ", groupOffset, "\n", + "expected = ", expectedOffset); +} + +// Make sure RegexHelper::get_matches works. +void test_regex_engine_part1() { + std::string testString = R"( +u8 pad[5] ; +s32 radius; +// Activation radius. +float angleY; +u8 pad2 [5][4][2] ; +u8 *********superPointer; +)"; + + std::string testRegex = R"(([A-Za-z_][A-Za-z0-9_]*)\s*([*]+)?\s*([A-Za-z_][A-Za-z0-9_]*)\s*(\[.*\])?\s*;)"; + + std::vector matches; + RegexHelper::get_matches(testString, testRegex, matches); + + + DebugHelper::assert(matches.size() == 5, + "(Regex Helper) Number of matches is not 5; got ", matches.size(), " matches instead!"); + + test_regex_engine_match(0, 0, matches[0].get_group(1), "u8", 1); + test_regex_engine_match(0, 1, matches[0].get_group(2), "", -1); + test_regex_engine_match(0, 2, matches[0].get_group(3), "pad", 7); + test_regex_engine_match(0, 3, matches[0].get_group(4), "[5]", 10); + + test_regex_engine_match(1, 0, matches[1].get_group(1), "s32", 4); + test_regex_engine_match(1, 1, matches[1].get_group(2), "", -1); + test_regex_engine_match(1, 2, matches[1].get_group(3), "radius", 11); + test_regex_engine_match(1, 3, matches[1].get_group(4), "", -1); + + test_regex_engine_match(2, 0, matches[2].get_group(1), "float", 23); + test_regex_engine_match(2, 1, matches[2].get_group(2), "", -1); + test_regex_engine_match(2, 2, matches[2].get_group(3), "angleY", 36); + test_regex_engine_match(2, 3, matches[2].get_group(4), "", -1); + + test_regex_engine_match(3, 0, matches[3].get_group(1), "u8", 1); + test_regex_engine_match(3, 1, matches[3].get_group(2), "", -1); + test_regex_engine_match(3, 2, matches[3].get_group(3), "pad2", 4); + test_regex_engine_match(3, 3, matches[3].get_group(4), "[5][4][2]", 11); + + test_regex_engine_match(4, 0, matches[4].get_group(1), "u8", 1); + test_regex_engine_match(4, 1, matches[4].get_group(2), "*********", 4); + test_regex_engine_match(4, 2, matches[4].get_group(3), "superPointer", 13); + test_regex_engine_match(4, 3, matches[4].get_group(4), "", -1); +} + + +// Make sure RegexHelper::get_first_match works. +void test_regex_engine_part2() { + std::string testString = R"(/* The comment below is needed for this file to be picked up by generate_ld */ +/* RAM_POS: 0x80076BA0 */ +)"; + + std::string testRegex = R"([\/][*]+[ \t]*RAM_POS:[ \t]*((?:0x)[0-9a-fA-F]+|(?:[Aa][Uu][Tt][Oo]))[ \t]*(?:if[ \t]*([^*]*))?[*][\/])"; + + RegexMatch *ramPosMatch = RegexHelper::get_first_match(testString, testRegex); + + DebugHelper::assert(ramPosMatch != nullptr, + "(Regex Helper) Could not find ramPos in test string!"); + + test_regex_engine_match(5, 0, ramPosMatch->get_group(1), "0x80076BA0", 91); +} + +// Returns true if a member was found. +bool part3_get_next_member(const std::string &inputStr, int &offset, std::string &outStr) { + const std::string endCharRegex = R"([ \t]+((?:[^;]|[^{])*?([;{])))"; + + //DebugHelper::info("offset = ", offset); + + RegexMatch *match = RegexHelper::get_first_match(inputStr, endCharRegex, offset); + + if(match == nullptr) { + outStr = ""; + return false; + } + + outStr = match->get_group(1).get_text(); + offset += match->get_group(2).get_offset() + 1; + + delete match; + + return true; +} + +void part3_check_member_and_offset(int testMajor, int testMinor, const std::string &memberStr, int nextOffset, + std::string expectedMemberStr, int expectedNextOffset) { + DebugHelper::assert(memberStr == expectedMemberStr, + "(Regex Helper) ", testMajor, ",", testMinor, " Test Failed!\nText did not match!\n", + "text = \"", memberStr, "\"\n", + "expected = \"", expectedMemberStr, "\""); + DebugHelper::assert(nextOffset == expectedNextOffset, + "(Regex Helper) ", testMajor, ",", testMinor, " Test Failed!\nOffset did not match!\n", + "next offset = ", nextOffset, "\n", + "expected = ", expectedNextOffset); +} + +// Test multiple get_first_match +void test_regex_engine_part3() { + std::string testString = R"( + int a0; + int b0; + struct { + int c0; + int d0; + }; + u8 pad2 [5][4][2]; + u8 *********superPointer; + )"; + + int curOffset = 0; + std::string curMember; + + part3_get_next_member(testString, curOffset, curMember); + part3_check_member_and_offset(6, 0, curMember, curOffset, "int a0;", 20); + part3_get_next_member(testString, curOffset, curMember); + part3_check_member_and_offset(6, 1, curMember, curOffset, "int b0;", 40); + part3_get_next_member(testString, curOffset, curMember); + part3_check_member_and_offset(6, 2, curMember, curOffset, "struct {", 61); + curOffset = StringHelper::find_closing_brace(testString, curOffset - 1) + 2; // Skip over the inner struct. +2 for the closing brace and semicolon. + part3_get_next_member(testString, curOffset, curMember); + part3_check_member_and_offset(6, 3, curMember, curOffset, "u8 pad2 [5][4][2];", 157); + +} + +void test_regex_engine(RegexEngine engine) { + if(!RegexHelper::set_engine(engine)) { + DebugHelper::warn("Regex engine ", engine, " is not implemented!"); + return; + } + + std::string regexEngineName = RegexHelper::get_current_engine_name(); + + DebugHelper::info("Testing regex engine: \"", regexEngineName, "\""); + + DebugHelper::DebugTimer timer; + + test_regex_engine_part1(); + test_regex_engine_part2(); + test_regex_engine_part3(); + + DebugHelper::info(GREEN_TEXT, "Regex engine ", regexEngineName, " passed all tests!", RESET_TEXT, " Took ", timer.elapsed()); +} + +void test_regex_helper() { + test_regex_engine(RegexEngine::STL); + test_regex_engine(RegexEngine::PCRE2); +} + +void test_cstruct_helper_engine(RegexEngine engine, DkrAssetsSettings &settings) { + if(!RegexHelper::set_engine(engine)) { + DebugHelper::warn("Regex engine ", engine, " is not implemented!"); + return; + } + + std::string regexEngineName = RegexHelper::get_current_engine_name(); + + DebugHelper::DebugTimer timer; + + CContext ctx; + + std::string input; + input = R"( + struct { + int a0; + int b0; + struct { + int c0; + int d0; + }; + }; + )"; + + CStruct test0(&ctx, input); + + DebugHelper::assert(test0.is_trivial(), "Failed test 0.0 (struct was not trivial)"); + DebugHelper::assert(test0.get_byte_size() == 16, "Failed test 0.1 (struct was incorrect size, was ", test0.get_byte_size(), " when it should be 16)"); + DebugHelper::assert(test0.get_entry(0)->name == "a0", "Failed test 0.2 (Invalid name, was ", test0.get_entry(0)->name, " when it should be a0)"); + DebugHelper::assert(test0.get_entry(1)->name == "b0", "Failed test 0.3 (Invalid name, was ", test0.get_entry(1)->name, " when it should be b0)"); + DebugHelper::assert(test0.get_entry(2)->innerStruct->get_entry(0)->name == "c0", "Failed test 0.4 (Invalid name, was ", + test0.get_entry(2)->innerStruct->get_entry(0)->name, " when it should be c0)"); + DebugHelper::assert(test0.get_entry(2)->innerStruct->get_entry(1)->name == "d0", "Failed test 0.5 (Invalid name, was ", + test0.get_entry(2)->innerStruct->get_entry(1)->name, " when it should be d0)"); + DebugHelper::assert(test0.get_entry(0)->get_offset() == 0, "Failed test 0.6"); + DebugHelper::assert(test0.get_entry(1)->get_offset() == 4, "Failed test 0.7"); + DebugHelper::assert(test0.get_entry(2)->innerStruct->get_entry(0)->get_offset() == 8, "Failed test 0.8"); + + // Clear structs that were created in the previous test. + ctx.clear_structs(); + + input = R"( + // Size: 8 bytes. Shared across every entry. + typedef struct LevelObjectEntryCommon { + u8 objectID; // 9-bit object ID to load (uses size's MSB). + u8 size; // 7-bit total entry length (MSB is used in object_id). + s16 x, y, z; // Position in level + } LevelObjectEntryCommon; + )"; + CStruct entryCommon(&ctx, input); + + input = R"( + typedef struct LevelObjectEntry_Racer { + LevelObjectEntryCommon common; + s16 angleZ; + s16 angleX; + s16 angleY; + s16 playerIndex; + } LevelObjectEntry_Racer; + )"; + + CStruct test1(&ctx, input); + DebugHelper::assert(!test1.is_trivial(), "Failed test 1.0 (struct was trivial)"); + DebugHelper::assert(test1.get_byte_size() == 16, "Failed test 1.0 (struct size incorrect, was ", test1.get_byte_size(), " when it should be 16)"); + + // Clear structs that were created in the previous test. + ctx.clear_structs(); + + input = R"( + // Size: 8 bytes. Shared across every entry. + typedef struct LevelObjectEntryCommon { + u8 objectID; // 9-bit object ID to load (uses size's MSB). + u8 size; // 7-bit total entry length (MSB is used in object_id). + s16 x, y, z; // Position in level + } LevelObjectEntryCommon; + )"; + CStruct entryCommon2(&ctx, input); + + input = R"( + typedef struct LevelObjectEntry_Exit { + LevelObjectEntryCommon common; + u8 destinationMapId; + u8 pad9; + + // Defines the location in overworld the player will spawn at. + // Only used if the exit goes to overworld. + // 0: Future Fun Land exit (also game start spawn) + // 2: Dino Domain exit + // 3: Snowflake Mountain exit + // 4: Sherbet Island exit + // 6: Dragon Forest exit + // 7: Wizpig head exit + s8 overworldSpawnIndex; + + u8 padB[5]; + u8 radius; // Activation radius. + u8 angleY; + u8 pad12[5]; + + // Defines the location in a hub world the player will spawn at when exiting `destinationMapId`. + // Only used if the exit goes to a race. + // 0: Hub exit door + // 1-4: One of the 4 race doors + // 5: Boss door + // 6: Minigame door + // 7: Wizpig head + u8 returnSpawnIndex; + + // -1: Doesn't warp to a boss race + // 0: Warps to a boss 1 race + // 1: Warps to a boss 2 race + s8 bossFlag; + + // Stuff added for testing purposes + char *stringTest; + int multiArrayTest[2][3][4][5]; + float floatTest; + f32 floatTest2; + int a, b, c; + float *a2, * * b2, *** * c2 [ 1 ] [ 43] [ 55] ; + + struct { + int a; + float b; + struct { + int c; + int d; + }; + struct { + int e; + int f; + } innerStructTest; + union { + struct LevelObjectEntry_Exit_SubStruct { + int g; + int h; + } innerStructinUnionInStruct; + u8 i; + s16 k; + } unionInStruct; + } structTest; + struct { + int aa; + long long ab; + }; + struct Foo { + union Bar { + int a; + long b; + }*bar[2]; + }; + } LevelObjectEntry_Exit; + )"; + CStruct test2(&ctx, input); + + DebugHelper::assert(!test2.is_trivial(), "Failed test 2.0 (struct was trivial)"); + // TODO: More tests needed! + + // Clear structs that were created in the previous test. + ctx.clear_structs(); + + DebugHelper::DebugTimer timer2; + + fs::path levelObjectEntriesFilepath = settings.pathToRepo / "include/level_object_entries.h"; + CStructHelper::load_structs_from_file(&ctx, levelObjectEntriesFilepath); + + DebugHelper::info(YELLOW_TEXT, "Took ", timer2.elapsed(), " to parse level_object_entries.h", RESET_TEXT); + + CStruct *levelObjectEntryCommon = ctx.get_struct("LevelObjectEntryCommon"); + CStruct *levelObjectEntryRacer = ctx.get_struct("LevelObjectEntry_Racer"); + CStruct *levelObjectEntryScenery = ctx.get_struct("LevelObjectEntry_Scenery"); + CStruct *levelObjectEntryExit = ctx.get_struct("LevelObjectEntry_Exit"); + CStruct *levelObjectEntryCheckpoint = ctx.get_struct("LevelObjectEntry_Checkpoint"); + + // Make sure the sizes are correct. + DebugHelper::assert(levelObjectEntryCommon->get_byte_size() == 8, "Failed test 3.0 (struct LevelObjectEntryCommon size is not 8)"); + DebugHelper::assert(levelObjectEntryRacer->get_byte_size() == 16, "Failed test 3.1 (struct LevelObjectEntry_Racer size is not 16)"); + DebugHelper::assert(levelObjectEntryScenery->get_byte_size() == 12, "Failed test 3.2 (struct LevelObjectEntry_Scenery size is not 12)"); + DebugHelper::assert(levelObjectEntryExit->get_byte_size() == 0x1A, "Failed test 3.3 (struct LevelObjectEntry_Exit size is not 0x1A)"); + DebugHelper::assert(levelObjectEntryCheckpoint->get_byte_size() == 0x1C, "Failed test 3.4 (struct LevelObjectEntry_Checkpoint size is not 0x1C)"); + // TODO: More tests needed! + + uint8_t entryCommonTestData[] = { + 0x0B, + 0x08, + 0xFA, 0xCE, + 0xDE, 0xAD, + 0xBE, 0xEF + }; + + int16_t entryCommonTestData_x = levelObjectEntryCommon->get_entry(2)->get_integer_from_data(entryCommonTestData); + int16_t entryCommonTestData_y = levelObjectEntryCommon->get_entry(3)->get_integer_from_data(entryCommonTestData); + int16_t entryCommonTestData_z = levelObjectEntryCommon->get_entry(4)->get_integer_from_data(entryCommonTestData); + + DebugHelper::assert(entryCommonTestData_x == (int16_t)0xFACE, "Failed test 3.6 (Should be 0xFACE, but was ", DebugHelper::to_hex(entryCommonTestData_x), ")"); + DebugHelper::assert(entryCommonTestData_y == (int16_t)0xDEAD, "Failed test 3.7 (Should be 0xDEAD, but was ", DebugHelper::to_hex(entryCommonTestData_y), ")"); + DebugHelper::assert(entryCommonTestData_z == (int16_t)0xBEEF, "Failed test 3.8 (Should be 0xBEEF, but was ", DebugHelper::to_hex(entryCommonTestData_z), ")"); + + DebugHelper::info(GREEN_TEXT, "C Struct Helper (using regex engine \"", regexEngineName, "\") passed all tests!", RESET_TEXT, " Took ", timer.elapsed()); +} + +void test_cstruct_helper(DkrAssetsSettings &settings) { + test_cstruct_helper_engine(RegexEngine::STL, settings); + test_cstruct_helper_engine(RegexEngine::PCRE2, settings); +} + +void test_cenum_helper_engine(RegexEngine engine, DkrAssetsSettings &settings) { + if(!RegexHelper::set_engine(engine)) { + DebugHelper::warn("Regex engine ", engine, " is not implemented!"); + return; + } + + std::string regexEngineName = RegexHelper::get_current_engine_name(); + + DebugHelper::DebugTimer timer; + + CContext ctx; + std::string input; + + input = R"( + typedef enum Test { + FOO_BAR, + FOO_BAR_2, + FOO_BAR_4 = 123 + } Test; + )"; + CEnum testEnum(&ctx, input); + + input = R"( + typedef enum Test2 { + AA = -1, + AB = 2, + AC, + AD = 512, + AE = FOO_BAR_4 | AD + } Test2; + )"; + CEnum test0(&ctx, input); + + DebugHelper::assert(ctx.get_int_value_of_symbol("AA") == -1, "Failed test 0.1 (AA has the incorrect value)"); + DebugHelper::assert(ctx.get_int_value_of_symbol("AB") == 2, "Failed test 0.2 (AB has the incorrect value)"); + DebugHelper::assert(ctx.get_int_value_of_symbol("AC") == 3, "Failed test 0.3 (AC has the incorrect value)"); + DebugHelper::assert(ctx.get_int_value_of_symbol("AD") == 512, "Failed test 0.4 (AD has the incorrect value)"); + DebugHelper::assert(ctx.get_int_value_of_symbol("AE") == (512 | 123), "Failed test 0.5 (AE has the incorrect value)"); + + ctx.clear_enums(); + + // Test enums.h + fs::path enumsFilepath = settings.pathToRepo / "include/enums.h"; + CEnumsHelper::load_enums_from_file(&ctx, enumsFilepath); + + // Check a single member from each enum. + DebugHelper::assert(ctx.get_int_value_of_symbol("VEHICLE_PLANE") == 2, "Failed test 1.1 (VEHICLE_PLANE has the incorrect value)"); + DebugHelper::assert(ctx.get_int_value_of_symbol("CAMERA_FINISH_CHALLENGE") == 5, "Failed test 1.2 (CAMERA_FINISH_CHALLENGE has the incorrect value)"); + DebugHelper::assert(ctx.get_int_value_of_symbol("LANGUAGE_GERMAN") == 1, "Failed test 1.3 (LANGUAGE_GERMAN has the incorrect value)"); + DebugHelper::assert(ctx.get_int_value_of_symbol("WORLD_FUTURE_FUN_LAND") == 5, "Failed test 1.4 (WORLD_FUTURE_FUN_LAND has the incorrect value)"); + DebugHelper::assert(ctx.get_int_value_of_symbol("RACETYPE_CHALLENGE_BANANAS") == 65, "Failed test 1.5 (RACETYPE_CHALLENGE_BANANAS has the incorrect value)"); + DebugHelper::assert(ctx.get_int_value_of_symbol("HORZ_ALIGN_CENTER") == 4, "Failed test 1.6 (HORZ_ALIGN_CENTER has the incorrect value)"); + DebugHelper::assert(ctx.get_int_value_of_symbol("VERT_ALIGN_BOTTOM") == 2, "Failed test 1.7 (VERT_ALIGN_BOTTOM has the incorrect value)"); + DebugHelper::assert(ctx.get_int_value_of_symbol("ALIGN_BOTTOM_CENTER") == 6, "Failed test 1.8 (ALIGN_BOTTOM_CENTER has the incorrect value)"); + DebugHelper::assert(ctx.get_int_value_of_symbol("SURFACE_ZIP_PAD") == 3, "Failed test 1.9 (SURFACE_ZIP_PAD has the incorrect value)"); + + DebugHelper::info(GREEN_TEXT, "C Enum Helper (using regex engine \"", regexEngineName, "\") passed all tests!", RESET_TEXT, " Took ", timer.elapsed()); +} + +void test_cenum_helper(DkrAssetsSettings &settings) { + test_cenum_helper_engine(RegexEngine::STL, settings); + test_cenum_helper_engine(RegexEngine::PCRE2, settings); +} + +TestDKRAT::TestDKRAT(DkrAssetsSettings &settings) : _settings(settings) { + DebugHelper::info("Testing helpers!"); + //test_string_helper(); + test_regex_helper(); + test_cstruct_helper(_settings); + test_cenum_helper(_settings); +} + +TestDKRAT::~TestDKRAT() { + +} \ No newline at end of file diff --git a/tools/dkr_assets_tool_src/test/test.h b/tools/dkr_assets_tool_src/test/test.h new file mode 100644 index 00000000..cdbe667d --- /dev/null +++ b/tools/dkr_assets_tool_src/test/test.h @@ -0,0 +1,11 @@ +#pragma once + +#include "misc/settings.hpp" + +class TestDKRAT { + public: + TestDKRAT(DkrAssetsSettings &settings); + ~TestDKRAT(); + private: + DkrAssetsSettings &_settings; +}; \ No newline at end of file

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 literal 0 HcmV?d00001 diff --git a/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/extractTypes/extractAudio.o b/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/extractTypes/extractAudio.o new file mode 100644 index 0000000000000000000000000000000000000000..627f7c827291dd2c4f0a3b58297788cfc64ca60a GIT binary patch literal 30744 zcmb<-^>JfjWMqH=Mg}_u1P><4z#x&0U^{@B4h$v?#$dI)3=CkJpMilv0Lm6-U|5@t8W3=bgHO$Hvi!-ck$@9_H6#cSZd6_&6S~p-KSec#iQHWr!$$u=@^STgGaZE3P*~E zHpIBn0FUM)0@1OKF^Bo(9TX6K?=cwU}C7d|1-bbufr44^!VjlKptZN@g2iGJ3n}IUULj{ z36F{bQ z9tTNFfDQ8K25E&xhe!7o6#+&D29MTnCA=QJd%zs1vOQ3j%uxZQVGqmuC4wH^Ef7v` z0V7mZiAsV;cZf=cN9TKw&N&b*jGtcU{rmsl2Wp;2cZrIGPv?J#j?Pyey`~_~A*TRj zcW}U!c0-*&n$?^Cf~;Pn0`d7fA7}u2;5E&scZB@ag;xbxe&42Q1T)5j&pU zH7XnslUfh(x4s7lDJU*ri3A#?`bCN5pb!BCB?}}dLBY!a(TYFH;1Rn;1>|&48sJ)rGD!kRuSN+UC=3fc5Gfv#U*W|ee=9fxH68(F zYf!1^80#447=IXBlz=jDfJbkMih~C3mh;TUWq7ncJ5Em5>aA>%wgusHL zM#TZ-AOnbl0+1Yp$ihTt9Z2c~<=O5jDxlN|ix%JR6cr9o+Q|L&|G!V?H&|ZW`Tzg_ z|Av=5I^X$pK8HpQ++O~cAW(LP=J1!U|NcYrI;aTr=sf%ql*DPp_Ut@DlKJGS2l)X7 zgFMvv;V?r|VsU12d~r!pW?s6LRlIL}a(-TMNl|HXi9%j!PL4ueeu+X^VoqiXif#r- z{Se~W391vi<2gLK^*tJN|ZQUy?w=Je>TRe*+gErUm|tAK~)@e*E-ZdUJx|tMX=_(SjQM}5T)_UyD%_-lIUSjdm+@PH($Up zBsAEg`HcipedGdaEckTlgPRJS;Eem*qw~8*=U0d;I$2aaJCArY|KKmT^JxCTSZWAv zH8=}^tNU(Yk4|TfV=PSQtp;0<<|7gy%N=76d$b-Xx%gTd++OhLybm>(*|YN~*bI1+ z0hUW&FM%jQYBNj#g}-B%52P+}4E5>N1qHBUh)=I7h!N@m5eNo_LE{@x0fFSl7L^+e zpgI>~Y&W6Fl0V-RgVu36R6%_@gZBR8*08V&CKS31-L<=ZNL9!t0 zKs2;D;M2QCr2}kBi^>de4gcPwx9A7RaVtQ=oh@K#u=#k5*Z@-73u!w*to{x%0^COF zY*7J8V>JRA79PDmD*PUu?{Jk+D}uLn%OD@?yD7X7sr9-Xex z7D4CxeHjc446$I-AoYnyw>hZF-~kKq%Yzah1E{PAxffdqr4$dQ%}00k7zx?JQ8)eHdhlXXlaELLi1m=V71D=boK+AVxve!SwzA z&nTe7%D`a4>c(Kh>d%k^4l9P_#5_=ym|T>aSdywxT#{mCRhF7ul3%2dlUS6VTBJ~t zk(j5Dn^+NFoLQBsp$T$32!k!$@dMNj`TxJ(F&xyV^6dNzuE2U_CV3ou%~({*4LrNu5N!j`=3^SKPeIkxGI(~E3V3M#^Jx8F0?`PoAHXW0 zcD}yA!0>;zE~8Q;>kCGPUPjjYjEu7wSwAu|-eLra+-72BV0gg9`jiROH3WqP1A~4bDCd^(@`fU@Kvh;^-R`CIhZK#>Yb`QXmScaKhpG;-w#tG9N6I!*A_7OW?0?9m;} z0j@JWU}Gm99*mzrHKzoKfK;Czy>q~$A3nWHR2G0LJJ5JmjEVrnEs%oR@Ea%)Ux51h zU==N39fk+eI$KmefQC`J!DSps(GQrS?ur+nJ~!A%gfs&*KtM`4pllz;=OC^ClY_#0Dt5vt}N#G3dRu(H<&5axkQih-&E zxg-YW637q^D0zSeN$FRJBmYz@vu)R@Ff277tL^!mBZ; zDoAbC*`flr8?0gq3xo|(0dp=`3R(vutOZxR$6Hijbs^LVEh?aj9NtvtZ+#6aV;YZu z>U*S?5VT$D*?Hh)>%ag1VdEVj{;daf)WFYBS7Z9UIrpPI*-0y1Y*2=_3!_G5CbH_3v=B|>;Irm zIJ9!_1~v5{Jz=nMuc!V0&zSyTxGwkPO{VB|Fo0oN=FvDSi@_u24(}Ez8 z$ATc0Zv|QVg&E!pbult9=w%h>=P^h}8(JG1=Q6lfloTZT* zyn_@Ri;GiBiWNfg^K%%2Qp+-nGxPHlOc+wKi{cZ(Qt>7E`8n~$sU;xY#Smjli{lOT z3_t^gsYUs@#rg~orTPr15PNjXQj7E%GV_viN>frnvbp*U#YM^b3^|!e`iaH45C&Kz zC9xz?pCPFtdF@E7BI3-=4SZI$hw(}VGX=VEAP zW1Y{8c16{*XFxRlo$Vkt?L=!3u)(C3S zgW8jzGSl5J6x47&01|_C(ZF-*Acc%oK@5x)0*ul;>>Lvq8Nl=HG9U>C1_tnO00RSq z0ThFTL9=`ePJ9AAOfGy9ZOkrw3e7C;d|Y*GLmE1_2+|H(Q=kA91Fuc+;S*?P%I58pmKg7#XfujZA`UbIZ${0}Y4or< z@)@+TIr3RFvj^}wFm-bASvc|;IPz&Y@hLd*NkIJX#LW=Ez`(EsYMv7p)I2v-^PE8D zxq!@b0h#B;_ko@H13Oj|J-8Vdz-EGGCPBuYXGJ#C1MWtInP4}%^F3f;fuRv94&%dUkY;8E(25!m z3l%dn2%-uwFff3oo|%xu!TAcRikShl8VAZjqL{&}bC3j}OlAhqN*yQ%iDG7e3!k z8PrkuAWj`KDEtxXL1_{s?#Kud7i55iJ18B3#M>D`Ynpf%8bAqyfq?;(o+{4LG4Rq^;eRf6^E6VFnd8`T8yCdjHZ4fR6S@i0@?lRpyIG_gPC(0Dh_JjBddQ36$f?ik;NI9 zA^u7L2_l6vXcz(H9&mY%ByI{-53>(OheE}n#(>wEf!O)bc!$Mz5lE1MfngW8V&#MK z5Y&FKIH)v1h=Eu~pyF&G4iY{I6-PJe98?^%o()Mk!)2&Ax(zp=;-ESeS^YhzxIMBU z0|UbosCX=z_$#P5tS*O1e}IbT!33c6H>h|SlnT;ZuO^g#JAiUTS> z5heho`Jm#{pnMo50u`SR6M)iEP;t7fq4i*4Jy7BAp~aWK*jfhc?iM? zDh``3g2`Aw#gD@TptK!S{4|sgqg+6yXv2g-+00bp@h>jEaqzz_-+hoxeK zcob9|91RFzhIp_zW@R=FERL?4f#EV(984gY!oZ*bYG{I&b)g6|B!k7#Q#k{}c2>}O zOhml~YinL&g|tCYO<`aVW5X^ki$mNBhqyNz$X-M}2ySOGFfcUXP=5@E_&FTru(D%! zCl5OVgAfBJy!;0T3usL$4si>1kUJ6eEUerr#bN$N9OCzIh`+~Sz77Y-Uhw=1I10dR zTm}Y)Ot3hj9*5Q3`*4U0bArr)se-g^K?eG9GB7AIfmYvwcnl1nHZ_Qq#fd%KCgTu4 zfWSHvOighRXzhxid3;&*U}%kX1&XDkl!07gjp1M1_0(gCPn2BOn(sGo{M zd=CzBP66!hNyQ=Fjzjz|4)I?<+L+iQnId?OC=UxL`f$54oY0XDS=3NIM81Bt^p zNOTwu@f;lDEjYv{;t+?8eu76>^^yw;7~-S+f=kTfWWEVjOt%IRs(m{rXP*t9JY55HCQ9edS zF0O8lp*|t;j={mMA;Iy%p-usgAs!$(Lt_{3AjgpSFxQ}9Pk%p#_^99#AB*_-%>2x} z%o4B)1BePgM_*Sk-x9(Pb`1&f^m7l6ck}dtNkFY}@eV>V(8tIGX1|kTuxpUNFNzC{ zjA63Q{(f$r?l>ep{hWP5U0hMzZVA)r80?E(A~?tySps2~kEc^Snl4mHbe#q;yIdSY z98t_PgvmICdiuCvmvVM=_CRsF5!^gqe-~6Qo59TU^>@J%V@3u+t^xk>LH_V=U|FzUBd}g0uwEmuUL&wxBd}g0uwEmuUL&wxBd}g0uwIBJkXgo%+-(L~ zS?1{%Tw-XDmYI`UTv=R_nhPsqObQZ9GC<`>uu;6LtBa{?8AKaQ-p~}e3`#0Z!(9v^ zG#eU}=4BR^rp6bP6ydelG~Oq(xWqKxGq)he)i2mM-q0A#j!#L=Ni9h&LUs{O*E^ef zI-0~M2OGw_x(0cN#QOys#+#+(7v(0FfHIw5a0y9a;B4v|Tw-Vj%G;TVIhj?dMe#YA z#U-Ag00NglpaAj?E-_6msVqqKOm?+M$&WA3Oi9giO$JGkUVdAGif`~*K-Zw$T!!4# z+~k5va4}Dmfpnvm-7xo| ziGsAC){-QoP>7d9!jLOj;KiAU>oU(C5fUB#kYgvGIaz^A*iJxIc_k6lyT7f1FAgZTADr?fZ&R2)PFmzX5ymxB5he#k8iL*sZ~NK+#o9Iw!} z8q`;~(wS*;PHJKiC_@;~&0Us@6m%Hf~}u#+jc!wu?W zLP{H)1zk!Q$lrz_fBPAlg%@R(BqrsgdKKsAxn<_0Ivcu@kzhc%5Q|}k2F0l*&|Q_T zLEhvT9BdA8C~|k#&=}-<&?+kM?h?h=~G%_kL$}CBZFUrr22Zv}$J~&N* zQUT5+K-yp$Yh{)Lw*CZ2hjC6FQ*+RgQMa|?D2i4Spf z@^J+x1Eg9CtQr#D@u12$u_UzuJeEO5Dgzq>9yJ5)lm#(BGfJSjhCh&JDvoY% zIaC~E4zj(Vb{}YEeE675qzx0vJ z;f0EWDCBs7%*#U77$JvSI7lHhzL4W32T2?`9J-Lik=;23NgOmc4hzroNaDRn?tF_R zj%?0XB=J5Z^<2;iNRTwLd$f?mkK99ex7k~nfa<{*hrLh^4bk~p&Y z{Yc`-`F%E29OPfnY%a|G%hAL^X$6$uHlvBdHXZFp6aNQN%)r2K8ciIuRud$39Zh^5 zNRWYn;W3&xY+b>7G;z?{d61UhXyUN>a&~r*ENHD019&yqY6zD>7)|^vL2)uT5cexpKVZaQ2Ifx?{-7Q zLFORWJ13#yAoZZ44pt9cLKFW34gcFn;!}{^{}@ReWR4BUKn4Z|HmE+3y;G6Y^FqZz zGyBt##HFC(AnhP?WIznixm-|jkU5|=zp#9v2^9w^1Epn{xCK-kWd2Mf^PQpM=;ruB z#X;s6BB_V1YeQF`j-(#s&O1;(Y~CMajuDbMEl_!MbGo78AoU<~U~5PxA&DC!nX>{a zj&9C+s5s1=IZ!@mT_7lGK;odZ2MeDwPOn_Xz|_BiileLl3>62d2f056 z%KrtWLE>ge?uX5dqMIWQQV6Y2LFT~LOv@pOnl7pFl6)Fxg zCmG57yGY`owV5#Wkae7pdf6EoKOh?fKn6g=AK82fs5pp1HXpJ+64HJ{HeVg25NeJK z(w>Q6BynW(qoLv;3fcT*kO0(u$mVB3#X)9(ya@AGJyaY-6(EHJayuDRx5L!W0V#x< zpNgdZBvc$^ekhXoEvPt%Lau+Wf&`%EAm_VhP;rnspmv=hv|RdxCLRqH|A!`?3>Am9 z!(rxtw$*~-OAOk+g^9!J6(uzBYN$DSXyTKh;?U*~czJmg0|RJ9HpqAeSo;X%EadhK zs7(%10J1k4Nj)t8fz*TYG%TEHZN3-CG0^Zwb|-A*D9Am??Qqb(2#^+#IC6Uo)Q1I$ zgZu@;F!zJ%M36X0J#zX4m31(2%L(>sRJ#sjkAc-T#i#?J!sLc#BCj?0xSv{&O1GIHL1_4tAc;eEGegQrkT~dUS&&j#e+6U?NF25!=Q&6c8a|~+ z?s*3lhpC6vFM?3_!^C0h^Ch9;AonAi1KU3VQxB2{8LbXg4-*HC8G*#Dki^ z$m(N|#F5p*j!pqdyCInaI<*DlPLO+$)x+9pAocD@>RUhpPe3`J_bl0WDasX!p6Hm<{-zT5=bG`eaQA&B8el1PbCiV1vtbH;}AE5)<+=eYNU8U z9xp<+Hyuema`})46$kkXIeaD}i6i@WBUBt@FS0p%q2eHOki+v7R2-xpxn8>n6$hzD zj^Ddz;;{Jrfh3NcPFSJiCm{1dZE9G0lSdLqc4rWhIB2W|rXG2mstzeU4d@=noYK`3tno8z$Zd6$hyY?cs!pZ^I#e21&dLDSn^e5Pydx4%&kS zGygM^IC8sJ47x=X$l(TR zOTg44n*(CQ#F5PbwP|7EAT_Y`1F92Y;>hYjWiLz|+1_@LAeQ(7%}s!$K<-2~A2e18 z6Gt|G8AuR|Ih%2aAHpGi3WxZ09O6%q#F5?k21y**oj-AiBaZ_kn**CS0EGjxIiSP( zK}LbZk=4W6y&!R9_4-KdRb+8DBynVO{E)534hv6Yb3kGs4AKTF+F|>tL1G{b z5>E#)pcuAO6jYvo?1l<6fX0?VY>+qzgV-Pp8v6p#ATbbznGYLx1c^bbM36FuD_|1R z&jPsz%4LA16OeikhV6@20XY!beufrlU@fqH=ODG9^BKT`3=9mg{v${nR%V0bVDSPH zPXY-*F>L=6NE|kX0Fs)CWG}321c}4;&4bhz44v_hi?uGy@F2yt-v^omQwhm`}tEKhQ zlau39E0R+SO5(w5*dQ^2bJY@l!=TX&_AhBGbqOs$rb^NwyvP|xa8TDT46y6~+NegI z)yI(FF+|G*)LPn%HB_i(I5g1|mlPT5q4=OQFDElQHK&pR!+xkgL91Wm6N`!xE1?45 zLZ&D+M-RLdSr6Y<0KMe=+}zZ>5(d4z{E}2XcfU|w@Ln1yKRvHh545{5wWtJUcxpy` zT2W$dDuZ5nQGO|C!U9xQQh*g$8IVrnK^O#@qXO|jWjlxl&2@wNm9V-TM&r^CTkim? zJ3;zEVlaI$8kc@hA0K2ds7?UUApM@ub}ficNI$GSfowl$%pax?M&q&{)K>%91FM5U z_Is0HKd3K>t{>FrfY}S9aoG=AGl8xjwEhjI4@TqC4?BAc+5e#S3QQl22DQ^bO%7Op z4rC_?gN{!H(ecQQF6g~!AaNK5-HQe?3zlAB;s(%;R|V8yQ22qms<89~I`0gmRtm_jfQL4e$f;4v_O#%VxG(e*2U1VQ(zfEpr58bJO<;xd5T1u~NjT^&?E zn)kuyx*_Wig1R5Hh67n#1F9dit^`>eD$D?~6C@65V}sb}_9s9U!upFKwIB>jk03S( zCqmOC>^vus7znQbC3evHtRN2Pauo&!@F`tTW8voxfz}Oy?T4y^Q4gRBVe9i?;^_7- zhS?8O0Hr@b?Oy;j2Ncerb}N(%w;#0L2y8!k_(L1Z=;;dGe$YB5aQZ{jKLIqU#K6D+ z>hpk{1hOC0?nJkr8GMcv0|Q3*L+uBxu>$FbVRZXJ>*cW7{{d=0Xe<<@7i2%^^b>UZ zy>ZyT0ct4UV6h)mm!jMM z6ly2Cux{9xr0DE>feaA5jj@rTWBklQ|hF0}=n zdkRWi43P2#)c!};56a$XP6TOZNB~&~T1SpNCKg7EJfjWMqH=Mg}_u1P><4z>txTU^{@B4h;GXdSJCY3=CkJkAZ=KAIcVDU|I@#;E-D-;9@-G&N&`Haj|fD^ zI>sF4mv>yqm$XA^SDPhi;735vw%$3LOL9*u7_ z7#SEmy309`BB@11f{}s2@PJ3}8kG;=XnPM17|(7Q6^~vQl>(368kGc(&Kea3kM80E zkM7_KP|R9@hy)MDPcL@;`~Tmgw?zdMy&k=rCxFd34wB{o8|2Xq(h7|TkM1oh0w71U zekqy`mt$dUQfu>f5cO z0&>6tkj=e&R3I*>QIYWME-mov4h6f{z@xJTBE$IU1v}Kq8$cC;h2j`2m{nFH7X81mj6rmKv_J% z0~WcU5Q8NSqWxH+qOqf>5>(tk?1zN#aY(vx%FIhl>ugbB0VTQPEh;}47#P?1xOJGDMb*4wU9^S5l~?RDz6=59pfD1 z4}(1eDxN$#55EK@@4?9S>^uT@8#eX?kfR;Lp(T)G7@}}(ep7)~vbv~bfQr=|NCpvr zWf@q(s^HW4A6!a$bQddlbO&pII0B$Vk?|8$G~}olc=Q%Kz~d5>BL0H|5tLvOAaM#R zo1tPgDh?jKF)9I|f)gWSm8b}S(x3!54aTTAfUIEzTT`Nv-~%!mf8hg4!>H*GWS!-G zNJ>D?!ss@^llr6||NkS|ge{?yVv7MN065^G(_Nz?07{!25Em&RrA-%=3`D}@_h>#+ zLG4tDEv0}G3QQcWeh&5M{Oi$q-J`RV!J{)2nz=gPw;U+pjD2bS~b_W2jHBE+}{%LwtHcZD58_4~Rf8C=?ps++bi}K=Nga$_WNg z>k49UH@NW$X_rE^K_oigL#zB3XFyGp&UYT&U|YaSA*~!xmgHPvoXu1H4ftvFgUD_vy`1DF9VU0Uo_YKf#(o)__t! zEUsaSdvjDOKuz!ta6W$T(OdMxr*{ps+3TWGfnW0)6-e`=1=3gnWrm{fApMZ0X$x2y zyAj7hO*N2<81{oQng@c9!~|>g>^$z#30CdV+W=PEo1>xt6#`iXQsvY6n_nK(^kMMm z1(h_V4?Ma%68pk58g1&CTn-J|gcsN?|UcSt6WhW1or9b+KvCve#cHVagwdvqQJ z3qaV%;cQrq0}{u@M%If<4NM$d|9JF*!wuZS?_~GruJ`chb&i1656%&Y`T?TOqqo|^ zqmwxr?kK2!NVNym?+VlJiba2|g-53=wDH~feqROy14As>G)R5u(QOW@vUtEk(D(w? zHK5o5c^p*VeSz5aJs2Eh9=)LgKAq1%MRaEpu@_*V8ZIgV8iOqki*KrV5Pty9c_>ccTYI1 zp$K+Wut(=*kH$AUn9*vA70jTT0+fvwFflOr^zKnnU;_1Pj)QwCpo|D@D)jP#Og6k^ z_|2oUM+KzVqZ=%g);UF`ff=Ny2coyz@dZ@M<9Lfo1v5w=0|SWNfyADG#GZk~UI1fv z_OO7R0Ewrm zCDg!fQINwxna~2{W00#Me)Q;^0)Muh|96tEq=Jt`BJ z7#Kj|%*4O|8b9;s^ii<@$v1$Uc)UfW18UB(7O+xC3ioY&!rxNL1}dl_9X=mWasJ(- z^ANAua!C%VYe50I3)J0)mhLbyk8Wd+?qCj35sw(r@$g{$ z1WH#DAR+-`UGE(5n2b;F5^%8#F8g9spdCj@1~>c$3d9$n4m7yDZvpEtJOJuxe*pEg zyTRoJNYM|NqV9?ppb;2wL64ATfCdOiDF>A8!}uJ;6@YR*I@zHPgBuF!(t`X68nRje zbphDm<^viaOTc3Y5T}B;U?sgRDi6R)!NWWXARBgo%m9fUZvhX2fVd!WP|*xyUjQ+n zYCr`vh>PMJP#f$%vMr#otK%&yAVmTojh!wkU`K(+)}TWWAXAP(MkpX@05psey9*Rn zKAq2xxv0b{f%G$YbjPS9_;lx}WPpZP;yoGf`dGd$HF_O|81Hjv_^VW+3DO@2)9=uc zqY?+v-+Y+S)ADYK7XLPFhlal~r5B-U{z0sXj{z%teE?w|$fOvkDv(QJU@mD<0fhyq zasv-)fl@Qb8z3+Cu7M2xb=zybJ6U`0x=l%3%Xoosfou2cA@6 zU8AA_82|xA8=@iu4_QKu>uga0r68!oAc+v%+k})_ptuJozHWyXpyCS5MrZ}4MW|NL zFsgNpiUg#GiaL4%F3dnCbgyAi00j&v*RN$_U}&hdVBl~0#>l|HzpvC89uS?!p@z1o zfC?&5w19F2DEWdM3l9FyIp7?84AQJ(07r)|sAlPIQ2~{D;OMAfWMJ?CMMp6>6^oq;7vz-3@(3#49ZJ`ey7H&D6Q`~sXm zz#)JLH*k>(9%}**0)t9cl;|;lHYz~IfYd@A1CJgKSXBd!B~aMHt1+l5aCHST0Bko{ z#S|6@8=?Z{T(A_h4n#N+T=5=nQGwNkP$#sgfGTo$+m65WH7JiX9s$+&pvDEHId>S^ zZt?6q@UrzEsLKx-zX$Q3{Xy{IE$wbs254)09~a2LZU+Mo%M1K1FaQ4k@6q}G{{{Yi zA70-1`~N?r{|#zmLcCJ(!iVvDcez6IImi(D%acFBiXiskQP=eI|NjXdy<1d3Q3q@8 zynO!``^XL9pBk4(ll_;B*Gg zW{3bs$x9v{op-@jfyOl*AS|d`U^c+q{Q5l1@@5F*=<8E3hB=H;-~p|c5bgoDHlXeS zvymbjWGe?!8U!T<6i0x}eZ34sdUPIry$Hm3`Rd>Q{~!iPgcs(zm)8G5T|{W*-VGX8 zgLDDF#=V~Q|372;Ge*`K!VEK*SpN$%%w=JnD8jIZrKDe&;RqXRgAl_)4%Rkdh8-OJ zjGaOZ8@O1%3o@MGV(k!NxX8oXFU+u?m-VMG!);#Hg~AMn1>!*RK68t z?H6WvFVw}zz@V3una7})Rh*y4ARTRJZET#&;95~ql$czSnU}8MSX`W1q5v9FFRDZq zcg{~qg$cWO2SL;oD}?0d=P(4NmSq-a=I1GxFr;J`#V3M{D2^}5&(Dc3PAvf$TMV(U zv^d^S&j2*cm0FaaTddCjQL4|73UPpLS!$6!LuOubPH9RiNH$lWp|~hnpCKnRNk6eT z7s3FGq$HLk>N6yjX6B^mGw3BJCTFDTGvwx{6oYkuG{DS(TgMRO>geL@s+XGrYKFmv zLLpHC@AHCEBREb#aW4U9K^x_uDgz=0A8CTecgjD z_pT8rETMulK>AFtuTMaC87!3G zodNVvxQDLe^%=N74`Jv=jB7)k4|4>}{MUD2U22#qK9;}vTbe*Kdfnv;p1t+pVNF(W zNO^YKd-l3RMl?OU-4P?2p3TQKULS*INw886$QYeRH+b~QL-U_U>;DpnDWFOg)HcM^ zv4=VqY!b{*aQ8vyb4V3uVEF%^G2exifuWG~G8aQHBkOT4hFOfPySW(NF|w}bVpzh& zx|oaM02AwUE{3yAtleA;E0|gTb298@X8p{`aG9C)IVZzP7Ldpu7S`LG46j&N&vP=& zXJtLi$#9O1bvq|R54-w#PKMp=tgAU0&a$)4=LA{F>U@n6Y`3{BD+5C^>q-`e64tpa z4E3xNSr|?+vbM4?++t+?$;|M9k@YPz!%ilU$Pp&ihs+Gum{_kegUn!24rO3q_&?j1 z(bXL^G&7M6TjSXaTCp#+x!$fwFb7!)HoOOg9FI^^Ckz9Nd?qD0dx#5;EFjz1! zFn}8MAT9ergcF}YFOwUeL=UqgpF$gpBcDbys|%k4Q#u!)h9lUWPGD0UxxxPBfkX!b zD6Bx*L495Ys2F$+iVvSaGgCev2Lq%(Yy*|^11a|56KG?q1Y2^pq~kBFPdM#_PX$GU}Rp&h~M54XdHkF zQE+(jZD2&U7aS+hjGzZ{qbn#5qq+DvJh&bCIKbht18T;97G!sU!`KrP9-g2u_5g*k z2Pize_$DwhTYEE;xS$*)iWy!?Aqg@tFfcQKR(PR`fq2Z|(JBxN6*GfZf1!$jc+3po zlmKF)U}o^@Fccv$hnWGCs=-VYf|)@Hg%9F5F)}bPA*l!D0g!k;R9p=dq0sOJiO&X$ z3oyXK7nJTm;*S_Xbpkg-15`cC1^=Mppn@Hw4kj+h1W^wgCWLBZ0JZxW8MwhTvU*V8 z3MBpjst{(5C)At+XyQpw@daq&puQEzoCGxSxlr{EXyTypK9G7?{)gFn8LA#Mj)CmX zH&AiV;1{wuCo{yquyBK!qXrcR^}mqSJ3z(3lOqfa@ED4QiYI^+BZ-$m#liIek~nCr z8SH*E^&6n-p~CPKd5Rg59#%lZ0aONn)QEu#0&ou=#D!yNu(&*&4`V1m#bI?7Ok5Qz zj-KPSpyHtX4O0uE^`YY0APy2Xfr>jJiGi3_Q1KuT2MIes#bc4gKukBNcr}QFgngjm zpmGICm>~!%-h(X2z`zgz6`z789tRa)h$fx_6<>uWo&^KzB zD*g+^LBgBB;?hVW5axEMIJCNi2r@7*>;a2ID>S$$1H)&qIJ#;E1_N+{1xq5SW?*Oq zi-QRi@dK<33`z`$dJ5JSz0C?~qoOEgU|^7E!!E9dL);mMcnBNFUPQeHZig~3Fm&Tk ze;$YUbsXmKv150qC_4j#5CaFioQH*o4i0f=c91&}^(L%*YQSOs9vtE?aftuIVZJ#B z$X?KDYe)=$+rSJA3?*Q3M7<1a|DMDlF2@Nn2h`Grm;-A2f>@E93=E1);1ww#F1$rj z%85PP=HU=Ok3(FT3%fZ9IMgd~VRvUNSRB!Q0JX(I4qk!7{M|UjAL0;K;KuIGR2|e3&)^Whk3;-54)LEj#F=@qyHf>+cmfXbWjMt5;Sm3aL)@MZ zyL&wOAo&;6hX$nsP(KPp7vfMqABXrE9O9pGh&%9OcTW}$@w+(0Ed{Wf6NW>4J`VAn z0+4X{09u~Rz`y|N*MY)e6(dC4fD^=HU;y{K7#J8H;4tS8)Esp6CV~tMuqjoDNf6Qz zBo1MskdZjV^Kpo`;}D;ML;M^L@hdpQpWzVyhC>`SZVVZ&)=MrZV2F?M3obE_k58_s zFf=qYLS9knnH*eVXqcRlSQKAUl$cpk?3wHuoamYC>S}0&yw=h)z&qL1wJan)*dji- z#K<5mzo}xVS#ffHN-A8f zyN|zKQ@Qg!oFm$3I$j}h#9M8P8e1`ZaA0s0d zS2xE{pOARR;9%E~;P~KBrvS$g50IRpv5R+*V@Q0MYf!MKzaK+zM1`NDuPc~u3E>C3hJ<+fxd+F)dHTR4pw_r}2O$~gV`Kue-^nr9HOSu=#RW#j zFj;4RKQ~Wz9Fm@X&OV_ot|)G|gz0n)_Qfs{9OR5Ffw0TR(P6L=-E{-9N zC}tYMWSl}heO$0hIXgOgpt#)#Zl15d3#ymRVCMPyyI_eiBZDB<0RQ+PfB%qpH%~v8 zcu-UZGsIIRxj>Sso{zHugPxDGF^Dh$5vCx*3`AIf2t%;6p&^)U1SY|14Z(^H!Kw|x z$_>rIvJhRCAhr=$uMt?U5m>JgSg#RSuMt?U5m>JgSg#RSuMt?UF<37|D=0Gsmzb5M zCYR(FdHMyH7#gHy=A;%^7MG;v!pbj`g2a*xP#G0$6z}TlV(MB3(FT(@G(|4ol1kHX z7jX#9h6bg1nT4gP@dYLLEjEq!$t*50jrYtg$Z_=xHjXzm2D9T+Qgc#EQj3sXgwyrT zrk;)_@yWr4@vg2x-XZaR!G`f>Y57IDi6x+H=jR<}rvcA77rClA7n5 zjOI@w%W+FkF=#^OmXn{Hn3L*4k+Uh%YygR9P&`vF4?zMFTmn$fP`Ed7XG|kJ8Pg?PuP8N5 zFFroKq9VQ^wWv5hFEJ;xq%yt?+T_7$EF_^j6Sm*bB;Gf^xF9F9BtAK}prjZUwD7Wx z$UJXo5bqnGl384kUz`duBQ&o(GcP4RD7CmWHx-l_K(U3RXmvKk69%9ri=j(uQfazJ zYED6Fk)dH`URr*9a%pi%ey*n%IKpt4>+0(2S{C4)9BdlzQV-x5-OXXY1UE4e}GJ|qM=gIPe-Lv{!imlUNY=3>(bY1M+X`vsQ}u)_q@QgRKz zo)rz_L584aa&p`N&AQNJ5nN(u79XDvaesVfUU6zs2{v!I1_hTG8biDcRqYuPA7T*i z8f+FH0BXyEifhymg8CMuJTosHVg)v{5kZ9NJJR(d#}6rKwkWkACowtIH8(fFI~iK& z!_x??$PUgoE+{R5)`$6~X*s3E8K6`i6rR;-XZchQ{%}kUBIT9Iwy@1JqZz z(wS*;PHJM2YjBC7QM_kHw%0iHvx-0V%MMMynjLc7s3}8Kr+>XqKK@5}#jM5)Uc~K&>?= zQ*h4{)Y}57##8vfOUfYcU?Wf{;VV&6!a#v(2v%lj7G9KDl9-f}>Q$Vd=a!k1>TKvr zMk)klZ9i1+7=gS4@=9J}ZYr8rFs-#HPA!QCdD=C|n;iS`c^Kk244)brfb4{ne`MMk zY>p!oO^OrCz*R^TYN!|)l^11}q{bKJ=f;DUoyC{rgQFW1<~Zv?*Q`uX{9^_hEajo6 zH!MAAumQ;3VT(+7j~pzA+H-d{B&tUppHiG3pOKiCk^{})@IuGLGcU6QQbt3&WBzV# z!LA|kA&yQyuHaA$EBfEW{%SDwoN8oEi0PfAVC%!^M> zEJ@CQilpX&$_)g+C>30ufXA~yJ4->e@bR2s;?$nNn&5=S;a0xAwN z4z%?a=FWH|anRT+OgsfD4l+L-DI6-1#F5=I9Z4M7J!g@`8Ik8CUk=P4XwaUf}Aaakns zRwQ@&Ac-T#OB|AT8m= zbpL82i6iIJpHOj7dPB~qdhDQF4Ou&doG((5#F4|N07)D>g7jab)+nBZ(uYhe#xG zWb+G=#F5Q!MiNI>KNm?HS^YsIapZV(fzHc-+~0*14(3SlD~Kcxnm-4{Fep4h;w~T# z0|SFUntD)K50Z*T6HfvOGB7Ztqlv?2{EN}VL1_r2r5;Tjw7m)>4w|0_(J=SS1#uV{ z7^b7Chs|6sMiYmv7g>)c4%;lZ8%=y4)coUU;-C}5KvI{{#Gil!85kJuqlt?`>$BHr z;-C|LKw8d1;|u05C8+wFXyRT_@uz6wAyDy;XyR#5@xN%|Mo@81XnKIzTL2XoMH8O| z6<0(Phpkrw)iof0fYKFm`t$$^Vkyt_aEOD}27{zP=783}!pd#fdLfWFa{C0fo)sjH z+&+P={{e|3r~hpr!x=zpv=|tW+e^El;vn^)v<$QNG*lcEKA@@$){eP?CjJK+K6jDC zL2ibb16$7nGsgzRU|?Y2fa(L;+l!R%_@Uw;H})fm%Rt3J+ClD-0WlaD7!;x6Aag*w z3}N`kogml%y)%~qnqOo6$hDPh@>95eTZytCX#xPJMTdGu=E8o z#|X)sHmE$hy}eLzkb00gd!YO&P#Pp|jARaI{uvYn=;mxhQV%j`4wMgD{|hn)l=fiZ za}FwxZVs$n3Q`Z+asgBS4u|@$P;roYki9WbJ}kX}#LbZ0F9Z^R<`?Afl!S_dD3Cd@ zwdtVso*@5%#Lbb+F#`!;F~=4v4x&Kjz|xZoNC28IK=| zhiyFviCZGMrw$~5#XYT1aS#PE=MKm-3=9lCAOWa*tdPuE1Qkbj&q}B`hys}d>*s6$ z2|&%UMl$CZR2OpJQVE*j|X@>eY4awelP;roYM{#{mk_#6f-nVaU2yNc{*>4{bIuv_jQ`s7XlS)(;YZh66}F%$C24-FEB?F|EoBd0^;b{!~e zVc~|{u0u}e$m5O3{?!K=42>7$bOLK%f!q!1S6g9WQ`k=`WBD?)SbxgSpyXZQ6LO+=SdI;svbFAU4V*%C{S90mFM3<0?>29a8Xt@fK2CaREg|jD;II=mg`U0dLxxC7Qsz(nW z*!Uqx9NE7cq3Y4i*$Wj1sYedaQ&4e`dgSu?B2*lt9u$utc~H3DMH7d`?++w#UyP(a3Q4>KN&EnkIC40H_Gf_12f4o#N&Oup^~mA> z3rQT=J&e$b3SA=#bNFQ*#pWKHc)X8AJpfD`3uAc$%AO*b{EWlAaP`SVg3V&BhSBp?vub~4sv@K z*&NUq7dG|C?O|l~pgtf>J#zSf#ynx-$m&654mNSv{#KCtk=29BE^O*SWhqP?Ieb82 z2opy(2Q-&~O&ruGf{7!W13T{l-91Y|im}8yY@a4bJ+e8l@pzCpvU_0Tv>Gj;tQEPaWiCkT|k>*n9#=9N9fVNcJMDhmBu?)FYdpfkab$B~^9dmH zk?jQ?_XKl4vieC#<{+zw%~ycTLH5@o9O~EL5Z{6%J{hUJJ&z=g+<%0fG6}L5x%~j^ zmxIJXdz@kA5+kSpgSMYRO;?yW>~u+xG)Np)PKkm9p!o&ad@Uq#<5=Randn9q> z@PUm(fZRD1$-l7i1CThf`5{Q=Ae)ceuR%5+Hm-nfP7V%pVB;Sk^~mPH`a2+TWcMKV zcaYr!8&3wQM>YqPra%}JouDQF?0f-`7zl&JVSRHDA9n5l$hjc1Kw=;anmYi|AaM`| zu|XKrhXTmdnvd)EhO2L!q~)Z9>n76f2-;#_0tjBg8rUV3tJd}>8y%NTm%2SUpcQ!=ZsuTvBAHhvI|MyqwJJ)SOBN4Ev$}1g%Mr zPb?}*tb_`HGfz=!jvjb#j~>2#Cwj^Gxw)x%B@B9b`6a1(?tY=V;H_IwetKT19%xf* zYEcQy@YIa>w4%h^R0h5DqWn_O02!!oqX7S4W?%r7Gw4Qu=IB6TpfU?YgT@s={c~7d z2cvQ6hpqR3)h!_X?$GuM$UH*&L1U>Pb+G;yNI%F-m_8Vd%YImWi)_Cq3HHPKL9jXs zWIt#Q0cJ0Z#$`WjJRMm-Xk8ghAB@JOAJjGk`5)Q+p!yi54@QI9A)qQ1I$Q-d& zkYM8nU_ns(0mgvRpc7y~X2IecD$L*j8f<1@VAugo03iQ^m>>*N13SqBbeAH?erWXs zk^z{+fK$rt+KWJSHh!4Xs|AX{^#6WYnEkNu2d#So+YeO-qYgmr-wz#!g^8ovzZjY)FybGy z_=$mmVFENBLGc9Ai*7$?y%gAfH1{`v6f-a|pqmR7hB=1;v2LFz#EgUTXw`@M14 zF90o6Vdvt2%m86@``w^tCBn{c1E~Sw6;S(O@eHybblMKO{i|`MLP+)`FJD|kHz`y`n xw*hLuqU#4`Z}hYW(r*D;ObSY`ph^cM0L38tpiD3YDrT_h&wyt9|7eov`T?F`2-E-o literal 0 HcmV?d00001 diff --git a/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/extractTypes/extractFonts.o b/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/extractTypes/extractFonts.o new file mode 100644 index 0000000000000000000000000000000000000000..d0a801afe5437261413e05f883e885c6c8d6251b GIT binary patch literal 46640 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 L42#j)Kj``aunN0Q literal 0 HcmV?d00001 diff --git a/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/extractTypes/extractGameText.o b/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/extractTypes/extractGameText.o new file mode 100644 index 0000000000000000000000000000000000000000..11e444184305ca7729fac1250223738c08dffe90 GIT binary patch literal 71600 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 literal 0 HcmV?d00001 diff --git a/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/extractTypes/extractLevelHeader.o b/tools/dkr_assets_tool_src/_build/dkr_assets_tool_src/extract/extractTypes/extractLevelHeader.o new file mode 100644 index 0000000000000000000000000000000000000000..f36b4e1f3a6a57105aefb003ea6935db0f240991 GIT binary patch literal 78600 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