diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1657a2b --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +*~ +*.3dsx +*.elf +*.smdh +Thumbs.db +build/ +lib/ +docs/ +examples/ +internal_docs +build.sh +output/ \ No newline at end of file diff --git a/.gitmodules b/.gitmodules index 4fd3f8a..ed96bf9 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,9 @@ [submodule "buildtools"] path = buildtools url = https://github.com/Steveice10/buildtools.git +[submodule "source/eshop"] + path = source/eshop + url = https://github.com/DanTheMan827/3DS-eShop-Utils.git +[submodule "source/ConsoleProgressPrinter"] + path = source/ConsoleProgressPrinter + url = https://github.com/DanTheMan827/ConsoleProgressPrinter.git diff --git a/Makefile b/Makefile index 0ba2a20..4647070 100644 --- a/Makefile +++ b/Makefile @@ -29,8 +29,18 @@ EXTRA_OUTPUT_FILES := LIBRARY_DIRS := $(DEVKITPRO)/libctru LIBRARIES := ctru m -BUILD_FLAGS := -DVERSION_STRING="\"`git describe --tags --abbrev=0`\"" -RUN_FLAGS := +BUILD_FLAGS := -DVERSION_STRING="\"`git describe --tags --abbrev=0`\"" -DREVISION_STRING="\"`git rev-parse --short HEAD``git diff-index --quiet HEAD -- || echo ' (dirty)'`\"" +RUN_FLAGS := + +VERSION_PARTS := $(subst ., ,$(shell echo "`git describe --tags --abbrev=0`.0.0" | cut -d "v" -f 2)) +VERSION_MAJOR := $(word 1, $(VERSION_PARTS)) +VERSION_MINOR := $(word 2, $(VERSION_PARTS)) +VERSION_MICRO := $(word 3, $(VERSION_PARTS)) + +$(info Major Version: $(VERSION_MAJOR)) +$(info Minor Version: $(VERSION_MINOR)) +$(info Micro Version: $(VERSION_MICRO)) +$(info ) # 3DS CONFIGURATION # diff --git a/README.md b/README.md index 84e09ed..b13a969 100644 --- a/README.md +++ b/README.md @@ -10,22 +10,19 @@ Fastest batch TIKs (eShop TIcKets) maker and installer on the planet, right on y - Removes temp files, leaving only table for local storage. **Soon** -- Region filtering; +- Region filtering; (partially implemented) - Separate menu items for single things; - QR to CIA for quick installing and updating TIKdevil; - **eShop redirection**; - More speeding and stuff :smile_cat: # Building -TIKdevil depends on [libctru](https://github.com/smealum/ctrulib) and a git submodule that will need to be fetched. +LibCTRU v.1.1.0 or higher is required, this version is not installed with devkitPro by default. This must be compiled, the lazy can look at my fork. -When initially fetching the project, the easiest way to get the code and submodules for building is the following: +The bt folder contains buildtools for the 3ds, up to date as of 5/29/2016. -`git clone --recursive https://github.com/Kyraminol/TIKdevil.git` +The code in my fork has been modified to compile with a standard devkitPro Windows environment, excepting changes above. Run make and magic happens. -If you have already checked out the code without the submodules, you can run the following command in the project directory to fetch the submodule data: - -`git submodule update --init --recursive` ## Credits diff --git a/audio.wav b/audio.wav index aa0e4e8..be54256 100644 Binary files a/audio.wav and b/audio.wav differ diff --git a/buildtools b/buildtools index 8d891f1..1ea00aa 160000 --- a/buildtools +++ b/buildtools @@ -1 +1 @@ -Subproject commit 8d891f1ab9f37df9d9edad1d215d090f31ebbb11 +Subproject commit 1ea00aaa369d80a825002e5d514dddff2305f88b diff --git a/source/ConsoleProgressPrinter b/source/ConsoleProgressPrinter new file mode 160000 index 0000000..b4a04d1 --- /dev/null +++ b/source/ConsoleProgressPrinter @@ -0,0 +1 @@ +Subproject commit b4a04d1004f7a9dee25e40eb55a23ffbccee5c67 diff --git a/source/data.h b/source/data.h index b3956e3..208cc50 100644 --- a/source/data.h +++ b/source/data.h @@ -1,222 +1,222 @@ const char tikTemp[2640] = { - 0x00, 0x01, 0x00, 0x04, 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, - 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, - 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, - 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, - 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, - 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, - 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, - 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, - 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, - 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, - 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, - 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, - 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, - 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, - 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, - 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, - 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, - 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, - 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, - 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, - 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, - 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0x6F, 0x6F, 0x74, - 0x2D, 0x43, 0x41, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x33, 0x2D, - 0x58, 0x53, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x63, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFE, 0xED, 0xFA, 0xCE, 0xFE, 0xED, 0xFA, 0xCE, 0xFE, 0xED, 0xFA, 0xCE, - 0xFE, 0xED, 0xFA, 0xCE, 0xFE, 0xED, 0xFA, 0xCE, 0xFE, 0xED, 0xFA, 0xCE, - 0xFE, 0xED, 0xFA, 0xCE, 0xFE, 0xED, 0xFA, 0xCE, 0xFE, 0xED, 0xFA, 0xCE, - 0xFE, 0xED, 0xFA, 0xCE, 0xFE, 0xED, 0xFA, 0xCE, 0xFE, 0xED, 0xFA, 0xCE, - 0xFE, 0xED, 0xFA, 0xCE, 0xFE, 0xED, 0xFA, 0xCE, 0xFE, 0xED, 0xFA, 0xCE, - 0x01, 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, - 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, - 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x14, 0x00, 0x00, 0x00, 0xAC, - 0x00, 0x00, 0x00, 0x14, 0x00, 0x01, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x84, - 0x00, 0x00, 0x00, 0x84, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, - 0x91, 0x9E, 0xBE, 0x46, 0x4A, 0xD0, 0xF5, 0x52, 0xCD, 0x1B, 0x72, 0xE7, - 0x88, 0x49, 0x10, 0xCF, 0x55, 0xA9, 0xF0, 0x2E, 0x50, 0x78, 0x96, 0x41, - 0xD8, 0x96, 0x68, 0x3D, 0xC0, 0x05, 0xBD, 0x0A, 0xEA, 0x87, 0x07, 0x9D, - 0x8A, 0xC2, 0x84, 0xC6, 0x75, 0x06, 0x5F, 0x74, 0xC8, 0xBF, 0x37, 0xC8, - 0x80, 0x44, 0x40, 0x95, 0x02, 0xA0, 0x22, 0x98, 0x0B, 0xB8, 0xAD, 0x48, - 0x38, 0x3F, 0x6D, 0x28, 0xA7, 0x9D, 0xE3, 0x96, 0x26, 0xCC, 0xB2, 0xB2, - 0x2A, 0x0F, 0x19, 0xE4, 0x10, 0x32, 0xF0, 0x94, 0xB3, 0x9F, 0xF0, 0x13, - 0x31, 0x46, 0xDE, 0xC8, 0xF6, 0xC1, 0xA9, 0xD5, 0x5C, 0xD2, 0x8D, 0x9E, - 0x1C, 0x47, 0xB3, 0xD1, 0x1F, 0x4F, 0x54, 0x26, 0xC2, 0xC7, 0x80, 0x13, - 0x5A, 0x27, 0x75, 0xD3, 0xCA, 0x67, 0x9B, 0xC7, 0xE8, 0x34, 0xF0, 0xE0, - 0xFB, 0x58, 0xE6, 0x88, 0x60, 0xA7, 0x13, 0x30, 0xFC, 0x95, 0x79, 0x17, - 0x93, 0xC8, 0xFB, 0xA9, 0x35, 0xA7, 0xA6, 0x90, 0x8F, 0x22, 0x9D, 0xEE, - 0x2A, 0x0C, 0xA6, 0xB9, 0xB2, 0x3B, 0x12, 0xD4, 0x95, 0xA6, 0xFE, 0x19, - 0xD0, 0xD7, 0x26, 0x48, 0x21, 0x68, 0x78, 0x60, 0x5A, 0x66, 0x53, 0x8D, - 0xBF, 0x37, 0x68, 0x99, 0x90, 0x5D, 0x34, 0x45, 0xFC, 0x5C, 0x72, 0x7A, - 0x0E, 0x13, 0xE0, 0xE2, 0xC8, 0x97, 0x1C, 0x9C, 0xFA, 0x6C, 0x60, 0x67, - 0x88, 0x75, 0x73, 0x2A, 0x4E, 0x75, 0x52, 0x3D, 0x2F, 0x56, 0x2F, 0x12, - 0xAA, 0xBD, 0x15, 0x73, 0xBF, 0x06, 0xC9, 0x40, 0x54, 0xAE, 0xFA, 0x81, - 0xA7, 0x14, 0x17, 0xAF, 0x9A, 0x4A, 0x06, 0x6D, 0x0F, 0xFC, 0x5A, 0xD6, - 0x4B, 0xAB, 0x28, 0xB1, 0xFF, 0x60, 0x66, 0x1F, 0x44, 0x37, 0xD4, 0x9E, - 0x1E, 0x0D, 0x94, 0x12, 0xEB, 0x4B, 0xCA, 0xCF, 0x4C, 0xFD, 0x6A, 0x34, - 0x08, 0x84, 0x79, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x52, 0x6F, 0x6F, 0x74, 0x2D, 0x43, 0x41, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x58, 0x53, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x63, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x13, 0x7A, 0x08, 0x94, 0xAD, 0x50, 0x5B, 0xB6, - 0xC6, 0x7E, 0x2E, 0x5B, 0xDD, 0x6A, 0x3B, 0xEC, 0x43, 0xD9, 0x10, 0xC7, - 0x72, 0xE9, 0xCC, 0x29, 0x0D, 0xA5, 0x85, 0x88, 0xB7, 0x7D, 0xCC, 0x11, - 0x68, 0x0B, 0xB3, 0xE2, 0x9F, 0x4E, 0xAB, 0xBB, 0x26, 0xE9, 0x8C, 0x26, - 0x01, 0x98, 0x5C, 0x04, 0x1B, 0xB1, 0x43, 0x78, 0xE6, 0x89, 0x18, 0x1A, - 0xAD, 0x77, 0x05, 0x68, 0xE9, 0x28, 0xA2, 0xB9, 0x81, 0x67, 0xEE, 0x3E, - 0x10, 0xD0, 0x72, 0xBE, 0xEF, 0x1F, 0xA2, 0x2F, 0xA2, 0xAA, 0x3E, 0x13, - 0xF1, 0x1E, 0x18, 0x36, 0xA9, 0x2A, 0x42, 0x81, 0xEF, 0x70, 0xAA, 0xF4, - 0xE4, 0x62, 0x99, 0x82, 0x21, 0xC6, 0xFB, 0xB9, 0xBD, 0xD0, 0x17, 0xE6, - 0xAC, 0x59, 0x04, 0x94, 0xE9, 0xCE, 0xA9, 0x85, 0x9C, 0xEB, 0x2D, 0x2A, - 0x4C, 0x17, 0x66, 0xF2, 0xC3, 0x39, 0x12, 0xC5, 0x8F, 0x14, 0xA8, 0x03, - 0xE3, 0x6F, 0xCC, 0xDC, 0xCC, 0xDC, 0x13, 0xFD, 0x7A, 0xE7, 0x7C, 0x7A, - 0x78, 0xD9, 0x97, 0xE6, 0xAC, 0xC3, 0x55, 0x57, 0xE0, 0xD3, 0xE9, 0xEB, - 0x64, 0xB4, 0x3C, 0x92, 0xF4, 0xC5, 0x0D, 0x67, 0xA6, 0x02, 0xDE, 0xB3, - 0x91, 0xB0, 0x66, 0x61, 0xCD, 0x32, 0x88, 0x0B, 0xD6, 0x49, 0x12, 0xAF, - 0x1C, 0xBC, 0xB7, 0x16, 0x2A, 0x06, 0xF0, 0x25, 0x65, 0xD3, 0xB0, 0xEC, - 0xE4, 0xFC, 0xEC, 0xDD, 0xAE, 0x8A, 0x49, 0x34, 0xDB, 0x8E, 0xE6, 0x7F, - 0x30, 0x17, 0x98, 0x62, 0x21, 0x15, 0x5D, 0x13, 0x1C, 0x6C, 0x3F, 0x09, - 0xAB, 0x19, 0x45, 0xC2, 0x06, 0xAC, 0x70, 0xC9, 0x42, 0xB3, 0x6F, 0x49, - 0xA1, 0x18, 0x3B, 0xCD, 0x78, 0xB6, 0xE4, 0xB4, 0x7C, 0x6C, 0x5C, 0xAC, - 0x0F, 0x8D, 0x62, 0xF8, 0x97, 0xC6, 0x95, 0x3D, 0xD1, 0x2F, 0x28, 0xB7, - 0x0C, 0x5B, 0x7D, 0xF7, 0x51, 0x81, 0x9A, 0x98, 0x34, 0x65, 0x26, 0x25, - 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, - 0x70, 0x41, 0x38, 0xEF, 0xBB, 0xBD, 0xA1, 0x6A, 0x98, 0x7D, 0xD9, 0x01, - 0x32, 0x6D, 0x1C, 0x94, 0x59, 0x48, 0x4C, 0x88, 0xA2, 0x86, 0x1B, 0x91, - 0xA3, 0x12, 0x58, 0x7A, 0xE7, 0x0E, 0xF6, 0x23, 0x7E, 0xC5, 0x0E, 0x10, - 0x32, 0xDC, 0x39, 0xDD, 0xE8, 0x9A, 0x96, 0xA8, 0xE8, 0x59, 0xD7, 0x6A, - 0x98, 0xA6, 0xE7, 0xE3, 0x6A, 0x0C, 0xFE, 0x35, 0x2C, 0xA8, 0x93, 0x05, - 0x82, 0x34, 0xFF, 0x83, 0x3F, 0xCB, 0x3B, 0x03, 0x81, 0x1E, 0x9F, 0x0D, - 0xC0, 0xD9, 0xA5, 0x2F, 0x80, 0x45, 0xB4, 0xB2, 0xF9, 0x41, 0x1B, 0x67, - 0xA5, 0x1C, 0x44, 0xB5, 0xEF, 0x8C, 0xE7, 0x7B, 0xD6, 0xD5, 0x6B, 0xA7, - 0x57, 0x34, 0xA1, 0x85, 0x6D, 0xE6, 0xD4, 0xBE, 0xD6, 0xD3, 0xA2, 0x42, - 0xC7, 0xC8, 0x79, 0x1B, 0x34, 0x22, 0x37, 0x5E, 0x5C, 0x77, 0x9A, 0xBF, - 0x07, 0x2F, 0x76, 0x95, 0xEF, 0xA0, 0xF7, 0x5B, 0xCB, 0x83, 0x78, 0x9F, - 0xC3, 0x0E, 0x3F, 0xE4, 0xCC, 0x83, 0x92, 0x20, 0x78, 0x40, 0x63, 0x89, - 0x49, 0xC7, 0xF6, 0x88, 0x56, 0x5F, 0x64, 0x9B, 0x74, 0xD6, 0x3D, 0x8D, - 0x58, 0xFF, 0xAD, 0xDA, 0x57, 0x1E, 0x95, 0x54, 0x42, 0x6B, 0x13, 0x18, - 0xFC, 0x46, 0x89, 0x83, 0xD4, 0xC8, 0xA5, 0x62, 0x8B, 0x06, 0xB6, 0xFC, - 0x5D, 0x50, 0x7C, 0x13, 0xE7, 0xA1, 0x8A, 0xC1, 0x51, 0x1E, 0xB6, 0xD6, - 0x2E, 0xA5, 0x44, 0x8F, 0x83, 0x50, 0x14, 0x47, 0xA9, 0xAF, 0xB3, 0xEC, - 0xC2, 0x90, 0x3C, 0x9D, 0xD5, 0x2F, 0x92, 0x2A, 0xC9, 0xAC, 0xDB, 0xEF, - 0x58, 0xC6, 0x02, 0x18, 0x48, 0xD9, 0x6E, 0x20, 0x87, 0x32, 0xD3, 0xD1, - 0xD9, 0xD9, 0xEA, 0x44, 0x0D, 0x91, 0x62, 0x1C, 0x7A, 0x99, 0xDB, 0x88, - 0x43, 0xC5, 0x9C, 0x1F, 0x2E, 0x2C, 0x7D, 0x9B, 0x57, 0x7D, 0x51, 0x2C, - 0x16, 0x6D, 0x6F, 0x7E, 0x1A, 0xAD, 0x4A, 0x77, 0x4A, 0x37, 0x44, 0x7E, - 0x78, 0xFE, 0x20, 0x21, 0xE1, 0x4A, 0x95, 0xD1, 0x12, 0xA0, 0x68, 0xAD, - 0xA0, 0x19, 0xF4, 0x63, 0xC7, 0xA5, 0x56, 0x85, 0xAA, 0xBB, 0x68, 0x88, - 0xB9, 0x24, 0x64, 0x83, 0xD1, 0x8B, 0x9C, 0x80, 0x6F, 0x47, 0x49, 0x18, - 0x33, 0x17, 0x82, 0x34, 0x4A, 0x4B, 0x85, 0x31, 0x33, 0x4B, 0x26, 0x30, - 0x32, 0x63, 0xD9, 0xD2, 0xEB, 0x4F, 0x4B, 0xB9, 0x96, 0x02, 0xB3, 0x52, - 0xF6, 0xAE, 0x40, 0x46, 0xC6, 0x9A, 0x5E, 0x7E, 0x8E, 0x4A, 0x18, 0xEF, - 0x9B, 0xC0, 0xA2, 0xDE, 0xD6, 0x13, 0x10, 0x41, 0x70, 0x12, 0xFD, 0x82, - 0x4C, 0xC1, 0x16, 0xCF, 0xB7, 0xC4, 0xC1, 0xF7, 0xEC, 0x71, 0x77, 0xA1, - 0x74, 0x46, 0xCB, 0xDE, 0x96, 0xF3, 0xED, 0xD8, 0x8F, 0xCD, 0x05, 0x2F, - 0x0B, 0x88, 0x8A, 0x45, 0xFD, 0xAF, 0x2B, 0x63, 0x13, 0x54, 0xF4, 0x0D, - 0x16, 0xE5, 0xFA, 0x9C, 0x2C, 0x4E, 0xDA, 0x98, 0xE7, 0x98, 0xD1, 0x5E, - 0x60, 0x46, 0xDC, 0x53, 0x63, 0xF3, 0x09, 0x6B, 0x2C, 0x60, 0x7A, 0x9D, - 0x8D, 0xD5, 0x5B, 0x15, 0x02, 0xA6, 0xAC, 0x7D, 0x3C, 0xC8, 0xD8, 0xC5, - 0x75, 0x99, 0x8E, 0x7D, 0x79, 0x69, 0x10, 0xC8, 0x04, 0xC4, 0x95, 0x23, - 0x50, 0x57, 0xE9, 0x1E, 0xCD, 0x26, 0x37, 0xC9, 0xC1, 0x84, 0x51, 0x51, - 0xAC, 0x6B, 0x9A, 0x04, 0x90, 0xAE, 0x3E, 0xC6, 0xF4, 0x77, 0x40, 0xA0, - 0xDB, 0x0B, 0xA3, 0x6D, 0x07, 0x59, 0x56, 0xCE, 0xE7, 0x35, 0x4E, 0xA3, - 0xE9, 0xA4, 0xF2, 0x72, 0x0B, 0x26, 0x55, 0x0C, 0x7D, 0x39, 0x43, 0x24, - 0xBC, 0x0C, 0xB7, 0xE9, 0x31, 0x7D, 0x8A, 0x86, 0x61, 0xF4, 0x21, 0x91, - 0xFF, 0x10, 0xB0, 0x82, 0x56, 0xCE, 0x3F, 0xD2, 0x5B, 0x74, 0x5E, 0x51, - 0x94, 0x90, 0x6B, 0x4D, 0x61, 0xCB, 0x4C, 0x2E, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0x6F, 0x6F, 0x74, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01, 0x43, 0x41, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7B, 0xE8, 0xEF, 0x6C, - 0xB2, 0x79, 0xC9, 0xE2, 0xEE, 0xE1, 0x21, 0xC6, 0xEA, 0xF4, 0x4F, 0xF6, - 0x39, 0xF8, 0x8F, 0x07, 0x8B, 0x4B, 0x77, 0xED, 0x9F, 0x95, 0x60, 0xB0, - 0x35, 0x82, 0x81, 0xB5, 0x0E, 0x55, 0xAB, 0x72, 0x11, 0x15, 0xA1, 0x77, - 0x70, 0x3C, 0x7A, 0x30, 0xFE, 0x3A, 0xE9, 0xEF, 0x1C, 0x60, 0xBC, 0x1D, - 0x97, 0x46, 0x76, 0xB2, 0x3A, 0x68, 0xCC, 0x04, 0xB1, 0x98, 0x52, 0x5B, - 0xC9, 0x68, 0xF1, 0x1D, 0xE2, 0xDB, 0x50, 0xE4, 0xD9, 0xE7, 0xF0, 0x71, - 0xE5, 0x62, 0xDA, 0xE2, 0x09, 0x22, 0x33, 0xE9, 0xD3, 0x63, 0xF6, 0x1D, - 0xD7, 0xC1, 0x9F, 0xF3, 0xA4, 0xA9, 0x1E, 0x8F, 0x65, 0x53, 0xD4, 0x71, - 0xDD, 0x7B, 0x84, 0xB9, 0xF1, 0xB8, 0xCE, 0x73, 0x35, 0xF0, 0xF5, 0x54, - 0x05, 0x63, 0xA1, 0xEA, 0xB8, 0x39, 0x63, 0xE0, 0x9B, 0xE9, 0x01, 0x01, - 0x1F, 0x99, 0x54, 0x63, 0x61, 0x28, 0x70, 0x20, 0xE9, 0xCC, 0x0D, 0xAB, - 0x48, 0x7F, 0x14, 0x0D, 0x66, 0x26, 0xA1, 0x83, 0x6D, 0x27, 0x11, 0x1F, - 0x20, 0x68, 0xDE, 0x47, 0x72, 0x14, 0x91, 0x51, 0xCF, 0x69, 0xC6, 0x1B, - 0xA6, 0x0E, 0xF9, 0xD9, 0x49, 0xA0, 0xF7, 0x1F, 0x54, 0x99, 0xF2, 0xD3, - 0x9A, 0xD2, 0x8C, 0x70, 0x05, 0x34, 0x82, 0x93, 0xC4, 0x31, 0xFF, 0xBD, - 0x33, 0xF6, 0xBC, 0xA6, 0x0D, 0xC7, 0x19, 0x5E, 0xA2, 0xBC, 0xC5, 0x6D, - 0x20, 0x0B, 0xAF, 0x6D, 0x06, 0xD0, 0x9C, 0x41, 0xDB, 0x8D, 0xE9, 0xC7, - 0x20, 0x15, 0x4C, 0xA4, 0x83, 0x2B, 0x69, 0xC0, 0x8C, 0x69, 0xCD, 0x3B, - 0x07, 0x3A, 0x00, 0x63, 0x60, 0x2F, 0x46, 0x2D, 0x33, 0x80, 0x61, 0xA5, - 0xEA, 0x6C, 0x91, 0x5C, 0xD5, 0x62, 0x35, 0x79, 0xC3, 0xEB, 0x64, 0xCE, - 0x44, 0xEF, 0x58, 0x6D, 0x14, 0xBA, 0xAA, 0x88, 0x34, 0x01, 0x9B, 0x3E, - 0xEB, 0xEE, 0xD3, 0x79, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + 0x00, 0x01, 0x00, 0x04, 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, + 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, + 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, + 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, + 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, + 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, + 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, + 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, + 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, + 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, + 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, + 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, + 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, + 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, + 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, + 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, + 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, + 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, + 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, + 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, + 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, + 0xD1, 0x5E, 0xA5, 0xE0, 0xD1, 0x5E, 0xA5, 0xE0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0x6F, 0x6F, 0x74, + 0x2D, 0x43, 0x41, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x33, 0x2D, + 0x58, 0x53, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x63, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFE, 0xED, 0xFA, 0xCE, 0xFE, 0xED, 0xFA, 0xCE, 0xFE, 0xED, 0xFA, 0xCE, + 0xFE, 0xED, 0xFA, 0xCE, 0xFE, 0xED, 0xFA, 0xCE, 0xFE, 0xED, 0xFA, 0xCE, + 0xFE, 0xED, 0xFA, 0xCE, 0xFE, 0xED, 0xFA, 0xCE, 0xFE, 0xED, 0xFA, 0xCE, + 0xFE, 0xED, 0xFA, 0xCE, 0xFE, 0xED, 0xFA, 0xCE, 0xFE, 0xED, 0xFA, 0xCE, + 0xFE, 0xED, 0xFA, 0xCE, 0xFE, 0xED, 0xFA, 0xCE, 0xFE, 0xED, 0xFA, 0xCE, + 0x01, 0x00, 0x00, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, + 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, + 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x14, 0x00, 0x00, 0x00, 0xAC, + 0x00, 0x00, 0x00, 0x14, 0x00, 0x01, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x84, + 0x00, 0x00, 0x00, 0x84, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, + 0x91, 0x9E, 0xBE, 0x46, 0x4A, 0xD0, 0xF5, 0x52, 0xCD, 0x1B, 0x72, 0xE7, + 0x88, 0x49, 0x10, 0xCF, 0x55, 0xA9, 0xF0, 0x2E, 0x50, 0x78, 0x96, 0x41, + 0xD8, 0x96, 0x68, 0x3D, 0xC0, 0x05, 0xBD, 0x0A, 0xEA, 0x87, 0x07, 0x9D, + 0x8A, 0xC2, 0x84, 0xC6, 0x75, 0x06, 0x5F, 0x74, 0xC8, 0xBF, 0x37, 0xC8, + 0x80, 0x44, 0x40, 0x95, 0x02, 0xA0, 0x22, 0x98, 0x0B, 0xB8, 0xAD, 0x48, + 0x38, 0x3F, 0x6D, 0x28, 0xA7, 0x9D, 0xE3, 0x96, 0x26, 0xCC, 0xB2, 0xB2, + 0x2A, 0x0F, 0x19, 0xE4, 0x10, 0x32, 0xF0, 0x94, 0xB3, 0x9F, 0xF0, 0x13, + 0x31, 0x46, 0xDE, 0xC8, 0xF6, 0xC1, 0xA9, 0xD5, 0x5C, 0xD2, 0x8D, 0x9E, + 0x1C, 0x47, 0xB3, 0xD1, 0x1F, 0x4F, 0x54, 0x26, 0xC2, 0xC7, 0x80, 0x13, + 0x5A, 0x27, 0x75, 0xD3, 0xCA, 0x67, 0x9B, 0xC7, 0xE8, 0x34, 0xF0, 0xE0, + 0xFB, 0x58, 0xE6, 0x88, 0x60, 0xA7, 0x13, 0x30, 0xFC, 0x95, 0x79, 0x17, + 0x93, 0xC8, 0xFB, 0xA9, 0x35, 0xA7, 0xA6, 0x90, 0x8F, 0x22, 0x9D, 0xEE, + 0x2A, 0x0C, 0xA6, 0xB9, 0xB2, 0x3B, 0x12, 0xD4, 0x95, 0xA6, 0xFE, 0x19, + 0xD0, 0xD7, 0x26, 0x48, 0x21, 0x68, 0x78, 0x60, 0x5A, 0x66, 0x53, 0x8D, + 0xBF, 0x37, 0x68, 0x99, 0x90, 0x5D, 0x34, 0x45, 0xFC, 0x5C, 0x72, 0x7A, + 0x0E, 0x13, 0xE0, 0xE2, 0xC8, 0x97, 0x1C, 0x9C, 0xFA, 0x6C, 0x60, 0x67, + 0x88, 0x75, 0x73, 0x2A, 0x4E, 0x75, 0x52, 0x3D, 0x2F, 0x56, 0x2F, 0x12, + 0xAA, 0xBD, 0x15, 0x73, 0xBF, 0x06, 0xC9, 0x40, 0x54, 0xAE, 0xFA, 0x81, + 0xA7, 0x14, 0x17, 0xAF, 0x9A, 0x4A, 0x06, 0x6D, 0x0F, 0xFC, 0x5A, 0xD6, + 0x4B, 0xAB, 0x28, 0xB1, 0xFF, 0x60, 0x66, 0x1F, 0x44, 0x37, 0xD4, 0x9E, + 0x1E, 0x0D, 0x94, 0x12, 0xEB, 0x4B, 0xCA, 0xCF, 0x4C, 0xFD, 0x6A, 0x34, + 0x08, 0x84, 0x79, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x52, 0x6F, 0x6F, 0x74, 0x2D, 0x43, 0x41, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x58, 0x53, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x63, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x13, 0x7A, 0x08, 0x94, 0xAD, 0x50, 0x5B, 0xB6, + 0xC6, 0x7E, 0x2E, 0x5B, 0xDD, 0x6A, 0x3B, 0xEC, 0x43, 0xD9, 0x10, 0xC7, + 0x72, 0xE9, 0xCC, 0x29, 0x0D, 0xA5, 0x85, 0x88, 0xB7, 0x7D, 0xCC, 0x11, + 0x68, 0x0B, 0xB3, 0xE2, 0x9F, 0x4E, 0xAB, 0xBB, 0x26, 0xE9, 0x8C, 0x26, + 0x01, 0x98, 0x5C, 0x04, 0x1B, 0xB1, 0x43, 0x78, 0xE6, 0x89, 0x18, 0x1A, + 0xAD, 0x77, 0x05, 0x68, 0xE9, 0x28, 0xA2, 0xB9, 0x81, 0x67, 0xEE, 0x3E, + 0x10, 0xD0, 0x72, 0xBE, 0xEF, 0x1F, 0xA2, 0x2F, 0xA2, 0xAA, 0x3E, 0x13, + 0xF1, 0x1E, 0x18, 0x36, 0xA9, 0x2A, 0x42, 0x81, 0xEF, 0x70, 0xAA, 0xF4, + 0xE4, 0x62, 0x99, 0x82, 0x21, 0xC6, 0xFB, 0xB9, 0xBD, 0xD0, 0x17, 0xE6, + 0xAC, 0x59, 0x04, 0x94, 0xE9, 0xCE, 0xA9, 0x85, 0x9C, 0xEB, 0x2D, 0x2A, + 0x4C, 0x17, 0x66, 0xF2, 0xC3, 0x39, 0x12, 0xC5, 0x8F, 0x14, 0xA8, 0x03, + 0xE3, 0x6F, 0xCC, 0xDC, 0xCC, 0xDC, 0x13, 0xFD, 0x7A, 0xE7, 0x7C, 0x7A, + 0x78, 0xD9, 0x97, 0xE6, 0xAC, 0xC3, 0x55, 0x57, 0xE0, 0xD3, 0xE9, 0xEB, + 0x64, 0xB4, 0x3C, 0x92, 0xF4, 0xC5, 0x0D, 0x67, 0xA6, 0x02, 0xDE, 0xB3, + 0x91, 0xB0, 0x66, 0x61, 0xCD, 0x32, 0x88, 0x0B, 0xD6, 0x49, 0x12, 0xAF, + 0x1C, 0xBC, 0xB7, 0x16, 0x2A, 0x06, 0xF0, 0x25, 0x65, 0xD3, 0xB0, 0xEC, + 0xE4, 0xFC, 0xEC, 0xDD, 0xAE, 0x8A, 0x49, 0x34, 0xDB, 0x8E, 0xE6, 0x7F, + 0x30, 0x17, 0x98, 0x62, 0x21, 0x15, 0x5D, 0x13, 0x1C, 0x6C, 0x3F, 0x09, + 0xAB, 0x19, 0x45, 0xC2, 0x06, 0xAC, 0x70, 0xC9, 0x42, 0xB3, 0x6F, 0x49, + 0xA1, 0x18, 0x3B, 0xCD, 0x78, 0xB6, 0xE4, 0xB4, 0x7C, 0x6C, 0x5C, 0xAC, + 0x0F, 0x8D, 0x62, 0xF8, 0x97, 0xC6, 0x95, 0x3D, 0xD1, 0x2F, 0x28, 0xB7, + 0x0C, 0x5B, 0x7D, 0xF7, 0x51, 0x81, 0x9A, 0x98, 0x34, 0x65, 0x26, 0x25, + 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, + 0x70, 0x41, 0x38, 0xEF, 0xBB, 0xBD, 0xA1, 0x6A, 0x98, 0x7D, 0xD9, 0x01, + 0x32, 0x6D, 0x1C, 0x94, 0x59, 0x48, 0x4C, 0x88, 0xA2, 0x86, 0x1B, 0x91, + 0xA3, 0x12, 0x58, 0x7A, 0xE7, 0x0E, 0xF6, 0x23, 0x7E, 0xC5, 0x0E, 0x10, + 0x32, 0xDC, 0x39, 0xDD, 0xE8, 0x9A, 0x96, 0xA8, 0xE8, 0x59, 0xD7, 0x6A, + 0x98, 0xA6, 0xE7, 0xE3, 0x6A, 0x0C, 0xFE, 0x35, 0x2C, 0xA8, 0x93, 0x05, + 0x82, 0x34, 0xFF, 0x83, 0x3F, 0xCB, 0x3B, 0x03, 0x81, 0x1E, 0x9F, 0x0D, + 0xC0, 0xD9, 0xA5, 0x2F, 0x80, 0x45, 0xB4, 0xB2, 0xF9, 0x41, 0x1B, 0x67, + 0xA5, 0x1C, 0x44, 0xB5, 0xEF, 0x8C, 0xE7, 0x7B, 0xD6, 0xD5, 0x6B, 0xA7, + 0x57, 0x34, 0xA1, 0x85, 0x6D, 0xE6, 0xD4, 0xBE, 0xD6, 0xD3, 0xA2, 0x42, + 0xC7, 0xC8, 0x79, 0x1B, 0x34, 0x22, 0x37, 0x5E, 0x5C, 0x77, 0x9A, 0xBF, + 0x07, 0x2F, 0x76, 0x95, 0xEF, 0xA0, 0xF7, 0x5B, 0xCB, 0x83, 0x78, 0x9F, + 0xC3, 0x0E, 0x3F, 0xE4, 0xCC, 0x83, 0x92, 0x20, 0x78, 0x40, 0x63, 0x89, + 0x49, 0xC7, 0xF6, 0x88, 0x56, 0x5F, 0x64, 0x9B, 0x74, 0xD6, 0x3D, 0x8D, + 0x58, 0xFF, 0xAD, 0xDA, 0x57, 0x1E, 0x95, 0x54, 0x42, 0x6B, 0x13, 0x18, + 0xFC, 0x46, 0x89, 0x83, 0xD4, 0xC8, 0xA5, 0x62, 0x8B, 0x06, 0xB6, 0xFC, + 0x5D, 0x50, 0x7C, 0x13, 0xE7, 0xA1, 0x8A, 0xC1, 0x51, 0x1E, 0xB6, 0xD6, + 0x2E, 0xA5, 0x44, 0x8F, 0x83, 0x50, 0x14, 0x47, 0xA9, 0xAF, 0xB3, 0xEC, + 0xC2, 0x90, 0x3C, 0x9D, 0xD5, 0x2F, 0x92, 0x2A, 0xC9, 0xAC, 0xDB, 0xEF, + 0x58, 0xC6, 0x02, 0x18, 0x48, 0xD9, 0x6E, 0x20, 0x87, 0x32, 0xD3, 0xD1, + 0xD9, 0xD9, 0xEA, 0x44, 0x0D, 0x91, 0x62, 0x1C, 0x7A, 0x99, 0xDB, 0x88, + 0x43, 0xC5, 0x9C, 0x1F, 0x2E, 0x2C, 0x7D, 0x9B, 0x57, 0x7D, 0x51, 0x2C, + 0x16, 0x6D, 0x6F, 0x7E, 0x1A, 0xAD, 0x4A, 0x77, 0x4A, 0x37, 0x44, 0x7E, + 0x78, 0xFE, 0x20, 0x21, 0xE1, 0x4A, 0x95, 0xD1, 0x12, 0xA0, 0x68, 0xAD, + 0xA0, 0x19, 0xF4, 0x63, 0xC7, 0xA5, 0x56, 0x85, 0xAA, 0xBB, 0x68, 0x88, + 0xB9, 0x24, 0x64, 0x83, 0xD1, 0x8B, 0x9C, 0x80, 0x6F, 0x47, 0x49, 0x18, + 0x33, 0x17, 0x82, 0x34, 0x4A, 0x4B, 0x85, 0x31, 0x33, 0x4B, 0x26, 0x30, + 0x32, 0x63, 0xD9, 0xD2, 0xEB, 0x4F, 0x4B, 0xB9, 0x96, 0x02, 0xB3, 0x52, + 0xF6, 0xAE, 0x40, 0x46, 0xC6, 0x9A, 0x5E, 0x7E, 0x8E, 0x4A, 0x18, 0xEF, + 0x9B, 0xC0, 0xA2, 0xDE, 0xD6, 0x13, 0x10, 0x41, 0x70, 0x12, 0xFD, 0x82, + 0x4C, 0xC1, 0x16, 0xCF, 0xB7, 0xC4, 0xC1, 0xF7, 0xEC, 0x71, 0x77, 0xA1, + 0x74, 0x46, 0xCB, 0xDE, 0x96, 0xF3, 0xED, 0xD8, 0x8F, 0xCD, 0x05, 0x2F, + 0x0B, 0x88, 0x8A, 0x45, 0xFD, 0xAF, 0x2B, 0x63, 0x13, 0x54, 0xF4, 0x0D, + 0x16, 0xE5, 0xFA, 0x9C, 0x2C, 0x4E, 0xDA, 0x98, 0xE7, 0x98, 0xD1, 0x5E, + 0x60, 0x46, 0xDC, 0x53, 0x63, 0xF3, 0x09, 0x6B, 0x2C, 0x60, 0x7A, 0x9D, + 0x8D, 0xD5, 0x5B, 0x15, 0x02, 0xA6, 0xAC, 0x7D, 0x3C, 0xC8, 0xD8, 0xC5, + 0x75, 0x99, 0x8E, 0x7D, 0x79, 0x69, 0x10, 0xC8, 0x04, 0xC4, 0x95, 0x23, + 0x50, 0x57, 0xE9, 0x1E, 0xCD, 0x26, 0x37, 0xC9, 0xC1, 0x84, 0x51, 0x51, + 0xAC, 0x6B, 0x9A, 0x04, 0x90, 0xAE, 0x3E, 0xC6, 0xF4, 0x77, 0x40, 0xA0, + 0xDB, 0x0B, 0xA3, 0x6D, 0x07, 0x59, 0x56, 0xCE, 0xE7, 0x35, 0x4E, 0xA3, + 0xE9, 0xA4, 0xF2, 0x72, 0x0B, 0x26, 0x55, 0x0C, 0x7D, 0x39, 0x43, 0x24, + 0xBC, 0x0C, 0xB7, 0xE9, 0x31, 0x7D, 0x8A, 0x86, 0x61, 0xF4, 0x21, 0x91, + 0xFF, 0x10, 0xB0, 0x82, 0x56, 0xCE, 0x3F, 0xD2, 0x5B, 0x74, 0x5E, 0x51, + 0x94, 0x90, 0x6B, 0x4D, 0x61, 0xCB, 0x4C, 0x2E, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0x6F, 0x6F, 0x74, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x43, 0x41, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7B, 0xE8, 0xEF, 0x6C, + 0xB2, 0x79, 0xC9, 0xE2, 0xEE, 0xE1, 0x21, 0xC6, 0xEA, 0xF4, 0x4F, 0xF6, + 0x39, 0xF8, 0x8F, 0x07, 0x8B, 0x4B, 0x77, 0xED, 0x9F, 0x95, 0x60, 0xB0, + 0x35, 0x82, 0x81, 0xB5, 0x0E, 0x55, 0xAB, 0x72, 0x11, 0x15, 0xA1, 0x77, + 0x70, 0x3C, 0x7A, 0x30, 0xFE, 0x3A, 0xE9, 0xEF, 0x1C, 0x60, 0xBC, 0x1D, + 0x97, 0x46, 0x76, 0xB2, 0x3A, 0x68, 0xCC, 0x04, 0xB1, 0x98, 0x52, 0x5B, + 0xC9, 0x68, 0xF1, 0x1D, 0xE2, 0xDB, 0x50, 0xE4, 0xD9, 0xE7, 0xF0, 0x71, + 0xE5, 0x62, 0xDA, 0xE2, 0x09, 0x22, 0x33, 0xE9, 0xD3, 0x63, 0xF6, 0x1D, + 0xD7, 0xC1, 0x9F, 0xF3, 0xA4, 0xA9, 0x1E, 0x8F, 0x65, 0x53, 0xD4, 0x71, + 0xDD, 0x7B, 0x84, 0xB9, 0xF1, 0xB8, 0xCE, 0x73, 0x35, 0xF0, 0xF5, 0x54, + 0x05, 0x63, 0xA1, 0xEA, 0xB8, 0x39, 0x63, 0xE0, 0x9B, 0xE9, 0x01, 0x01, + 0x1F, 0x99, 0x54, 0x63, 0x61, 0x28, 0x70, 0x20, 0xE9, 0xCC, 0x0D, 0xAB, + 0x48, 0x7F, 0x14, 0x0D, 0x66, 0x26, 0xA1, 0x83, 0x6D, 0x27, 0x11, 0x1F, + 0x20, 0x68, 0xDE, 0x47, 0x72, 0x14, 0x91, 0x51, 0xCF, 0x69, 0xC6, 0x1B, + 0xA6, 0x0E, 0xF9, 0xD9, 0x49, 0xA0, 0xF7, 0x1F, 0x54, 0x99, 0xF2, 0xD3, + 0x9A, 0xD2, 0x8C, 0x70, 0x05, 0x34, 0x82, 0x93, 0xC4, 0x31, 0xFF, 0xBD, + 0x33, 0xF6, 0xBC, 0xA6, 0x0D, 0xC7, 0x19, 0x5E, 0xA2, 0xBC, 0xC5, 0x6D, + 0x20, 0x0B, 0xAF, 0x6D, 0x06, 0xD0, 0x9C, 0x41, 0xDB, 0x8D, 0xE9, 0xC7, + 0x20, 0x15, 0x4C, 0xA4, 0x83, 0x2B, 0x69, 0xC0, 0x8C, 0x69, 0xCD, 0x3B, + 0x07, 0x3A, 0x00, 0x63, 0x60, 0x2F, 0x46, 0x2D, 0x33, 0x80, 0x61, 0xA5, + 0xEA, 0x6C, 0x91, 0x5C, 0xD5, 0x62, 0x35, 0x79, 0xC3, 0xEB, 0x64, 0xCE, + 0x44, 0xEF, 0x58, 0x6D, 0x14, 0xBA, 0xAA, 0x88, 0x34, 0x01, 0x9B, 0x3E, + 0xEB, 0xEE, 0xD3, 0x79, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; diff --git a/source/data/builtin_rootca.bin b/source/data/builtin_rootca.bin new file mode 100644 index 0000000..9d2132e Binary files /dev/null and b/source/data/builtin_rootca.bin differ diff --git a/source/eshop b/source/eshop new file mode 160000 index 0000000..9d5ef08 --- /dev/null +++ b/source/eshop @@ -0,0 +1 @@ +Subproject commit 9d5ef08c9f4c67b60b11f5f73252345bf442b764 diff --git a/source/font.h b/source/font.h index 9026a54..4775f3c 100644 --- a/source/font.h +++ b/source/font.h @@ -8,137 +8,137 @@ Visit http://www.devkitpro.org #define _font_h_ //--------------------------------------------------------------------------------- static const unsigned char font[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e, - 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e, 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, - 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x3c, 0x3c, 0x18, 0xff, 0xe7, 0x18, 0x3c, 0x00, - 0x10, 0x38, 0x7c, 0xfe, 0xee, 0x10, 0x38, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, - 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, - 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78, - 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x08, 0x0c, 0x0a, 0x0a, 0x08, 0x78, 0xf0, 0x00, - 0x18, 0x14, 0x1a, 0x16, 0x72, 0xe2, 0x0e, 0x1c, 0x10, 0x54, 0x38, 0xee, 0x38, 0x54, 0x10, 0x00, - 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00, 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00, - 0x18, 0x3c, 0x5a, 0x18, 0x5a, 0x3c, 0x18, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00, - 0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x00, 0x1c, 0x22, 0x38, 0x44, 0x44, 0x38, 0x88, 0x70, - 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00, 0x18, 0x3c, 0x5a, 0x18, 0x5a, 0x3c, 0x18, 0x7e, - 0x18, 0x3c, 0x5a, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x5a, 0x3c, 0x18, 0x00, - 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, - 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x24, 0x42, 0xff, 0x42, 0x24, 0x00, 0x00, - 0x00, 0x10, 0x38, 0x7c, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x18, 0x00, 0x18, 0x00, - 0x6c, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, - 0x10, 0x7c, 0xd0, 0x7c, 0x16, 0xfc, 0x10, 0x00, 0x00, 0x66, 0xac, 0xd8, 0x36, 0x6a, 0xcc, 0x00, - 0x38, 0x4c, 0x38, 0x78, 0xce, 0xcc, 0x7a, 0x00, 0x30, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00, 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00, - 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x10, 0x20, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x00, - 0x7c, 0xce, 0xde, 0xf6, 0xe6, 0xe6, 0x7c, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x7e, 0x00, - 0x7c, 0xc6, 0x06, 0x1c, 0x70, 0xc6, 0xfe, 0x00, 0x7c, 0xc6, 0x06, 0x3c, 0x06, 0xc6, 0x7c, 0x00, - 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00, 0xfe, 0xc0, 0xfc, 0x06, 0x06, 0xc6, 0x7c, 0x00, - 0x7c, 0xc6, 0xc0, 0xfc, 0xc6, 0xc6, 0x7c, 0x00, 0xfe, 0xc6, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00, - 0x7c, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0x7c, 0x00, 0x7c, 0xc6, 0xc6, 0x7e, 0x06, 0xc6, 0x7c, 0x00, - 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x10, 0x20, - 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, - 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00, - 0x7c, 0x82, 0x9e, 0xa6, 0x9e, 0x80, 0x7c, 0x00, 0x7c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, - 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, - 0xfc, 0x66, 0x66, 0x66, 0x66, 0x66, 0xfc, 0x00, 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00, - 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00, 0x7c, 0xc6, 0xc6, 0xc0, 0xce, 0xc6, 0x7e, 0x00, - 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, - 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00, 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00, - 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x82, 0xc6, 0xee, 0xfe, 0xd6, 0xc6, 0xc6, 0x00, - 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, - 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 0x06, - 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xe6, 0x00, 0x7c, 0xc6, 0xc0, 0x7c, 0x06, 0xc6, 0x7c, 0x00, - 0x7e, 0x5a, 0x5a, 0x18, 0x18, 0x18, 0x3c, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, - 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x10, 0x00, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x82, 0x00, - 0xc6, 0x6c, 0x38, 0x38, 0x38, 0x6c, 0xc6, 0x00, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x3c, 0x00, - 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00, 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00, - 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00, - 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, - 0x30, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, - 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc6, 0x7c, 0x00, - 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x00, - 0x1c, 0x36, 0x30, 0x78, 0x30, 0x30, 0x78, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x78, - 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00, - 0x00, 0x0c, 0x00, 0x1c, 0x0c, 0x0c, 0xcc, 0x78, 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00, - 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0xcc, 0xfe, 0xd6, 0xd6, 0xd6, 0x00, - 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, - 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0, 0x00, 0x00, 0x7c, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e, - 0x00, 0x00, 0xde, 0x76, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x7c, 0xc0, 0x7c, 0x06, 0x7c, 0x00, - 0x10, 0x30, 0xfc, 0x30, 0x30, 0x34, 0x18, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, - 0x00, 0x00, 0xc6, 0xc6, 0x6c, 0x38, 0x10, 0x00, 0x00, 0x00, 0xc6, 0xd6, 0xd6, 0xfe, 0x6c, 0x00, - 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8, - 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00, 0x0e, 0x18, 0x18, 0x30, 0x18, 0x18, 0x0e, 0x00, - 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00, 0xe0, 0x30, 0x30, 0x18, 0x30, 0x30, 0xe0, 0x00, - 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00, - 0x7c, 0xc6, 0xc0, 0xc0, 0xc6, 0x7c, 0x18, 0x70, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, - 0x0e, 0x10, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x00, 0x7c, 0x82, 0x38, 0x0c, 0x7c, 0xcc, 0x76, 0x00, - 0xcc, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, 0xe0, 0x10, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, - 0x30, 0x30, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x7c, 0xc0, 0xc0, 0x7c, 0x18, 0x70, - 0x7c, 0x82, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x00, - 0xe0, 0x10, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x00, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00, - 0x7c, 0x82, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00, 0xe0, 0x10, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00, - 0xc6, 0x00, 0x7c, 0xc6, 0xfe, 0xc6, 0xc6, 0x00, 0x38, 0x38, 0x7c, 0xc6, 0xfe, 0xc6, 0xc6, 0x00, - 0x0e, 0x10, 0xfe, 0x60, 0x78, 0x60, 0xfe, 0x00, 0x00, 0x00, 0x7c, 0x12, 0x7e, 0xd0, 0x7e, 0x00, - 0x7e, 0xc8, 0xc8, 0xfe, 0xc8, 0xc8, 0xce, 0x00, 0x7c, 0x82, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, - 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0xe0, 0x10, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, - 0x7c, 0x82, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0xe0, 0x10, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, - 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, - 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x18, 0x7c, 0xd6, 0xd0, 0xd6, 0x7c, 0x18, 0x00, - 0x38, 0x6c, 0x60, 0xf0, 0x60, 0xf2, 0xdc, 0x00, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x7e, 0x18, 0x00, - 0xf8, 0xcc, 0xf8, 0xc4, 0xcc, 0xde, 0xcc, 0x06, 0x0e, 0x1b, 0x18, 0x3c, 0x18, 0x18, 0xd8, 0x70, - 0x0e, 0x10, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, 0x0e, 0x10, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00, - 0x0e, 0x10, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x0e, 0x10, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, - 0x66, 0x98, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x98, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0x00, - 0x38, 0x0c, 0x3c, 0x34, 0x00, 0x7e, 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, - 0x30, 0x00, 0x30, 0x60, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xc0, 0xc0, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xfc, 0x0c, 0x0c, 0x00, 0x00, 0xc0, 0xc8, 0xd0, 0xfe, 0x46, 0x8c, 0x1e, 0x00, - 0xc0, 0xc8, 0xd0, 0xec, 0x5c, 0xbe, 0x0c, 0x00, 0x18, 0x00, 0x18, 0x18, 0x3c, 0x3c, 0x18, 0x00, - 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 0x6c, 0xd8, 0x00, 0x00, - 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, - 0xdb, 0x77, 0xdb, 0xee, 0xdb, 0x77, 0xdb, 0xee, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, - 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, - 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36, - 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, - 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, - 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, - 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, - 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, - 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, - 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, - 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00, - 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, - 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, - 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, - 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x74, 0xcc, 0xc8, 0xdc, 0x76, 0x00, 0x78, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xdc, 0x40, - 0xfe, 0x62, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x02, 0x7e, 0xec, 0x6c, 0x6c, 0x48, 0x00, - 0xfe, 0x62, 0x30, 0x18, 0x30, 0x62, 0xfe, 0x00, 0x00, 0x00, 0x7e, 0xd0, 0xc8, 0xc8, 0x70, 0x00, - 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xf8, 0x80, 0x00, 0x00, 0x7e, 0xd8, 0x18, 0x18, 0x10, 0x00, - 0x38, 0x10, 0x7c, 0xd6, 0xd6, 0x7c, 0x10, 0x38, 0x7c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x7c, 0x00, - 0x7c, 0xc6, 0xc6, 0xc6, 0x6c, 0x28, 0xee, 0x00, 0x3c, 0x22, 0x18, 0x7c, 0xcc, 0xcc, 0x78, 0x00, - 0x00, 0x00, 0x66, 0x99, 0x99, 0x66, 0x00, 0x00, 0x00, 0x06, 0x7c, 0x9e, 0xf2, 0x7c, 0xc0, 0x00, - 0x00, 0x00, 0x7c, 0xc0, 0xf8, 0xc0, 0x7c, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, - 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x7e, 0x00, - 0x30, 0x18, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0x00, 0x18, 0x30, 0x60, 0x30, 0x18, 0x00, 0x7c, 0x00, - 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0x70, - 0x00, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00, - 0x38, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x3c, 0x00, - 0xd8, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x30, 0xc0, 0xf0, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e, + 0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e, 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, + 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x3c, 0x3c, 0x18, 0xff, 0xe7, 0x18, 0x3c, 0x00, + 0x10, 0x38, 0x7c, 0xfe, 0xee, 0x10, 0x38, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, + 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, + 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78, + 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x08, 0x0c, 0x0a, 0x0a, 0x08, 0x78, 0xf0, 0x00, + 0x18, 0x14, 0x1a, 0x16, 0x72, 0xe2, 0x0e, 0x1c, 0x10, 0x54, 0x38, 0xee, 0x38, 0x54, 0x10, 0x00, + 0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00, 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00, + 0x18, 0x3c, 0x5a, 0x18, 0x5a, 0x3c, 0x18, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00, + 0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x00, 0x1c, 0x22, 0x38, 0x44, 0x44, 0x38, 0x88, 0x70, + 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00, 0x18, 0x3c, 0x5a, 0x18, 0x5a, 0x3c, 0x18, 0x7e, + 0x18, 0x3c, 0x5a, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x5a, 0x3c, 0x18, 0x00, + 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, + 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x24, 0x42, 0xff, 0x42, 0x24, 0x00, 0x00, + 0x00, 0x10, 0x38, 0x7c, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x18, 0x00, 0x18, 0x00, + 0x6c, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, + 0x10, 0x7c, 0xd0, 0x7c, 0x16, 0xfc, 0x10, 0x00, 0x00, 0x66, 0xac, 0xd8, 0x36, 0x6a, 0xcc, 0x00, + 0x38, 0x4c, 0x38, 0x78, 0xce, 0xcc, 0x7a, 0x00, 0x30, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00, 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00, + 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x10, 0x20, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x00, + 0x7c, 0xce, 0xde, 0xf6, 0xe6, 0xe6, 0x7c, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x7e, 0x00, + 0x7c, 0xc6, 0x06, 0x1c, 0x70, 0xc6, 0xfe, 0x00, 0x7c, 0xc6, 0x06, 0x3c, 0x06, 0xc6, 0x7c, 0x00, + 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00, 0xfe, 0xc0, 0xfc, 0x06, 0x06, 0xc6, 0x7c, 0x00, + 0x7c, 0xc6, 0xc0, 0xfc, 0xc6, 0xc6, 0x7c, 0x00, 0xfe, 0xc6, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00, + 0x7c, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0x7c, 0x00, 0x7c, 0xc6, 0xc6, 0x7e, 0x06, 0xc6, 0x7c, 0x00, + 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x10, 0x20, + 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, + 0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00, + 0x7c, 0x82, 0x9e, 0xa6, 0x9e, 0x80, 0x7c, 0x00, 0x7c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, + 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, + 0xfc, 0x66, 0x66, 0x66, 0x66, 0x66, 0xfc, 0x00, 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00, + 0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00, 0x7c, 0xc6, 0xc6, 0xc0, 0xce, 0xc6, 0x7e, 0x00, + 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, + 0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00, 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00, + 0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x82, 0xc6, 0xee, 0xfe, 0xd6, 0xc6, 0xc6, 0x00, + 0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, + 0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 0x06, + 0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xe6, 0x00, 0x7c, 0xc6, 0xc0, 0x7c, 0x06, 0xc6, 0x7c, 0x00, + 0x7e, 0x5a, 0x5a, 0x18, 0x18, 0x18, 0x3c, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, + 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x10, 0x00, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x82, 0x00, + 0xc6, 0x6c, 0x38, 0x38, 0x38, 0x6c, 0xc6, 0x00, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x3c, 0x00, + 0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00, 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00, + 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00, + 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x30, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, + 0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc6, 0x7c, 0x00, + 0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x00, + 0x1c, 0x36, 0x30, 0x78, 0x30, 0x30, 0x78, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x78, + 0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00, + 0x00, 0x0c, 0x00, 0x1c, 0x0c, 0x0c, 0xcc, 0x78, 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00, + 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0xcc, 0xfe, 0xd6, 0xd6, 0xd6, 0x00, + 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, + 0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0, 0x00, 0x00, 0x7c, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e, + 0x00, 0x00, 0xde, 0x76, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x7c, 0xc0, 0x7c, 0x06, 0x7c, 0x00, + 0x10, 0x30, 0xfc, 0x30, 0x30, 0x34, 0x18, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, + 0x00, 0x00, 0xc6, 0xc6, 0x6c, 0x38, 0x10, 0x00, 0x00, 0x00, 0xc6, 0xd6, 0xd6, 0xfe, 0x6c, 0x00, + 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8, + 0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00, 0x0e, 0x18, 0x18, 0x30, 0x18, 0x18, 0x0e, 0x00, + 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00, 0xe0, 0x30, 0x30, 0x18, 0x30, 0x30, 0xe0, 0x00, + 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00, + 0x7c, 0xc6, 0xc0, 0xc0, 0xc6, 0x7c, 0x18, 0x70, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, + 0x0e, 0x10, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x00, 0x7c, 0x82, 0x38, 0x0c, 0x7c, 0xcc, 0x76, 0x00, + 0xcc, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, 0xe0, 0x10, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, + 0x30, 0x30, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x7c, 0xc0, 0xc0, 0x7c, 0x18, 0x70, + 0x7c, 0x82, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x00, + 0xe0, 0x10, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x00, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00, + 0x7c, 0x82, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00, 0xe0, 0x10, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00, + 0xc6, 0x00, 0x7c, 0xc6, 0xfe, 0xc6, 0xc6, 0x00, 0x38, 0x38, 0x7c, 0xc6, 0xfe, 0xc6, 0xc6, 0x00, + 0x0e, 0x10, 0xfe, 0x60, 0x78, 0x60, 0xfe, 0x00, 0x00, 0x00, 0x7c, 0x12, 0x7e, 0xd0, 0x7e, 0x00, + 0x7e, 0xc8, 0xc8, 0xfe, 0xc8, 0xc8, 0xce, 0x00, 0x7c, 0x82, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, + 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0xe0, 0x10, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, + 0x7c, 0x82, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0xe0, 0x10, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, + 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, + 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x18, 0x7c, 0xd6, 0xd0, 0xd6, 0x7c, 0x18, 0x00, + 0x38, 0x6c, 0x60, 0xf0, 0x60, 0xf2, 0xdc, 0x00, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x7e, 0x18, 0x00, + 0xf8, 0xcc, 0xf8, 0xc4, 0xcc, 0xde, 0xcc, 0x06, 0x0e, 0x1b, 0x18, 0x3c, 0x18, 0x18, 0xd8, 0x70, + 0x0e, 0x10, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, 0x0e, 0x10, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00, + 0x0e, 0x10, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x0e, 0x10, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, + 0x66, 0x98, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x98, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0x00, + 0x38, 0x0c, 0x3c, 0x34, 0x00, 0x7e, 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, + 0x30, 0x00, 0x30, 0x60, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xc0, 0xc0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfc, 0x0c, 0x0c, 0x00, 0x00, 0xc0, 0xc8, 0xd0, 0xfe, 0x46, 0x8c, 0x1e, 0x00, + 0xc0, 0xc8, 0xd0, 0xec, 0x5c, 0xbe, 0x0c, 0x00, 0x18, 0x00, 0x18, 0x18, 0x3c, 0x3c, 0x18, 0x00, + 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 0x6c, 0xd8, 0x00, 0x00, + 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, + 0xdb, 0x77, 0xdb, 0xee, 0xdb, 0x77, 0xdb, 0xee, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, + 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, + 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36, + 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, + 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, + 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, + 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, + 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00, + 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, + 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x74, 0xcc, 0xc8, 0xdc, 0x76, 0x00, 0x78, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xdc, 0x40, + 0xfe, 0x62, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x02, 0x7e, 0xec, 0x6c, 0x6c, 0x48, 0x00, + 0xfe, 0x62, 0x30, 0x18, 0x30, 0x62, 0xfe, 0x00, 0x00, 0x00, 0x7e, 0xd0, 0xc8, 0xc8, 0x70, 0x00, + 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xf8, 0x80, 0x00, 0x00, 0x7e, 0xd8, 0x18, 0x18, 0x10, 0x00, + 0x38, 0x10, 0x7c, 0xd6, 0xd6, 0x7c, 0x10, 0x38, 0x7c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x7c, 0x00, + 0x7c, 0xc6, 0xc6, 0xc6, 0x6c, 0x28, 0xee, 0x00, 0x3c, 0x22, 0x18, 0x7c, 0xcc, 0xcc, 0x78, 0x00, + 0x00, 0x00, 0x66, 0x99, 0x99, 0x66, 0x00, 0x00, 0x00, 0x06, 0x7c, 0x9e, 0xf2, 0x7c, 0xc0, 0x00, + 0x00, 0x00, 0x7c, 0xc0, 0xf8, 0xc0, 0x7c, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, + 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x7e, 0x00, + 0x30, 0x18, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0x00, 0x18, 0x30, 0x60, 0x30, 0x18, 0x00, 0x7c, 0x00, + 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0x70, + 0x00, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00, + 0x38, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x3c, 0x00, + 0xd8, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x30, 0xc0, 0xf0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; const int font_size = sizeof(font); //--------------------------------------------------------------------------------- #endif //_font_h_ -//--------------------------------------------------------------------------------- \ No newline at end of file +//--------------------------------------------------------------------------------- diff --git a/source/json/json-forwards.h b/source/json/json-forwards.h new file mode 100644 index 0000000..cff5fa9 --- /dev/null +++ b/source/json/json-forwards.h @@ -0,0 +1,319 @@ +/// Json-cpp amalgated forward header (http://jsoncpp.sourceforge.net/). +/// It is intended to be used with #include "json/json-forwards.h" +/// This header provides forward declaration for all JsonCpp types. + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: LICENSE +// ////////////////////////////////////////////////////////////////////// + +/* +The JsonCpp library's source code, including accompanying documentation, +tests and demonstration applications, are licensed under the following +conditions... + +The author (Baptiste Lepilleur) explicitly disclaims copyright in all +jurisdictions which recognize such a disclaimer. In such jurisdictions, +this software is released into the Public Domain. + +In jurisdictions which do not recognize Public Domain property (e.g. Germany as of +2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is +released under the terms of the MIT License (see below). + +In jurisdictions which recognize Public Domain property, the user of this +software may choose to accept it either as 1) Public Domain, 2) under the +conditions of the MIT License (see below), or 3) under the terms of dual +Public Domain/MIT License conditions described here, as they choose. + +The MIT License is about as close to Public Domain as a license can get, and is +described in clear, concise terms at: + + http://en.wikipedia.org/wiki/MIT_License + +The full text of the MIT License follows: + +======================================================================== +Copyright (c) 2007-2010 Baptiste Lepilleur + +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. +======================================================================== +(END LICENSE TEXT) + +The MIT license is compatible with both the GPL and commercial +software, affording one all of the rights of Public Domain with the +minor nuisance of being required to keep the above copyright notice +and license text in the source code. Note also that by accepting the +Public Domain "license" you can re-license your copy using whatever +license you like. + +*/ + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: LICENSE +// ////////////////////////////////////////////////////////////////////// + + + + + +#ifndef JSON_FORWARD_AMALGATED_H_INCLUDED +# define JSON_FORWARD_AMALGATED_H_INCLUDED +/// If defined, indicates that the source file is amalgated +/// to prevent private header inclusion. +#define JSON_IS_AMALGAMATION + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/config.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_CONFIG_H_INCLUDED +#define JSON_CONFIG_H_INCLUDED +#include +#include //typdef String + +/// If defined, indicates that json library is embedded in CppTL library. +//# define JSON_IN_CPPTL 1 + +/// If defined, indicates that json may leverage CppTL library +//# define JSON_USE_CPPTL 1 +/// If defined, indicates that cpptl vector based map should be used instead of +/// std::map +/// as Value container. +//# define JSON_USE_CPPTL_SMALLMAP 1 + +// If non-zero, the library uses exceptions to report bad input instead of C +// assertion macros. The default is to use exceptions. +#ifndef JSON_USE_EXCEPTION +#define JSON_USE_EXCEPTION 1 +#endif + +/// If defined, indicates that the source file is amalgated +/// to prevent private header inclusion. +/// Remarks: it is automatically defined in the generated amalgated header. +// #define JSON_IS_AMALGAMATION + +#ifdef JSON_IN_CPPTL +#include +#ifndef JSON_USE_CPPTL +#define JSON_USE_CPPTL 1 +#endif +#endif + +#ifdef JSON_IN_CPPTL +#define JSON_API CPPTL_API +#elif defined(JSON_DLL_BUILD) +#if defined(_MSC_VER) || defined(__MINGW32__) +#define JSON_API __declspec(dllexport) +#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING +#endif // if defined(_MSC_VER) +#elif defined(JSON_DLL) +#if defined(_MSC_VER) || defined(__MINGW32__) +#define JSON_API __declspec(dllimport) +#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING +#endif // if defined(_MSC_VER) +#endif // ifdef JSON_IN_CPPTL +#if !defined(JSON_API) +#define JSON_API +#endif + +// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for +// integer +// Storages, and 64 bits integer support is disabled. +// #define JSON_NO_INT64 1 + +#if defined(_MSC_VER) // MSVC +# if _MSC_VER <= 1200 // MSVC 6 + // Microsoft Visual Studio 6 only support conversion from __int64 to double + // (no conversion from unsigned __int64). +# define JSON_USE_INT64_DOUBLE_CONVERSION 1 + // Disable warning 4786 for VS6 caused by STL (identifier was truncated to '255' + // characters in the debug information) + // All projects I've ever seen with VS6 were using this globally (not bothering + // with pragma push/pop). +# pragma warning(disable : 4786) +# endif // MSVC 6 + +# if _MSC_VER >= 1500 // MSVC 2008 + /// Indicates that the following function is deprecated. +# define JSONCPP_DEPRECATED(message) __declspec(deprecated(message)) +# endif + +#endif // defined(_MSC_VER) + +#if defined(_MSC_VER) && _MSC_VER <= 1600 // MSVC <= 2010 +# define JSONCPP_OVERRIDE +#else +# define JSONCPP_OVERRIDE override +#endif // MSVC <= 2010 + + +#ifndef JSON_HAS_RVALUE_REFERENCES + +#if defined(_MSC_VER) && _MSC_VER >= 1600 // MSVC >= 2010 +#define JSON_HAS_RVALUE_REFERENCES 1 +#endif // MSVC >= 2010 + +#ifdef __clang__ +#if __has_feature(cxx_rvalue_references) +#define JSON_HAS_RVALUE_REFERENCES 1 +#endif // has_feature + +#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc) +#if defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103L) +#define JSON_HAS_RVALUE_REFERENCES 1 +#endif // GXX_EXPERIMENTAL + +#endif // __clang__ || __GNUC__ + +#endif // not defined JSON_HAS_RVALUE_REFERENCES + +#ifndef JSON_HAS_RVALUE_REFERENCES +#define JSON_HAS_RVALUE_REFERENCES 0 +#endif + +#ifdef __clang__ +#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc) +# if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) +# define JSONCPP_DEPRECATED(message) __attribute__ ((deprecated(message))) +# elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) +# define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__)) +# endif // GNUC version +#endif // __clang__ || __GNUC__ + +#if !defined(JSONCPP_DEPRECATED) +#define JSONCPP_DEPRECATED(message) +#endif // if !defined(JSONCPP_DEPRECATED) + +#if __GNUC__ >= 6 +# define JSON_USE_INT64_DOUBLE_CONVERSION 1 +#endif + +#if !defined(JSON_IS_AMALGAMATION) + +# include "version.h" + +# if JSONCPP_USING_SECURE_MEMORY +# include "allocator.h" //typedef Allocator +# endif + +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json { +typedef int Int; +typedef unsigned int UInt; +#if defined(JSON_NO_INT64) +typedef int LargestInt; +typedef unsigned int LargestUInt; +#undef JSON_HAS_INT64 +#else // if defined(JSON_NO_INT64) +// For Microsoft Visual use specific types as long long is not supported +#if defined(_MSC_VER) // Microsoft Visual Studio +typedef __int64 Int64; +typedef unsigned __int64 UInt64; +#else // if defined(_MSC_VER) // Other platforms, use long long +typedef long long int Int64; +typedef unsigned long long int UInt64; +#endif // if defined(_MSC_VER) +typedef Int64 LargestInt; +typedef UInt64 LargestUInt; +#define JSON_HAS_INT64 +#endif // if defined(JSON_NO_INT64) +#if JSONCPP_USING_SECURE_MEMORY +#define JSONCPP_STRING std::basic_string, Json::SecureAllocator > +#define JSONCPP_OSTRINGSTREAM std::basic_ostringstream, Json::SecureAllocator > +#define JSONCPP_OSTREAM std::basic_ostream> +#define JSONCPP_ISTRINGSTREAM std::basic_istringstream, Json::SecureAllocator > +#define JSONCPP_ISTREAM std::istream +#else +#define JSONCPP_STRING std::string +#define JSONCPP_OSTRINGSTREAM std::ostringstream +#define JSONCPP_OSTREAM std::ostream +#define JSONCPP_ISTRINGSTREAM std::istringstream +#define JSONCPP_ISTREAM std::istream +#endif // if JSONCPP_USING_SECURE_MEMORY +} // end namespace Json + +#endif // JSON_CONFIG_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/config.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/forwards.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_FORWARDS_H_INCLUDED +#define JSON_FORWARDS_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "config.h" +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json { + +// writer.h +class FastWriter; +class StyledWriter; + +// reader.h +class Reader; + +// features.h +class Features; + +// value.h +typedef unsigned int ArrayIndex; +class StaticString; +class Path; +class PathArgument; +class Value; +class ValueIteratorBase; +class ValueIterator; +class ValueConstIterator; + +} // namespace Json + +#endif // JSON_FORWARDS_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/forwards.h +// ////////////////////////////////////////////////////////////////////// + + + + + +#endif //ifndef JSON_FORWARD_AMALGATED_H_INCLUDED diff --git a/source/json/json.h b/source/json/json.h new file mode 100644 index 0000000..14599a0 --- /dev/null +++ b/source/json/json.h @@ -0,0 +1,2133 @@ +/// Json-cpp amalgated header (http://jsoncpp.sourceforge.net/). +/// It is intended to be used with #include "json/json.h" + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: LICENSE +// ////////////////////////////////////////////////////////////////////// + +/* +The JsonCpp library's source code, including accompanying documentation, +tests and demonstration applications, are licensed under the following +conditions... + +The author (Baptiste Lepilleur) explicitly disclaims copyright in all +jurisdictions which recognize such a disclaimer. In such jurisdictions, +this software is released into the Public Domain. + +In jurisdictions which do not recognize Public Domain property (e.g. Germany as of +2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is +released under the terms of the MIT License (see below). + +In jurisdictions which recognize Public Domain property, the user of this +software may choose to accept it either as 1) Public Domain, 2) under the +conditions of the MIT License (see below), or 3) under the terms of dual +Public Domain/MIT License conditions described here, as they choose. + +The MIT License is about as close to Public Domain as a license can get, and is +described in clear, concise terms at: + + http://en.wikipedia.org/wiki/MIT_License + +The full text of the MIT License follows: + +======================================================================== +Copyright (c) 2007-2010 Baptiste Lepilleur + +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. +======================================================================== +(END LICENSE TEXT) + +The MIT license is compatible with both the GPL and commercial +software, affording one all of the rights of Public Domain with the +minor nuisance of being required to keep the above copyright notice +and license text in the source code. Note also that by accepting the +Public Domain "license" you can re-license your copy using whatever +license you like. + +*/ + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: LICENSE +// ////////////////////////////////////////////////////////////////////// + + + + + +#ifndef JSON_AMALGATED_H_INCLUDED +# define JSON_AMALGATED_H_INCLUDED +/// If defined, indicates that the source file is amalgated +/// to prevent private header inclusion. +#define JSON_IS_AMALGAMATION + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/version.h +// ////////////////////////////////////////////////////////////////////// + +// DO NOT EDIT. This file (and "version") is generated by CMake. +// Run CMake configure step to update it. +#ifndef JSON_VERSION_H_INCLUDED +# define JSON_VERSION_H_INCLUDED + +# define JSONCPP_VERSION_STRING "1.7.2" +# define JSONCPP_VERSION_MAJOR 1 +# define JSONCPP_VERSION_MINOR 7 +# define JSONCPP_VERSION_PATCH 2 +# define JSONCPP_VERSION_QUALIFIER +# define JSONCPP_VERSION_HEXA ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | (JSONCPP_VERSION_PATCH << 8)) + +#ifdef JSONCPP_USING_SECURE_MEMORY +#undef JSONCPP_USING_SECURE_MEMORY +#endif +#define JSONCPP_USING_SECURE_MEMORY 0 +// If non-zero, the library zeroes any memory that it has allocated before +// it frees its memory. + +#endif // JSON_VERSION_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/version.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/config.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_CONFIG_H_INCLUDED +#define JSON_CONFIG_H_INCLUDED +#include +#include //typdef String + +/// If defined, indicates that json library is embedded in CppTL library. +//# define JSON_IN_CPPTL 1 + +/// If defined, indicates that json may leverage CppTL library +//# define JSON_USE_CPPTL 1 +/// If defined, indicates that cpptl vector based map should be used instead of +/// std::map +/// as Value container. +//# define JSON_USE_CPPTL_SMALLMAP 1 + +// If non-zero, the library uses exceptions to report bad input instead of C +// assertion macros. The default is to use exceptions. +#ifndef JSON_USE_EXCEPTION +#define JSON_USE_EXCEPTION 1 +#endif + +/// If defined, indicates that the source file is amalgated +/// to prevent private header inclusion. +/// Remarks: it is automatically defined in the generated amalgated header. +// #define JSON_IS_AMALGAMATION + +#ifdef JSON_IN_CPPTL +#include +#ifndef JSON_USE_CPPTL +#define JSON_USE_CPPTL 1 +#endif +#endif + +#ifdef JSON_IN_CPPTL +#define JSON_API CPPTL_API +#elif defined(JSON_DLL_BUILD) +#if defined(_MSC_VER) || defined(__MINGW32__) +#define JSON_API __declspec(dllexport) +#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING +#endif // if defined(_MSC_VER) +#elif defined(JSON_DLL) +#if defined(_MSC_VER) || defined(__MINGW32__) +#define JSON_API __declspec(dllimport) +#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING +#endif // if defined(_MSC_VER) +#endif // ifdef JSON_IN_CPPTL +#if !defined(JSON_API) +#define JSON_API +#endif + +// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for +// integer +// Storages, and 64 bits integer support is disabled. +// #define JSON_NO_INT64 1 + +#if defined(_MSC_VER) // MSVC +# if _MSC_VER <= 1200 // MSVC 6 + // Microsoft Visual Studio 6 only support conversion from __int64 to double + // (no conversion from unsigned __int64). +# define JSON_USE_INT64_DOUBLE_CONVERSION 1 + // Disable warning 4786 for VS6 caused by STL (identifier was truncated to '255' + // characters in the debug information) + // All projects I've ever seen with VS6 were using this globally (not bothering + // with pragma push/pop). +# pragma warning(disable : 4786) +# endif // MSVC 6 + +# if _MSC_VER >= 1500 // MSVC 2008 + /// Indicates that the following function is deprecated. +# define JSONCPP_DEPRECATED(message) __declspec(deprecated(message)) +# endif + +#endif // defined(_MSC_VER) + +#if defined(_MSC_VER) && _MSC_VER <= 1600 // MSVC <= 2010 +# define JSONCPP_OVERRIDE +#else +# define JSONCPP_OVERRIDE override +#endif // MSVC <= 2010 + + +#ifndef JSON_HAS_RVALUE_REFERENCES + +#if defined(_MSC_VER) && _MSC_VER >= 1600 // MSVC >= 2010 +#define JSON_HAS_RVALUE_REFERENCES 1 +#endif // MSVC >= 2010 + +#ifdef __clang__ +#if __has_feature(cxx_rvalue_references) +#define JSON_HAS_RVALUE_REFERENCES 1 +#endif // has_feature + +#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc) +#if defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103L) +#define JSON_HAS_RVALUE_REFERENCES 1 +#endif // GXX_EXPERIMENTAL + +#endif // __clang__ || __GNUC__ + +#endif // not defined JSON_HAS_RVALUE_REFERENCES + +#ifndef JSON_HAS_RVALUE_REFERENCES +#define JSON_HAS_RVALUE_REFERENCES 0 +#endif + +#ifdef __clang__ +#elif defined __GNUC__ // not clang (gcc comes later since clang emulates gcc) +# if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) +# define JSONCPP_DEPRECATED(message) __attribute__ ((deprecated(message))) +# elif (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) +# define JSONCPP_DEPRECATED(message) __attribute__((__deprecated__)) +# endif // GNUC version +#endif // __clang__ || __GNUC__ + +#if !defined(JSONCPP_DEPRECATED) +#define JSONCPP_DEPRECATED(message) +#endif // if !defined(JSONCPP_DEPRECATED) + +#if __GNUC__ >= 6 +# define JSON_USE_INT64_DOUBLE_CONVERSION 1 +#endif + +#if !defined(JSON_IS_AMALGAMATION) + +# include "version.h" + +# if JSONCPP_USING_SECURE_MEMORY +# include "allocator.h" //typedef Allocator +# endif + +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json { +typedef int Int; +typedef unsigned int UInt; +#if defined(JSON_NO_INT64) +typedef int LargestInt; +typedef unsigned int LargestUInt; +#undef JSON_HAS_INT64 +#else // if defined(JSON_NO_INT64) +// For Microsoft Visual use specific types as long long is not supported +#if defined(_MSC_VER) // Microsoft Visual Studio +typedef __int64 Int64; +typedef unsigned __int64 UInt64; +#else // if defined(_MSC_VER) // Other platforms, use long long +typedef long long int Int64; +typedef unsigned long long int UInt64; +#endif // if defined(_MSC_VER) +typedef Int64 LargestInt; +typedef UInt64 LargestUInt; +#define JSON_HAS_INT64 +#endif // if defined(JSON_NO_INT64) +#if JSONCPP_USING_SECURE_MEMORY +#define JSONCPP_STRING std::basic_string, Json::SecureAllocator > +#define JSONCPP_OSTRINGSTREAM std::basic_ostringstream, Json::SecureAllocator > +#define JSONCPP_OSTREAM std::basic_ostream> +#define JSONCPP_ISTRINGSTREAM std::basic_istringstream, Json::SecureAllocator > +#define JSONCPP_ISTREAM std::istream +#else +#define JSONCPP_STRING std::string +#define JSONCPP_OSTRINGSTREAM std::ostringstream +#define JSONCPP_OSTREAM std::ostream +#define JSONCPP_ISTRINGSTREAM std::istringstream +#define JSONCPP_ISTREAM std::istream +#endif // if JSONCPP_USING_SECURE_MEMORY +} // end namespace Json + +#endif // JSON_CONFIG_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/config.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/forwards.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_FORWARDS_H_INCLUDED +#define JSON_FORWARDS_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "config.h" +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json { + +// writer.h +class FastWriter; +class StyledWriter; + +// reader.h +class Reader; + +// features.h +class Features; + +// value.h +typedef unsigned int ArrayIndex; +class StaticString; +class Path; +class PathArgument; +class Value; +class ValueIteratorBase; +class ValueIterator; +class ValueConstIterator; + +} // namespace Json + +#endif // JSON_FORWARDS_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/forwards.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/features.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef CPPTL_JSON_FEATURES_H_INCLUDED +#define CPPTL_JSON_FEATURES_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "forwards.h" +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json { + +/** \brief Configuration passed to reader and writer. + * This configuration object can be used to force the Reader or Writer + * to behave in a standard conforming way. + */ +class JSON_API Features { +public: + /** \brief A configuration that allows all features and assumes all strings + * are UTF-8. + * - C & C++ comments are allowed + * - Root object can be any JSON value + * - Assumes Value strings are encoded in UTF-8 + */ + static Features all(); + + /** \brief A configuration that is strictly compatible with the JSON + * specification. + * - Comments are forbidden. + * - Root object must be either an array or an object value. + * - Assumes Value strings are encoded in UTF-8 + */ + static Features strictMode(); + + /** \brief Initialize the configuration like JsonConfig::allFeatures; + */ + Features(); + + /// \c true if comments are allowed. Default: \c true. + bool allowComments_; + + /// \c true if root must be either an array or an object value. Default: \c + /// false. + bool strictRoot_; + + /// \c true if dropped null placeholders are allowed. Default: \c false. + bool allowDroppedNullPlaceholders_; + + /// \c true if numeric object key are allowed. Default: \c false. + bool allowNumericKeys_; +}; + +} // namespace Json + +#endif // CPPTL_JSON_FEATURES_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/features.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/value.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef CPPTL_JSON_H_INCLUDED +#define CPPTL_JSON_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "forwards.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include + +#ifndef JSON_USE_CPPTL_SMALLMAP +#include +#else +#include +#endif +#ifdef JSON_USE_CPPTL +#include +#endif + +//Conditional NORETURN attribute on the throw functions would: +// a) suppress false positives from static code analysis +// b) possibly improve optimization opportunities. +#if !defined(JSONCPP_NORETURN) +# if defined(_MSC_VER) +# define JSONCPP_NORETURN __declspec(noreturn) +# elif defined(__GNUC__) +# define JSONCPP_NORETURN __attribute__ ((__noreturn__)) +# else +# define JSONCPP_NORETURN +# endif +#endif + +// Disable warning C4251: : needs to have dll-interface to +// be used by... +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(push) +#pragma warning(disable : 4251) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +/** \brief JSON (JavaScript Object Notation). + */ +namespace Json { + +/** Base class for all exceptions we throw. + * + * We use nothing but these internally. Of course, STL can throw others. + */ +class JSON_API Exception : public std::exception { +public: + Exception(JSONCPP_STRING const& msg); + ~Exception() throw() JSONCPP_OVERRIDE; + char const* what() const throw() JSONCPP_OVERRIDE; +protected: + JSONCPP_STRING msg_; +}; + +/** Exceptions which the user cannot easily avoid. + * + * E.g. out-of-memory (when we use malloc), stack-overflow, malicious input + * + * \remark derived from Json::Exception + */ +class JSON_API RuntimeError : public Exception { +public: + RuntimeError(JSONCPP_STRING const& msg); +}; + +/** Exceptions thrown by JSON_ASSERT/JSON_FAIL macros. + * + * These are precondition-violations (user bugs) and internal errors (our bugs). + * + * \remark derived from Json::Exception + */ +class JSON_API LogicError : public Exception { +public: + LogicError(JSONCPP_STRING const& msg); +}; + +/// used internally +JSONCPP_NORETURN void throwRuntimeError(JSONCPP_STRING const& msg); +/// used internally +JSONCPP_NORETURN void throwLogicError(JSONCPP_STRING const& msg); + +/** \brief Type of the value held by a Value object. + */ +enum ValueType { + nullValue = 0, ///< 'null' value + intValue, ///< signed integer value + uintValue, ///< unsigned integer value + realValue, ///< double value + stringValue, ///< UTF-8 string value + booleanValue, ///< bool value + arrayValue, ///< array value (ordered list) + objectValue ///< object value (collection of name/value pairs). +}; + +enum CommentPlacement { + commentBefore = 0, ///< a comment placed on the line before a value + commentAfterOnSameLine, ///< a comment just after a value on the same line + commentAfter, ///< a comment on the line after a value (only make sense for + /// root value) + numberOfCommentPlacement +}; + +//# ifdef JSON_USE_CPPTL +// typedef CppTL::AnyEnumerator EnumMemberNames; +// typedef CppTL::AnyEnumerator EnumValues; +//# endif + +/** \brief Lightweight wrapper to tag static string. + * + * Value constructor and objectValue member assignement takes advantage of the + * StaticString and avoid the cost of string duplication when storing the + * string or the member name. + * + * Example of usage: + * \code + * Json::Value aValue( StaticString("some text") ); + * Json::Value object; + * static const StaticString code("code"); + * object[code] = 1234; + * \endcode + */ +class JSON_API StaticString { +public: + explicit StaticString(const char* czstring) : c_str_(czstring) {} + + operator const char*() const { return c_str_; } + + const char* c_str() const { return c_str_; } + +private: + const char* c_str_; +}; + +/** \brief Represents a JSON value. + * + * This class is a discriminated union wrapper that can represents a: + * - signed integer [range: Value::minInt - Value::maxInt] + * - unsigned integer (range: 0 - Value::maxUInt) + * - double + * - UTF-8 string + * - boolean + * - 'null' + * - an ordered list of Value + * - collection of name/value pairs (javascript object) + * + * The type of the held value is represented by a #ValueType and + * can be obtained using type(). + * + * Values of an #objectValue or #arrayValue can be accessed using operator[]() + * methods. + * Non-const methods will automatically create the a #nullValue element + * if it does not exist. + * The sequence of an #arrayValue will be automatically resized and initialized + * with #nullValue. resize() can be used to enlarge or truncate an #arrayValue. + * + * The get() methods can be used to obtain default value in the case the + * required element does not exist. + * + * It is possible to iterate over the list of a #objectValue values using + * the getMemberNames() method. + * + * \note #Value string-length fit in size_t, but keys must be < 2^30. + * (The reason is an implementation detail.) A #CharReader will raise an + * exception if a bound is exceeded to avoid security holes in your app, + * but the Value API does *not* check bounds. That is the responsibility + * of the caller. + */ +class JSON_API Value { + friend class ValueIteratorBase; +public: + typedef std::vector Members; + typedef ValueIterator iterator; + typedef ValueConstIterator const_iterator; + typedef Json::UInt UInt; + typedef Json::Int Int; +#if defined(JSON_HAS_INT64) + typedef Json::UInt64 UInt64; + typedef Json::Int64 Int64; +#endif // defined(JSON_HAS_INT64) + typedef Json::LargestInt LargestInt; + typedef Json::LargestUInt LargestUInt; + typedef Json::ArrayIndex ArrayIndex; + + static const Value& null; ///< We regret this reference to a global instance; prefer the simpler Value(). + static const Value& nullRef; ///< just a kludge for binary-compatibility; same as null + /// Minimum signed integer value that can be stored in a Json::Value. + static const LargestInt minLargestInt; + /// Maximum signed integer value that can be stored in a Json::Value. + static const LargestInt maxLargestInt; + /// Maximum unsigned integer value that can be stored in a Json::Value. + static const LargestUInt maxLargestUInt; + + /// Minimum signed int value that can be stored in a Json::Value. + static const Int minInt; + /// Maximum signed int value that can be stored in a Json::Value. + static const Int maxInt; + /// Maximum unsigned int value that can be stored in a Json::Value. + static const UInt maxUInt; + +#if defined(JSON_HAS_INT64) + /// Minimum signed 64 bits int value that can be stored in a Json::Value. + static const Int64 minInt64; + /// Maximum signed 64 bits int value that can be stored in a Json::Value. + static const Int64 maxInt64; + /// Maximum unsigned 64 bits int value that can be stored in a Json::Value. + static const UInt64 maxUInt64; +#endif // defined(JSON_HAS_INT64) + +private: +#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + class CZString { + public: + enum DuplicationPolicy { + noDuplication = 0, + duplicate, + duplicateOnCopy + }; + CZString(ArrayIndex index); + CZString(char const* str, unsigned length, DuplicationPolicy allocate); + CZString(CZString const& other); +#if JSON_HAS_RVALUE_REFERENCES + CZString(CZString&& other); +#endif + ~CZString(); + CZString& operator=(CZString other); + bool operator<(CZString const& other) const; + bool operator==(CZString const& other) const; + ArrayIndex index() const; + //const char* c_str() const; ///< \deprecated + char const* data() const; + unsigned length() const; + bool isStaticString() const; + + private: + void swap(CZString& other); + + struct StringStorage { + unsigned policy_: 2; + unsigned length_: 30; // 1GB max + }; + + char const* cstr_; // actually, a prefixed string, unless policy is noDup + union { + ArrayIndex index_; + StringStorage storage_; + }; + }; + +public: +#ifndef JSON_USE_CPPTL_SMALLMAP + typedef std::map ObjectValues; +#else + typedef CppTL::SmallMap ObjectValues; +#endif // ifndef JSON_USE_CPPTL_SMALLMAP +#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION + +public: + /** \brief Create a default Value of the given type. + + This is a very useful constructor. + To create an empty array, pass arrayValue. + To create an empty object, pass objectValue. + Another Value can then be set to this one by assignment. +This is useful since clear() and resize() will not alter types. + + Examples: +\code +Json::Value null_value; // null +Json::Value arr_value(Json::arrayValue); // [] +Json::Value obj_value(Json::objectValue); // {} +\endcode + */ + Value(ValueType type = nullValue); + Value(Int value); + Value(UInt value); +#if defined(JSON_HAS_INT64) + Value(Int64 value); + Value(UInt64 value); +#endif // if defined(JSON_HAS_INT64) + Value(double value); + Value(const char* value); ///< Copy til first 0. (NULL causes to seg-fault.) + Value(const char* begin, const char* end); ///< Copy all, incl zeroes. + /** \brief Constructs a value from a static string. + + * Like other value string constructor but do not duplicate the string for + * internal storage. The given string must remain alive after the call to this + * constructor. + * \note This works only for null-terminated strings. (We cannot change the + * size of this class, so we have nowhere to store the length, + * which might be computed later for various operations.) + * + * Example of usage: + * \code + * static StaticString foo("some text"); + * Json::Value aValue(foo); + * \endcode + */ + Value(const StaticString& value); + Value(const JSONCPP_STRING& value); ///< Copy data() til size(). Embedded zeroes too. +#ifdef JSON_USE_CPPTL + Value(const CppTL::ConstString& value); +#endif + Value(bool value); + /// Deep copy. + Value(const Value& other); +#if JSON_HAS_RVALUE_REFERENCES + /// Move constructor + Value(Value&& other); +#endif + ~Value(); + + /// Deep copy, then swap(other). + /// \note Over-write existing comments. To preserve comments, use #swapPayload(). + Value& operator=(Value other); + /// Swap everything. + void swap(Value& other); + /// Swap values but leave comments and source offsets in place. + void swapPayload(Value& other); + + ValueType type() const; + + /// Compare payload only, not comments etc. + bool operator<(const Value& other) const; + bool operator<=(const Value& other) const; + bool operator>=(const Value& other) const; + bool operator>(const Value& other) const; + bool operator==(const Value& other) const; + bool operator!=(const Value& other) const; + int compare(const Value& other) const; + + const char* asCString() const; ///< Embedded zeroes could cause you trouble! +#if JSONCPP_USING_SECURE_MEMORY + unsigned getCStringLength() const; //Allows you to understand the length of the CString +#endif + JSONCPP_STRING asString() const; ///< Embedded zeroes are possible. + /** Get raw char* of string-value. + * \return false if !string. (Seg-fault if str or end are NULL.) + */ + bool getString( + char const** begin, char const** end) const; +#ifdef JSON_USE_CPPTL + CppTL::ConstString asConstString() const; +#endif + Int asInt() const; + UInt asUInt() const; +#if defined(JSON_HAS_INT64) + Int64 asInt64() const; + UInt64 asUInt64() const; +#endif // if defined(JSON_HAS_INT64) + LargestInt asLargestInt() const; + LargestUInt asLargestUInt() const; + float asFloat() const; + double asDouble() const; + bool asBool() const; + + bool isNull() const; + bool isBool() const; + bool isInt() const; + bool isInt64() const; + bool isUInt() const; + bool isUInt64() const; + bool isIntegral() const; + bool isDouble() const; + bool isNumeric() const; + bool isString() const; + bool isArray() const; + bool isObject() const; + + bool isConvertibleTo(ValueType other) const; + + /// Number of values in array or object + ArrayIndex size() const; + + /// \brief Return true if empty array, empty object, or null; + /// otherwise, false. + bool empty() const; + + /// Return isNull() + bool operator!() const; + + /// Remove all object members and array elements. + /// \pre type() is arrayValue, objectValue, or nullValue + /// \post type() is unchanged + void clear(); + + /// Resize the array to size elements. + /// New elements are initialized to null. + /// May only be called on nullValue or arrayValue. + /// \pre type() is arrayValue or nullValue + /// \post type() is arrayValue + void resize(ArrayIndex size); + + /// Access an array element (zero based index ). + /// If the array contains less than index element, then null value are + /// inserted + /// in the array so that its size is index+1. + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + Value& operator[](ArrayIndex index); + + /// Access an array element (zero based index ). + /// If the array contains less than index element, then null value are + /// inserted + /// in the array so that its size is index+1. + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + Value& operator[](int index); + + /// Access an array element (zero based index ) + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + const Value& operator[](ArrayIndex index) const; + + /// Access an array element (zero based index ) + /// (You may need to say 'value[0u]' to get your compiler to distinguish + /// this from the operator[] which takes a string.) + const Value& operator[](int index) const; + + /// If the array contains at least index+1 elements, returns the element + /// value, + /// otherwise returns defaultValue. + Value get(ArrayIndex index, const Value& defaultValue) const; + /// Return true if index < size(). + bool isValidIndex(ArrayIndex index) const; + /// \brief Append value to array at the end. + /// + /// Equivalent to jsonvalue[jsonvalue.size()] = value; + Value& append(const Value& value); + + /// Access an object value by name, create a null member if it does not exist. + /// \note Because of our implementation, keys are limited to 2^30 -1 chars. + /// Exceeding that will cause an exception. + Value& operator[](const char* key); + /// Access an object value by name, returns null if there is no member with + /// that name. + const Value& operator[](const char* key) const; + /// Access an object value by name, create a null member if it does not exist. + /// \param key may contain embedded nulls. + Value& operator[](const JSONCPP_STRING& key); + /// Access an object value by name, returns null if there is no member with + /// that name. + /// \param key may contain embedded nulls. + const Value& operator[](const JSONCPP_STRING& key) const; + /** \brief Access an object value by name, create a null member if it does not + exist. + + * If the object has no entry for that name, then the member name used to store + * the new entry is not duplicated. + * Example of use: + * \code + * Json::Value object; + * static const StaticString code("code"); + * object[code] = 1234; + * \endcode + */ + Value& operator[](const StaticString& key); +#ifdef JSON_USE_CPPTL + /// Access an object value by name, create a null member if it does not exist. + Value& operator[](const CppTL::ConstString& key); + /// Access an object value by name, returns null if there is no member with + /// that name. + const Value& operator[](const CppTL::ConstString& key) const; +#endif + /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy + Value get(const char* key, const Value& defaultValue) const; + /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy + /// \note key may contain embedded nulls. + Value get(const char* begin, const char* end, const Value& defaultValue) const; + /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy + /// \param key may contain embedded nulls. + Value get(const JSONCPP_STRING& key, const Value& defaultValue) const; +#ifdef JSON_USE_CPPTL + /// Return the member named key if it exist, defaultValue otherwise. + /// \note deep copy + Value get(const CppTL::ConstString& key, const Value& defaultValue) const; +#endif + /// Most general and efficient version of isMember()const, get()const, + /// and operator[]const + /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30 + Value const* find(char const* begin, char const* end) const; + /// Most general and efficient version of object-mutators. + /// \note As stated elsewhere, behavior is undefined if (end-begin) >= 2^30 + /// \return non-zero, but JSON_ASSERT if this is neither object nor nullValue. + Value const* demand(char const* begin, char const* end); + /// \brief Remove and return the named member. + /// + /// Do nothing if it did not exist. + /// \return the removed Value, or null. + /// \pre type() is objectValue or nullValue + /// \post type() is unchanged + /// \deprecated + Value removeMember(const char* key); + /// Same as removeMember(const char*) + /// \param key may contain embedded nulls. + /// \deprecated + Value removeMember(const JSONCPP_STRING& key); + /// Same as removeMember(const char* begin, const char* end, Value* removed), + /// but 'key' is null-terminated. + bool removeMember(const char* key, Value* removed); + /** \brief Remove the named map member. + + Update 'removed' iff removed. + \param key may contain embedded nulls. + \return true iff removed (no exceptions) + */ + bool removeMember(JSONCPP_STRING const& key, Value* removed); + /// Same as removeMember(JSONCPP_STRING const& key, Value* removed) + bool removeMember(const char* begin, const char* end, Value* removed); + /** \brief Remove the indexed array element. + + O(n) expensive operations. + Update 'removed' iff removed. + \return true iff removed (no exceptions) + */ + bool removeIndex(ArrayIndex i, Value* removed); + + /// Return true if the object has a member named key. + /// \note 'key' must be null-terminated. + bool isMember(const char* key) const; + /// Return true if the object has a member named key. + /// \param key may contain embedded nulls. + bool isMember(const JSONCPP_STRING& key) const; + /// Same as isMember(JSONCPP_STRING const& key)const + bool isMember(const char* begin, const char* end) const; +#ifdef JSON_USE_CPPTL + /// Return true if the object has a member named key. + bool isMember(const CppTL::ConstString& key) const; +#endif + + /// \brief Return a list of the member names. + /// + /// If null, return an empty list. + /// \pre type() is objectValue or nullValue + /// \post if type() was nullValue, it remains nullValue + Members getMemberNames() const; + + //# ifdef JSON_USE_CPPTL + // EnumMemberNames enumMemberNames() const; + // EnumValues enumValues() const; + //# endif + + /// \deprecated Always pass len. + JSONCPP_DEPRECATED("Use setComment(JSONCPP_STRING const&) instead.") + void setComment(const char* comment, CommentPlacement placement); + /// Comments must be //... or /* ... */ + void setComment(const char* comment, size_t len, CommentPlacement placement); + /// Comments must be //... or /* ... */ + void setComment(const JSONCPP_STRING& comment, CommentPlacement placement); + bool hasComment(CommentPlacement placement) const; + /// Include delimiters and embedded newlines. + JSONCPP_STRING getComment(CommentPlacement placement) const; + + JSONCPP_STRING toStyledString() const; + + const_iterator begin() const; + const_iterator end() const; + + iterator begin(); + iterator end(); + + // Accessors for the [start, limit) range of bytes within the JSON text from + // which this value was parsed, if any. + void setOffsetStart(ptrdiff_t start); + void setOffsetLimit(ptrdiff_t limit); + ptrdiff_t getOffsetStart() const; + ptrdiff_t getOffsetLimit() const; + +private: + void initBasic(ValueType type, bool allocated = false); + + Value& resolveReference(const char* key); + Value& resolveReference(const char* key, const char* end); + + struct CommentInfo { + CommentInfo(); + ~CommentInfo(); + + void setComment(const char* text, size_t len); + + char* comment_; + }; + + // struct MemberNamesTransform + //{ + // typedef const char *result_type; + // const char *operator()( const CZString &name ) const + // { + // return name.c_str(); + // } + //}; + + union ValueHolder { + LargestInt int_; + LargestUInt uint_; + double real_; + bool bool_; + char* string_; // actually ptr to unsigned, followed by str, unless !allocated_ + ObjectValues* map_; + } value_; + ValueType type_ : 8; + unsigned int allocated_ : 1; // Notes: if declared as bool, bitfield is useless. + // If not allocated_, string_ must be null-terminated. + CommentInfo* comments_; + + // [start, limit) byte offsets in the source JSON text from which this Value + // was extracted. + ptrdiff_t start_; + ptrdiff_t limit_; +}; + +/** \brief Experimental and untested: represents an element of the "path" to + * access a node. + */ +class JSON_API PathArgument { +public: + friend class Path; + + PathArgument(); + PathArgument(ArrayIndex index); + PathArgument(const char* key); + PathArgument(const JSONCPP_STRING& key); + +private: + enum Kind { + kindNone = 0, + kindIndex, + kindKey + }; + JSONCPP_STRING key_; + ArrayIndex index_; + Kind kind_; +}; + +/** \brief Experimental and untested: represents a "path" to access a node. + * + * Syntax: + * - "." => root node + * - ".[n]" => elements at index 'n' of root node (an array value) + * - ".name" => member named 'name' of root node (an object value) + * - ".name1.name2.name3" + * - ".[0][1][2].name1[3]" + * - ".%" => member name is provided as parameter + * - ".[%]" => index is provied as parameter + */ +class JSON_API Path { +public: + Path(const JSONCPP_STRING& path, + const PathArgument& a1 = PathArgument(), + const PathArgument& a2 = PathArgument(), + const PathArgument& a3 = PathArgument(), + const PathArgument& a4 = PathArgument(), + const PathArgument& a5 = PathArgument()); + + const Value& resolve(const Value& root) const; + Value resolve(const Value& root, const Value& defaultValue) const; + /// Creates the "path" to access the specified node and returns a reference on + /// the node. + Value& make(Value& root) const; + +private: + typedef std::vector InArgs; + typedef std::vector Args; + + void makePath(const JSONCPP_STRING& path, const InArgs& in); + void addPathInArg(const JSONCPP_STRING& path, + const InArgs& in, + InArgs::const_iterator& itInArg, + PathArgument::Kind kind); + void invalidPath(const JSONCPP_STRING& path, int location); + + Args args_; +}; + +/** \brief base class for Value iterators. + * + */ +class JSON_API ValueIteratorBase { +public: + typedef std::bidirectional_iterator_tag iterator_category; + typedef unsigned int size_t; + typedef int difference_type; + typedef ValueIteratorBase SelfType; + + bool operator==(const SelfType& other) const { return isEqual(other); } + + bool operator!=(const SelfType& other) const { return !isEqual(other); } + + difference_type operator-(const SelfType& other) const { + return other.computeDistance(*this); + } + + /// Return either the index or the member name of the referenced value as a + /// Value. + Value key() const; + + /// Return the index of the referenced Value, or -1 if it is not an arrayValue. + UInt index() const; + + /// Return the member name of the referenced Value, or "" if it is not an + /// objectValue. + /// \note Avoid `c_str()` on result, as embedded zeroes are possible. + JSONCPP_STRING name() const; + + /// Return the member name of the referenced Value. "" if it is not an + /// objectValue. + /// \deprecated This cannot be used for UTF-8 strings, since there can be embedded nulls. + JSONCPP_DEPRECATED("Use `key = name();` instead.") + char const* memberName() const; + /// Return the member name of the referenced Value, or NULL if it is not an + /// objectValue. + /// \note Better version than memberName(). Allows embedded nulls. + char const* memberName(char const** end) const; + +protected: + Value& deref() const; + + void increment(); + + void decrement(); + + difference_type computeDistance(const SelfType& other) const; + + bool isEqual(const SelfType& other) const; + + void copy(const SelfType& other); + +private: + Value::ObjectValues::iterator current_; + // Indicates that iterator is for a null value. + bool isNull_; + +public: + // For some reason, BORLAND needs these at the end, rather + // than earlier. No idea why. + ValueIteratorBase(); + explicit ValueIteratorBase(const Value::ObjectValues::iterator& current); +}; + +/** \brief const iterator for object and array value. + * + */ +class JSON_API ValueConstIterator : public ValueIteratorBase { + friend class Value; + +public: + typedef const Value value_type; + //typedef unsigned int size_t; + //typedef int difference_type; + typedef const Value& reference; + typedef const Value* pointer; + typedef ValueConstIterator SelfType; + + ValueConstIterator(); + ValueConstIterator(ValueIterator const& other); + +private: +/*! \internal Use by Value to create an iterator. + */ + explicit ValueConstIterator(const Value::ObjectValues::iterator& current); +public: + SelfType& operator=(const ValueIteratorBase& other); + + SelfType operator++(int) { + SelfType temp(*this); + ++*this; + return temp; + } + + SelfType operator--(int) { + SelfType temp(*this); + --*this; + return temp; + } + + SelfType& operator--() { + decrement(); + return *this; + } + + SelfType& operator++() { + increment(); + return *this; + } + + reference operator*() const { return deref(); } + + pointer operator->() const { return &deref(); } +}; + +/** \brief Iterator for object and array value. + */ +class JSON_API ValueIterator : public ValueIteratorBase { + friend class Value; + +public: + typedef Value value_type; + typedef unsigned int size_t; + typedef int difference_type; + typedef Value& reference; + typedef Value* pointer; + typedef ValueIterator SelfType; + + ValueIterator(); + explicit ValueIterator(const ValueConstIterator& other); + ValueIterator(const ValueIterator& other); + +private: +/*! \internal Use by Value to create an iterator. + */ + explicit ValueIterator(const Value::ObjectValues::iterator& current); +public: + SelfType& operator=(const SelfType& other); + + SelfType operator++(int) { + SelfType temp(*this); + ++*this; + return temp; + } + + SelfType operator--(int) { + SelfType temp(*this); + --*this; + return temp; + } + + SelfType& operator--() { + decrement(); + return *this; + } + + SelfType& operator++() { + increment(); + return *this; + } + + reference operator*() const { return deref(); } + + pointer operator->() const { return &deref(); } +}; + +} // namespace Json + + +namespace std { +/// Specialize std::swap() for Json::Value. +template<> +inline void swap(Json::Value& a, Json::Value& b) { a.swap(b); } +} + + +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(pop) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#endif // CPPTL_JSON_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/value.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/reader.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef CPPTL_JSON_READER_H_INCLUDED +#define CPPTL_JSON_READER_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "features.h" +#include "value.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include +#include +#include + +// Disable warning C4251: : needs to have dll-interface to +// be used by... +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(push) +#pragma warning(disable : 4251) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +namespace Json { + +/** \brief Unserialize a JSON document into a + *Value. + * + * \deprecated Use CharReader and CharReaderBuilder. + */ +class JSON_API Reader { +public: + typedef char Char; + typedef const Char* Location; + + /** \brief An error tagged with where in the JSON text it was encountered. + * + * The offsets give the [start, limit) range of bytes within the text. Note + * that this is bytes, not codepoints. + * + */ + struct StructuredError { + ptrdiff_t offset_start; + ptrdiff_t offset_limit; + JSONCPP_STRING message; + }; + + /** \brief Constructs a Reader allowing all features + * for parsing. + */ + Reader(); + + /** \brief Constructs a Reader allowing the specified feature set + * for parsing. + */ + Reader(const Features& features); + + /** \brief Read a Value from a JSON + * document. + * \param document UTF-8 encoded string containing the document to read. + * \param root [out] Contains the root value of the document if it was + * successfully parsed. + * \param collectComments \c true to collect comment and allow writing them + * back during + * serialization, \c false to discard comments. + * This parameter is ignored if + * Features::allowComments_ + * is \c false. + * \return \c true if the document was successfully parsed, \c false if an + * error occurred. + */ + bool + parse(const std::string& document, Value& root, bool collectComments = true); + + /** \brief Read a Value from a JSON + document. + * \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the + document to read. + * \param endDoc Pointer on the end of the UTF-8 encoded string of the + document to read. + * Must be >= beginDoc. + * \param root [out] Contains the root value of the document if it was + * successfully parsed. + * \param collectComments \c true to collect comment and allow writing them + back during + * serialization, \c false to discard comments. + * This parameter is ignored if + Features::allowComments_ + * is \c false. + * \return \c true if the document was successfully parsed, \c false if an + error occurred. + */ + bool parse(const char* beginDoc, + const char* endDoc, + Value& root, + bool collectComments = true); + + /// \brief Parse from input stream. + /// \see Json::operator>>(std::istream&, Json::Value&). + bool parse(JSONCPP_ISTREAM& is, Value& root, bool collectComments = true); + + /** \brief Returns a user friendly string that list errors in the parsed + * document. + * \return Formatted error message with the list of errors with their location + * in + * the parsed document. An empty string is returned if no error + * occurred + * during parsing. + * \deprecated Use getFormattedErrorMessages() instead (typo fix). + */ + JSONCPP_DEPRECATED("Use getFormattedErrorMessages() instead.") + JSONCPP_STRING getFormatedErrorMessages() const; + + /** \brief Returns a user friendly string that list errors in the parsed + * document. + * \return Formatted error message with the list of errors with their location + * in + * the parsed document. An empty string is returned if no error + * occurred + * during parsing. + */ + JSONCPP_STRING getFormattedErrorMessages() const; + + /** \brief Returns a vector of structured erros encounted while parsing. + * \return A (possibly empty) vector of StructuredError objects. Currently + * only one error can be returned, but the caller should tolerate + * multiple + * errors. This can occur if the parser recovers from a non-fatal + * parse error and then encounters additional errors. + */ + std::vector getStructuredErrors() const; + + /** \brief Add a semantic error message. + * \param value JSON Value location associated with the error + * \param message The error message. + * \return \c true if the error was successfully added, \c false if the + * Value offset exceeds the document size. + */ + bool pushError(const Value& value, const JSONCPP_STRING& message); + + /** \brief Add a semantic error message with extra context. + * \param value JSON Value location associated with the error + * \param message The error message. + * \param extra Additional JSON Value location to contextualize the error + * \return \c true if the error was successfully added, \c false if either + * Value offset exceeds the document size. + */ + bool pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra); + + /** \brief Return whether there are any errors. + * \return \c true if there are no errors to report \c false if + * errors have occurred. + */ + bool good() const; + +private: + enum TokenType { + tokenEndOfStream = 0, + tokenObjectBegin, + tokenObjectEnd, + tokenArrayBegin, + tokenArrayEnd, + tokenString, + tokenNumber, + tokenTrue, + tokenFalse, + tokenNull, + tokenArraySeparator, + tokenMemberSeparator, + tokenComment, + tokenError + }; + + class Token { + public: + TokenType type_; + Location start_; + Location end_; + }; + + class ErrorInfo { + public: + Token token_; + JSONCPP_STRING message_; + Location extra_; + }; + + typedef std::deque Errors; + + bool readToken(Token& token); + void skipSpaces(); + bool match(Location pattern, int patternLength); + bool readComment(); + bool readCStyleComment(); + bool readCppStyleComment(); + bool readString(); + void readNumber(); + bool readValue(); + bool readObject(Token& token); + bool readArray(Token& token); + bool decodeNumber(Token& token); + bool decodeNumber(Token& token, Value& decoded); + bool decodeString(Token& token); + bool decodeString(Token& token, JSONCPP_STRING& decoded); + bool decodeDouble(Token& token); + bool decodeDouble(Token& token, Value& decoded); + bool decodeUnicodeCodePoint(Token& token, + Location& current, + Location end, + unsigned int& unicode); + bool decodeUnicodeEscapeSequence(Token& token, + Location& current, + Location end, + unsigned int& unicode); + bool addError(const JSONCPP_STRING& message, Token& token, Location extra = 0); + bool recoverFromError(TokenType skipUntilToken); + bool addErrorAndRecover(const JSONCPP_STRING& message, + Token& token, + TokenType skipUntilToken); + void skipUntilSpace(); + Value& currentValue(); + Char getNextChar(); + void + getLocationLineAndColumn(Location location, int& line, int& column) const; + JSONCPP_STRING getLocationLineAndColumn(Location location) const; + void addComment(Location begin, Location end, CommentPlacement placement); + void skipCommentTokens(Token& token); + + typedef std::stack Nodes; + Nodes nodes_; + Errors errors_; + JSONCPP_STRING document_; + Location begin_; + Location end_; + Location current_; + Location lastValueEnd_; + Value* lastValue_; + JSONCPP_STRING commentsBefore_; + Features features_; + bool collectComments_; +}; // Reader + +/** Interface for reading JSON from a char array. + */ +class JSON_API CharReader { +public: + virtual ~CharReader() {} + /** \brief Read a Value from a JSON + document. + * The document must be a UTF-8 encoded string containing the document to read. + * + * \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the + document to read. + * \param endDoc Pointer on the end of the UTF-8 encoded string of the + document to read. + * Must be >= beginDoc. + * \param root [out] Contains the root value of the document if it was + * successfully parsed. + * \param errs [out] Formatted error messages (if not NULL) + * a user friendly string that lists errors in the parsed + * document. + * \return \c true if the document was successfully parsed, \c false if an + error occurred. + */ + virtual bool parse( + char const* beginDoc, char const* endDoc, + Value* root, JSONCPP_STRING* errs) = 0; + + class JSON_API Factory { + public: + virtual ~Factory() {} + /** \brief Allocate a CharReader via operator new(). + * \throw std::exception if something goes wrong (e.g. invalid settings) + */ + virtual CharReader* newCharReader() const = 0; + }; // Factory +}; // CharReader + +/** \brief Build a CharReader implementation. + +Usage: +\code + using namespace Json; + CharReaderBuilder builder; + builder["collectComments"] = false; + Value value; + JSONCPP_STRING errs; + bool ok = parseFromStream(builder, std::cin, &value, &errs); +\endcode +*/ +class JSON_API CharReaderBuilder : public CharReader::Factory { +public: + // Note: We use a Json::Value so that we can add data-members to this class + // without a major version bump. + /** Configuration of this builder. + These are case-sensitive. + Available settings (case-sensitive): + - `"collectComments": false or true` + - true to collect comment and allow writing them + back during serialization, false to discard comments. + This parameter is ignored if allowComments is false. + - `"allowComments": false or true` + - true if comments are allowed. + - `"strictRoot": false or true` + - true if root must be either an array or an object value + - `"allowDroppedNullPlaceholders": false or true` + - true if dropped null placeholders are allowed. (See StreamWriterBuilder.) + - `"allowNumericKeys": false or true` + - true if numeric object keys are allowed. + - `"allowSingleQuotes": false or true` + - true if '' are allowed for strings (both keys and values) + - `"stackLimit": integer` + - Exceeding stackLimit (recursive depth of `readValue()`) will + cause an exception. + - This is a security issue (seg-faults caused by deeply nested JSON), + so the default is low. + - `"failIfExtra": false or true` + - If true, `parse()` returns false when extra non-whitespace trails + the JSON value in the input string. + - `"rejectDupKeys": false or true` + - If true, `parse()` returns false when a key is duplicated within an object. + - `"allowSpecialFloats": false or true` + - If true, special float values (NaNs and infinities) are allowed + and their values are lossfree restorable. + + You can examine 'settings_` yourself + to see the defaults. You can also write and read them just like any + JSON Value. + \sa setDefaults() + */ + Json::Value settings_; + + CharReaderBuilder(); + ~CharReaderBuilder() JSONCPP_OVERRIDE; + + CharReader* newCharReader() const JSONCPP_OVERRIDE; + + /** \return true if 'settings' are legal and consistent; + * otherwise, indicate bad settings via 'invalid'. + */ + bool validate(Json::Value* invalid) const; + + /** A simple way to update a specific setting. + */ + Value& operator[](JSONCPP_STRING key); + + /** Called by ctor, but you can use this to reset settings_. + * \pre 'settings' != NULL (but Json::null is fine) + * \remark Defaults: + * \snippet src/lib_json/json_reader.cpp CharReaderBuilderDefaults + */ + static void setDefaults(Json::Value* settings); + /** Same as old Features::strictMode(). + * \pre 'settings' != NULL (but Json::null is fine) + * \remark Defaults: + * \snippet src/lib_json/json_reader.cpp CharReaderBuilderStrictMode + */ + static void strictMode(Json::Value* settings); +}; + +/** Consume entire stream and use its begin/end. + * Someday we might have a real StreamReader, but for now this + * is convenient. + */ +bool JSON_API parseFromStream( + CharReader::Factory const&, + JSONCPP_ISTREAM&, + Value* root, std::string* errs); + +/** \brief Read from 'sin' into 'root'. + + Always keep comments from the input JSON. + + This can be used to read a file into a particular sub-object. + For example: + \code + Json::Value root; + cin >> root["dir"]["file"]; + cout << root; + \endcode + Result: + \verbatim + { + "dir": { + "file": { + // The input stream JSON would be nested here. + } + } + } + \endverbatim + \throw std::exception on parse error. + \see Json::operator<<() +*/ +JSON_API JSONCPP_ISTREAM& operator>>(JSONCPP_ISTREAM&, Value&); + +} // namespace Json + +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(pop) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#endif // CPPTL_JSON_READER_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/reader.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/writer.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef JSON_WRITER_H_INCLUDED +#define JSON_WRITER_H_INCLUDED + +#if !defined(JSON_IS_AMALGAMATION) +#include "value.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include + +// Disable warning C4251: : needs to have dll-interface to +// be used by... +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(push) +#pragma warning(disable : 4251) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +namespace Json { + +class Value; + +/** + +Usage: +\code + using namespace Json; + void writeToStdout(StreamWriter::Factory const& factory, Value const& value) { + std::unique_ptr const writer( + factory.newStreamWriter()); + writer->write(value, &std::cout); + std::cout << std::endl; // add lf and flush + } +\endcode +*/ +class JSON_API StreamWriter { +protected: + JSONCPP_OSTREAM* sout_; // not owned; will not delete +public: + StreamWriter(); + virtual ~StreamWriter(); + /** Write Value into document as configured in sub-class. + Do not take ownership of sout, but maintain a reference during function. + \pre sout != NULL + \return zero on success (For now, we always return zero, so check the stream instead.) + \throw std::exception possibly, depending on configuration + */ + virtual int write(Value const& root, JSONCPP_OSTREAM* sout) = 0; + + /** \brief A simple abstract factory. + */ + class JSON_API Factory { + public: + virtual ~Factory(); + /** \brief Allocate a CharReader via operator new(). + * \throw std::exception if something goes wrong (e.g. invalid settings) + */ + virtual StreamWriter* newStreamWriter() const = 0; + }; // Factory +}; // StreamWriter + +/** \brief Write into stringstream, then return string, for convenience. + * A StreamWriter will be created from the factory, used, and then deleted. + */ +JSONCPP_STRING JSON_API writeString(StreamWriter::Factory const& factory, Value const& root); + + +/** \brief Build a StreamWriter implementation. + +Usage: +\code + using namespace Json; + Value value = ...; + StreamWriterBuilder builder; + builder["commentStyle"] = "None"; + builder["indentation"] = " "; // or whatever you like + std::unique_ptr writer( + builder.newStreamWriter()); + writer->write(value, &std::cout); + std::cout << std::endl; // add lf and flush +\endcode +*/ +class JSON_API StreamWriterBuilder : public StreamWriter::Factory { +public: + // Note: We use a Json::Value so that we can add data-members to this class + // without a major version bump. + /** Configuration of this builder. + Available settings (case-sensitive): + - "commentStyle": "None" or "All" + - "indentation": "" + - "enableYAMLCompatibility": false or true + - slightly change the whitespace around colons + - "dropNullPlaceholders": false or true + - Drop the "null" string from the writer's output for nullValues. + Strictly speaking, this is not valid JSON. But when the output is being + fed to a browser's Javascript, it makes for smaller output and the + browser can handle the output just fine. + - "useSpecialFloats": false or true + - If true, outputs non-finite floating point values in the following way: + NaN values as "NaN", positive infinity as "Infinity", and negative infinity + as "-Infinity". + + You can examine 'settings_` yourself + to see the defaults. You can also write and read them just like any + JSON Value. + \sa setDefaults() + */ + Json::Value settings_; + + StreamWriterBuilder(); + ~StreamWriterBuilder() JSONCPP_OVERRIDE; + + /** + * \throw std::exception if something goes wrong (e.g. invalid settings) + */ + StreamWriter* newStreamWriter() const JSONCPP_OVERRIDE; + + /** \return true if 'settings' are legal and consistent; + * otherwise, indicate bad settings via 'invalid'. + */ + bool validate(Json::Value* invalid) const; + /** A simple way to update a specific setting. + */ + Value& operator[](JSONCPP_STRING key); + + /** Called by ctor, but you can use this to reset settings_. + * \pre 'settings' != NULL (but Json::null is fine) + * \remark Defaults: + * \snippet src/lib_json/json_writer.cpp StreamWriterBuilderDefaults + */ + static void setDefaults(Json::Value* settings); +}; + +/** \brief Abstract class for writers. + * \deprecated Use StreamWriter. (And really, this is an implementation detail.) + */ +class JSON_API Writer { +public: + virtual ~Writer(); + + virtual JSONCPP_STRING write(const Value& root) = 0; +}; + +/** \brief Outputs a Value in JSON format + *without formatting (not human friendly). + * + * The JSON document is written in a single line. It is not intended for 'human' + *consumption, + * but may be usefull to support feature such as RPC where bandwith is limited. + * \sa Reader, Value + * \deprecated Use StreamWriterBuilder. + */ +class JSON_API FastWriter : public Writer { + +public: + FastWriter(); + ~FastWriter() JSONCPP_OVERRIDE {} + + void enableYAMLCompatibility(); + + /** \brief Drop the "null" string from the writer's output for nullValues. + * Strictly speaking, this is not valid JSON. But when the output is being + * fed to a browser's Javascript, it makes for smaller output and the + * browser can handle the output just fine. + */ + void dropNullPlaceholders(); + + void omitEndingLineFeed(); + +public: // overridden from Writer + JSONCPP_STRING write(const Value& root) JSONCPP_OVERRIDE; + +private: + void writeValue(const Value& value); + + JSONCPP_STRING document_; + bool yamlCompatiblityEnabled_; + bool dropNullPlaceholders_; + bool omitEndingLineFeed_; +}; + +/** \brief Writes a Value in JSON format in a + *human friendly way. + * + * The rules for line break and indent are as follow: + * - Object value: + * - if empty then print {} without indent and line break + * - if not empty the print '{', line break & indent, print one value per + *line + * and then unindent and line break and print '}'. + * - Array value: + * - if empty then print [] without indent and line break + * - if the array contains no object value, empty array or some other value + *types, + * and all the values fit on one lines, then print the array on a single + *line. + * - otherwise, it the values do not fit on one line, or the array contains + * object or non empty array, then print one value per line. + * + * If the Value have comments then they are outputed according to their + *#CommentPlacement. + * + * \sa Reader, Value, Value::setComment() + * \deprecated Use StreamWriterBuilder. + */ +class JSON_API StyledWriter : public Writer { +public: + StyledWriter(); + ~StyledWriter() JSONCPP_OVERRIDE {} + +public: // overridden from Writer + /** \brief Serialize a Value in JSON format. + * \param root Value to serialize. + * \return String containing the JSON document that represents the root value. + */ + JSONCPP_STRING write(const Value& root) JSONCPP_OVERRIDE; + +private: + void writeValue(const Value& value); + void writeArrayValue(const Value& value); + bool isMultineArray(const Value& value); + void pushValue(const JSONCPP_STRING& value); + void writeIndent(); + void writeWithIndent(const JSONCPP_STRING& value); + void indent(); + void unindent(); + void writeCommentBeforeValue(const Value& root); + void writeCommentAfterValueOnSameLine(const Value& root); + bool hasCommentForValue(const Value& value); + static JSONCPP_STRING normalizeEOL(const JSONCPP_STRING& text); + + typedef std::vector ChildValues; + + ChildValues childValues_; + JSONCPP_STRING document_; + JSONCPP_STRING indentString_; + unsigned int rightMargin_; + unsigned int indentSize_; + bool addChildValues_; +}; + +/** \brief Writes a Value in JSON format in a + human friendly way, + to a stream rather than to a string. + * + * The rules for line break and indent are as follow: + * - Object value: + * - if empty then print {} without indent and line break + * - if not empty the print '{', line break & indent, print one value per + line + * and then unindent and line break and print '}'. + * - Array value: + * - if empty then print [] without indent and line break + * - if the array contains no object value, empty array or some other value + types, + * and all the values fit on one lines, then print the array on a single + line. + * - otherwise, it the values do not fit on one line, or the array contains + * object or non empty array, then print one value per line. + * + * If the Value have comments then they are outputed according to their + #CommentPlacement. + * + * \param indentation Each level will be indented by this amount extra. + * \sa Reader, Value, Value::setComment() + * \deprecated Use StreamWriterBuilder. + */ +class JSON_API StyledStreamWriter { +public: + StyledStreamWriter(JSONCPP_STRING indentation = "\t"); + ~StyledStreamWriter() {} + +public: + /** \brief Serialize a Value in JSON format. + * \param out Stream to write to. (Can be ostringstream, e.g.) + * \param root Value to serialize. + * \note There is no point in deriving from Writer, since write() should not + * return a value. + */ + void write(JSONCPP_OSTREAM& out, const Value& root); + +private: + void writeValue(const Value& value); + void writeArrayValue(const Value& value); + bool isMultineArray(const Value& value); + void pushValue(const JSONCPP_STRING& value); + void writeIndent(); + void writeWithIndent(const JSONCPP_STRING& value); + void indent(); + void unindent(); + void writeCommentBeforeValue(const Value& root); + void writeCommentAfterValueOnSameLine(const Value& root); + bool hasCommentForValue(const Value& value); + static JSONCPP_STRING normalizeEOL(const JSONCPP_STRING& text); + + typedef std::vector ChildValues; + + ChildValues childValues_; + JSONCPP_OSTREAM* document_; + JSONCPP_STRING indentString_; + unsigned int rightMargin_; + JSONCPP_STRING indentation_; + bool addChildValues_ : 1; + bool indented_ : 1; +}; + +#if defined(JSON_HAS_INT64) +JSONCPP_STRING JSON_API valueToString(Int value); +JSONCPP_STRING JSON_API valueToString(UInt value); +#endif // if defined(JSON_HAS_INT64) +JSONCPP_STRING JSON_API valueToString(LargestInt value); +JSONCPP_STRING JSON_API valueToString(LargestUInt value); +JSONCPP_STRING JSON_API valueToString(double value); +JSONCPP_STRING JSON_API valueToString(bool value); +JSONCPP_STRING JSON_API valueToQuotedString(const char* value); + +/// \brief Output using the StyledStreamWriter. +/// \see Json::operator>>() +JSON_API JSONCPP_OSTREAM& operator<<(JSONCPP_OSTREAM&, const Value& root); + +} // namespace Json + +#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) +#pragma warning(pop) +#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING) + +#endif // JSON_WRITER_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/writer.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: include/json/assertions.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef CPPTL_JSON_ASSERTIONS_H_INCLUDED +#define CPPTL_JSON_ASSERTIONS_H_INCLUDED + +#include +#include + +#if !defined(JSON_IS_AMALGAMATION) +#include "config.h" +#endif // if !defined(JSON_IS_AMALGAMATION) + +/** It should not be possible for a maliciously designed file to + * cause an abort() or seg-fault, so these macros are used only + * for pre-condition violations and internal logic errors. + */ +#if JSON_USE_EXCEPTION + +// @todo <= add detail about condition in exception +# define JSON_ASSERT(condition) \ + {if (!(condition)) {Json::throwLogicError( "assert json failed" );}} + +# define JSON_FAIL_MESSAGE(message) \ + { \ + JSONCPP_OSTRINGSTREAM oss; oss << message; \ + Json::throwLogicError(oss.str()); \ + abort(); \ + } + +#else // JSON_USE_EXCEPTION + +# define JSON_ASSERT(condition) assert(condition) + +// The call to assert() will show the failure message in debug builds. In +// release builds we abort, for a core-dump or debugger. +# define JSON_FAIL_MESSAGE(message) \ + { \ + JSONCPP_OSTRINGSTREAM oss; oss << message; \ + assert(false && oss.str().c_str()); \ + abort(); \ + } + + +#endif + +#define JSON_ASSERT_MESSAGE(condition, message) \ + if (!(condition)) { \ + JSON_FAIL_MESSAGE(message); \ + } + +#endif // CPPTL_JSON_ASSERTIONS_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: include/json/assertions.h +// ////////////////////////////////////////////////////////////////////// + + + + + +#endif //ifndef JSON_AMALGATED_H_INCLUDED diff --git a/source/json/jsoncpp.cpp b/source/json/jsoncpp.cpp new file mode 100644 index 0000000..ee7b3b4 --- /dev/null +++ b/source/json/jsoncpp.cpp @@ -0,0 +1,5246 @@ +/// Json-cpp amalgated source (http://jsoncpp.sourceforge.net/). +/// It is intended to be used with #include "json/json.h" + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: LICENSE +// ////////////////////////////////////////////////////////////////////// + +/* +The JsonCpp library's source code, including accompanying documentation, +tests and demonstration applications, are licensed under the following +conditions... + +The author (Baptiste Lepilleur) explicitly disclaims copyright in all +jurisdictions which recognize such a disclaimer. In such jurisdictions, +this software is released into the Public Domain. + +In jurisdictions which do not recognize Public Domain property (e.g. Germany as of +2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is +released under the terms of the MIT License (see below). + +In jurisdictions which recognize Public Domain property, the user of this +software may choose to accept it either as 1) Public Domain, 2) under the +conditions of the MIT License (see below), or 3) under the terms of dual +Public Domain/MIT License conditions described here, as they choose. + +The MIT License is about as close to Public Domain as a license can get, and is +described in clear, concise terms at: + + http://en.wikipedia.org/wiki/MIT_License + +The full text of the MIT License follows: + +======================================================================== +Copyright (c) 2007-2010 Baptiste Lepilleur + +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. +======================================================================== +(END LICENSE TEXT) + +The MIT license is compatible with both the GPL and commercial +software, affording one all of the rights of Public Domain with the +minor nuisance of being required to keep the above copyright notice +and license text in the source code. Note also that by accepting the +Public Domain "license" you can re-license your copy using whatever +license you like. + +*/ + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: LICENSE +// ////////////////////////////////////////////////////////////////////// + + + + + + +#include "json.h" + +#ifndef JSON_IS_AMALGAMATION +#error "Compile with -I PATH_TO_JSON_DIRECTORY" +#endif + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: src/lib_json/json_tool.h +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#ifndef LIB_JSONCPP_JSON_TOOL_H_INCLUDED +#define LIB_JSONCPP_JSON_TOOL_H_INCLUDED + +/* This header provides common string manipulation support, such as UTF-8, + * portable conversion from/to string... + * + * It is an internal header that must not be exposed. + */ + +namespace Json { + +/// Converts a unicode code-point to UTF-8. +static inline JSONCPP_STRING codePointToUTF8(unsigned int cp) { + JSONCPP_STRING result; + + // based on description from http://en.wikipedia.org/wiki/UTF-8 + + if (cp <= 0x7f) { + result.resize(1); + result[0] = static_cast(cp); + } else if (cp <= 0x7FF) { + result.resize(2); + result[1] = static_cast(0x80 | (0x3f & cp)); + result[0] = static_cast(0xC0 | (0x1f & (cp >> 6))); + } else if (cp <= 0xFFFF) { + result.resize(3); + result[2] = static_cast(0x80 | (0x3f & cp)); + result[1] = static_cast(0x80 | (0x3f & (cp >> 6))); + result[0] = static_cast(0xE0 | (0xf & (cp >> 12))); + } else if (cp <= 0x10FFFF) { + result.resize(4); + result[3] = static_cast(0x80 | (0x3f & cp)); + result[2] = static_cast(0x80 | (0x3f & (cp >> 6))); + result[1] = static_cast(0x80 | (0x3f & (cp >> 12))); + result[0] = static_cast(0xF0 | (0x7 & (cp >> 18))); + } + + return result; +} + +/// Returns true if ch is a control character (in range [1,31]). +static inline bool isControlCharacter(char ch) { return ch > 0 && ch <= 0x1F; } + +enum { + /// Constant that specify the size of the buffer that must be passed to + /// uintToString. + uintToStringBufferSize = 3 * sizeof(LargestUInt) + 1 +}; + +// Defines a char buffer for use with uintToString(). +typedef char UIntToStringBuffer[uintToStringBufferSize]; + +/** Converts an unsigned integer to string. + * @param value Unsigned interger to convert to string + * @param current Input/Output string buffer. + * Must have at least uintToStringBufferSize chars free. + */ +static inline void uintToString(LargestUInt value, char*& current) { + *--current = 0; + do { + *--current = static_cast(value % 10U + static_cast('0')); + value /= 10; + } while (value != 0); +} + +/** Change ',' to '.' everywhere in buffer. + * + * We had a sophisticated way, but it did not work in WinCE. + * @see https://github.com/open-source-parsers/jsoncpp/pull/9 + */ +static inline void fixNumericLocale(char* begin, char* end) { + while (begin < end) { + if (*begin == ',') { + *begin = '.'; + } + ++begin; + } +} + +} // namespace Json { + +#endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: src/lib_json/json_tool.h +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: src/lib_json/json_reader.cpp +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2011 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include +#include "json_tool.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(_MSC_VER) +#if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above +#define snprintf sprintf_s +#elif _MSC_VER >= 1900 // VC++ 14.0 and above +#define snprintf std::snprintf +#else +#define snprintf _snprintf +#endif +#elif defined(__ANDROID__) || defined(__QNXNTO__) +#define snprintf snprintf +#elif __cplusplus >= 201103L +#if !defined(__MINGW32__) && !defined(__CYGWIN__) +//#define snprintf std::snprintf +#endif +#endif + +#if defined(__QNXNTO__) +#define sscanf std::sscanf +#endif + +#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0 +// Disable warning about strdup being deprecated. +#pragma warning(disable : 4996) +#endif + +static int const stackLimit_g = 1000; +static int stackDepth_g = 0; // see readValue() + +namespace Json { + +#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) +typedef std::unique_ptr CharReaderPtr; +#else +typedef std::auto_ptr CharReaderPtr; +#endif + +// Implementation of class Features +// //////////////////////////////// + +Features::Features() + : allowComments_(true), strictRoot_(false), + allowDroppedNullPlaceholders_(false), allowNumericKeys_(false) {} + +Features Features::all() { return Features(); } + +Features Features::strictMode() { + Features features; + features.allowComments_ = false; + features.strictRoot_ = true; + features.allowDroppedNullPlaceholders_ = false; + features.allowNumericKeys_ = false; + return features; +} + +// Implementation of class Reader +// //////////////////////////////// + +static bool containsNewLine(Reader::Location begin, Reader::Location end) { + for (; begin < end; ++begin) + if (*begin == '\n' || *begin == '\r') + return true; + return false; +} + +// Class Reader +// ////////////////////////////////////////////////////////////////// + +Reader::Reader() + : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), + lastValue_(), commentsBefore_(), features_(Features::all()), + collectComments_() {} + +Reader::Reader(const Features& features) + : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), + lastValue_(), commentsBefore_(), features_(features), collectComments_() { +} + +bool +Reader::parse(const std::string& document, Value& root, bool collectComments) { + JSONCPP_STRING documentCopy(document.data(), document.data() + document.capacity()); + std::swap(documentCopy, document_); + const char* begin = document_.c_str(); + const char* end = begin + document_.length(); + return parse(begin, end, root, collectComments); +} + +bool Reader::parse(std::istream& sin, Value& root, bool collectComments) { + // std::istream_iterator begin(sin); + // std::istream_iterator end; + // Those would allow streamed input from a file, if parse() were a + // template function. + + // Since JSONCPP_STRING is reference-counted, this at least does not + // create an extra copy. + JSONCPP_STRING doc; + std::getline(sin, doc, (char)EOF); + return parse(doc.data(), doc.data() + doc.size(), root, collectComments); +} + +bool Reader::parse(const char* beginDoc, + const char* endDoc, + Value& root, + bool collectComments) { + if (!features_.allowComments_) { + collectComments = false; + } + + begin_ = beginDoc; + end_ = endDoc; + collectComments_ = collectComments; + current_ = begin_; + lastValueEnd_ = 0; + lastValue_ = 0; + commentsBefore_ = ""; + errors_.clear(); + while (!nodes_.empty()) + nodes_.pop(); + nodes_.push(&root); + + stackDepth_g = 0; // Yes, this is bad coding, but options are limited. + bool successful = readValue(); + Token token; + skipCommentTokens(token); + if (collectComments_ && !commentsBefore_.empty()) + root.setComment(commentsBefore_, commentAfter); + if (features_.strictRoot_) { + if (!root.isArray() && !root.isObject()) { + // Set error location to start of doc, ideally should be first token found + // in doc + token.type_ = tokenError; + token.start_ = beginDoc; + token.end_ = endDoc; + addError( + "A valid JSON document must be either an array or an object value.", + token); + return false; + } + } + return successful; +} + +bool Reader::readValue() { + // This is a non-reentrant way to support a stackLimit. Terrible! + // But this deprecated class has a security problem: Bad input can + // cause a seg-fault. This seems like a fair, binary-compatible way + // to prevent the problem. + if (stackDepth_g >= stackLimit_g) throwRuntimeError("Exceeded stackLimit in readValue()."); + ++stackDepth_g; + + Token token; + skipCommentTokens(token); + bool successful = true; + + if (collectComments_ && !commentsBefore_.empty()) { + currentValue().setComment(commentsBefore_, commentBefore); + commentsBefore_ = ""; + } + + switch (token.type_) { + case tokenObjectBegin: + successful = readObject(token); + currentValue().setOffsetLimit(current_ - begin_); + break; + case tokenArrayBegin: + successful = readArray(token); + currentValue().setOffsetLimit(current_ - begin_); + break; + case tokenNumber: + successful = decodeNumber(token); + break; + case tokenString: + successful = decodeString(token); + break; + case tokenTrue: + { + Value v(true); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenFalse: + { + Value v(false); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenNull: + { + Value v; + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenArraySeparator: + case tokenObjectEnd: + case tokenArrayEnd: + if (features_.allowDroppedNullPlaceholders_) { + // "Un-read" the current token and mark the current value as a null + // token. + current_--; + Value v; + currentValue().swapPayload(v); + currentValue().setOffsetStart(current_ - begin_ - 1); + currentValue().setOffsetLimit(current_ - begin_); + break; + } // Else, fall through... + default: + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return addError("Syntax error: value, object or array expected.", token); + } + + if (collectComments_) { + lastValueEnd_ = current_; + lastValue_ = ¤tValue(); + } + + --stackDepth_g; + return successful; +} + +void Reader::skipCommentTokens(Token& token) { + if (features_.allowComments_) { + do { + readToken(token); + } while (token.type_ == tokenComment); + } else { + readToken(token); + } +} + +bool Reader::readToken(Token& token) { + skipSpaces(); + token.start_ = current_; + Char c = getNextChar(); + bool ok = true; + switch (c) { + case '{': + token.type_ = tokenObjectBegin; + break; + case '}': + token.type_ = tokenObjectEnd; + break; + case '[': + token.type_ = tokenArrayBegin; + break; + case ']': + token.type_ = tokenArrayEnd; + break; + case '"': + token.type_ = tokenString; + ok = readString(); + break; + case '/': + token.type_ = tokenComment; + ok = readComment(); + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '-': + token.type_ = tokenNumber; + readNumber(); + break; + case 't': + token.type_ = tokenTrue; + ok = match("rue", 3); + break; + case 'f': + token.type_ = tokenFalse; + ok = match("alse", 4); + break; + case 'n': + token.type_ = tokenNull; + ok = match("ull", 3); + break; + case ',': + token.type_ = tokenArraySeparator; + break; + case ':': + token.type_ = tokenMemberSeparator; + break; + case 0: + token.type_ = tokenEndOfStream; + break; + default: + ok = false; + break; + } + if (!ok) + token.type_ = tokenError; + token.end_ = current_; + return true; +} + +void Reader::skipSpaces() { + while (current_ != end_) { + Char c = *current_; + if (c == ' ' || c == '\t' || c == '\r' || c == '\n') + ++current_; + else + break; + } +} + +bool Reader::match(Location pattern, int patternLength) { + if (end_ - current_ < patternLength) + return false; + int index = patternLength; + while (index--) + if (current_[index] != pattern[index]) + return false; + current_ += patternLength; + return true; +} + +bool Reader::readComment() { + Location commentBegin = current_ - 1; + Char c = getNextChar(); + bool successful = false; + if (c == '*') + successful = readCStyleComment(); + else if (c == '/') + successful = readCppStyleComment(); + if (!successful) + return false; + + if (collectComments_) { + CommentPlacement placement = commentBefore; + if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) { + if (c != '*' || !containsNewLine(commentBegin, current_)) + placement = commentAfterOnSameLine; + } + + addComment(commentBegin, current_, placement); + } + return true; +} + +static JSONCPP_STRING normalizeEOL(Reader::Location begin, Reader::Location end) { + JSONCPP_STRING normalized; + normalized.reserve(static_cast(end - begin)); + Reader::Location current = begin; + while (current != end) { + char c = *current++; + if (c == '\r') { + if (current != end && *current == '\n') + // convert dos EOL + ++current; + // convert Mac EOL + normalized += '\n'; + } else { + normalized += c; + } + } + return normalized; +} + +void +Reader::addComment(Location begin, Location end, CommentPlacement placement) { + assert(collectComments_); + const JSONCPP_STRING& normalized = normalizeEOL(begin, end); + if (placement == commentAfterOnSameLine) { + assert(lastValue_ != 0); + lastValue_->setComment(normalized, placement); + } else { + commentsBefore_ += normalized; + } +} + +bool Reader::readCStyleComment() { + while (current_ != end_) { + Char c = getNextChar(); + if (c == '*' && *current_ == '/') + break; + } + return getNextChar() == '/'; +} + +bool Reader::readCppStyleComment() { + while (current_ != end_) { + Char c = getNextChar(); + if (c == '\n') + break; + if (c == '\r') { + // Consume DOS EOL. It will be normalized in addComment. + if (current_ != end_ && *current_ == '\n') + getNextChar(); + // Break on Moc OS 9 EOL. + break; + } + } + return true; +} + +void Reader::readNumber() { + const char *p = current_; + char c = '0'; // stopgap for already consumed character + // integral part + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : 0; + // fractional part + if (c == '.') { + c = (current_ = p) < end_ ? *p++ : 0; + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : 0; + } + // exponential part + if (c == 'e' || c == 'E') { + c = (current_ = p) < end_ ? *p++ : 0; + if (c == '+' || c == '-') + c = (current_ = p) < end_ ? *p++ : 0; + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : 0; + } +} + +bool Reader::readString() { + Char c = 0; + while (current_ != end_) { + c = getNextChar(); + if (c == '\\') + getNextChar(); + else if (c == '"') + break; + } + return c == '"'; +} + +bool Reader::readObject(Token& tokenStart) { + Token tokenName; + JSONCPP_STRING name; + Value init(objectValue); + currentValue().swapPayload(init); + currentValue().setOffsetStart(tokenStart.start_ - begin_); + while (readToken(tokenName)) { + bool initialTokenOk = true; + while (tokenName.type_ == tokenComment && initialTokenOk) + initialTokenOk = readToken(tokenName); + if (!initialTokenOk) + break; + if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object + return true; + name = ""; + if (tokenName.type_ == tokenString) { + if (!decodeString(tokenName, name)) + return recoverFromError(tokenObjectEnd); + } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) { + Value numberName; + if (!decodeNumber(tokenName, numberName)) + return recoverFromError(tokenObjectEnd); + name = JSONCPP_STRING(numberName.asCString()); + } else { + break; + } + + Token colon; + if (!readToken(colon) || colon.type_ != tokenMemberSeparator) { + return addErrorAndRecover( + "Missing ':' after object member name", colon, tokenObjectEnd); + } + Value& value = currentValue()[name]; + nodes_.push(&value); + bool ok = readValue(); + nodes_.pop(); + if (!ok) // error already set + return recoverFromError(tokenObjectEnd); + + Token comma; + if (!readToken(comma) || + (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator && + comma.type_ != tokenComment)) { + return addErrorAndRecover( + "Missing ',' or '}' in object declaration", comma, tokenObjectEnd); + } + bool finalizeTokenOk = true; + while (comma.type_ == tokenComment && finalizeTokenOk) + finalizeTokenOk = readToken(comma); + if (comma.type_ == tokenObjectEnd) + return true; + } + return addErrorAndRecover( + "Missing '}' or object member name", tokenName, tokenObjectEnd); +} + +bool Reader::readArray(Token& tokenStart) { + Value init(arrayValue); + currentValue().swapPayload(init); + currentValue().setOffsetStart(tokenStart.start_ - begin_); + skipSpaces(); + if (*current_ == ']') // empty array + { + Token endArray; + readToken(endArray); + return true; + } + int index = 0; + for (;;) { + Value& value = currentValue()[index++]; + nodes_.push(&value); + bool ok = readValue(); + nodes_.pop(); + if (!ok) // error already set + return recoverFromError(tokenArrayEnd); + + Token token; + // Accept Comment after last item in the array. + ok = readToken(token); + while (token.type_ == tokenComment && ok) { + ok = readToken(token); + } + bool badTokenType = + (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd); + if (!ok || badTokenType) { + return addErrorAndRecover( + "Missing ',' or ']' in array declaration", token, tokenArrayEnd); + } + if (token.type_ == tokenArrayEnd) + break; + } + return true; +} + +bool Reader::decodeNumber(Token& token) { + Value decoded; + if (!decodeNumber(token, decoded)) + return false; + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool Reader::decodeNumber(Token& token, Value& decoded) { + // Attempts to parse the number as an integer. If the number is + // larger than the maximum supported value of an integer then + // we decode the number as a double. + Location current = token.start_; + bool isNegative = *current == '-'; + if (isNegative) + ++current; + // TODO: Help the compiler do the div and mod at compile time or get rid of them. + Value::LargestUInt maxIntegerValue = + isNegative ? Value::LargestUInt(Value::maxLargestInt) + 1 + : Value::maxLargestUInt; + Value::LargestUInt threshold = maxIntegerValue / 10; + Value::LargestUInt value = 0; + while (current < token.end_) { + Char c = *current++; + if (c < '0' || c > '9') + return decodeDouble(token, decoded); + Value::UInt digit(static_cast(c - '0')); + if (value >= threshold) { + // We've hit or exceeded the max value divided by 10 (rounded down). If + // a) we've only just touched the limit, b) this is the last digit, and + // c) it's small enough to fit in that rounding delta, we're okay. + // Otherwise treat this number as a double to avoid overflow. + if (value > threshold || current != token.end_ || + digit > maxIntegerValue % 10) { + return decodeDouble(token, decoded); + } + } + value = value * 10 + digit; + } + if (isNegative && value == maxIntegerValue) + decoded = Value::minLargestInt; + else if (isNegative) + decoded = -Value::LargestInt(value); + else if (value <= Value::LargestUInt(Value::maxInt)) + decoded = Value::LargestInt(value); + else + decoded = value; + return true; +} + +bool Reader::decodeDouble(Token& token) { + Value decoded; + if (!decodeDouble(token, decoded)) + return false; + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool Reader::decodeDouble(Token& token, Value& decoded) { + double value = 0; + JSONCPP_STRING buffer(token.start_, token.end_); + JSONCPP_ISTRINGSTREAM is(buffer); + if (!(is >> value)) + return addError("'" + JSONCPP_STRING(token.start_, token.end_) + + "' is not a number.", + token); + decoded = value; + return true; +} + +bool Reader::decodeString(Token& token) { + JSONCPP_STRING decoded_string; + if (!decodeString(token, decoded_string)) + return false; + Value decoded(decoded_string); + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool Reader::decodeString(Token& token, JSONCPP_STRING& decoded) { + decoded.reserve(static_cast(token.end_ - token.start_ - 2)); + Location current = token.start_ + 1; // skip '"' + Location end = token.end_ - 1; // do not include '"' + while (current != end) { + Char c = *current++; + if (c == '"') + break; + else if (c == '\\') { + if (current == end) + return addError("Empty escape sequence in string", token, current); + Char escape = *current++; + switch (escape) { + case '"': + decoded += '"'; + break; + case '/': + decoded += '/'; + break; + case '\\': + decoded += '\\'; + break; + case 'b': + decoded += '\b'; + break; + case 'f': + decoded += '\f'; + break; + case 'n': + decoded += '\n'; + break; + case 'r': + decoded += '\r'; + break; + case 't': + decoded += '\t'; + break; + case 'u': { + unsigned int unicode; + if (!decodeUnicodeCodePoint(token, current, end, unicode)) + return false; + decoded += codePointToUTF8(unicode); + } break; + default: + return addError("Bad escape sequence in string", token, current); + } + } else { + decoded += c; + } + } + return true; +} + +bool Reader::decodeUnicodeCodePoint(Token& token, + Location& current, + Location end, + unsigned int& unicode) { + + if (!decodeUnicodeEscapeSequence(token, current, end, unicode)) + return false; + if (unicode >= 0xD800 && unicode <= 0xDBFF) { + // surrogate pairs + if (end - current < 6) + return addError( + "additional six characters expected to parse unicode surrogate pair.", + token, + current); + unsigned int surrogatePair; + if (*(current++) == '\\' && *(current++) == 'u') { + if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) { + unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF); + } else + return false; + } else + return addError("expecting another \\u token to begin the second half of " + "a unicode surrogate pair", + token, + current); + } + return true; +} + +bool Reader::decodeUnicodeEscapeSequence(Token& token, + Location& current, + Location end, + unsigned int& ret_unicode) { + if (end - current < 4) + return addError( + "Bad unicode escape sequence in string: four digits expected.", + token, + current); + int unicode = 0; + for (int index = 0; index < 4; ++index) { + Char c = *current++; + unicode *= 16; + if (c >= '0' && c <= '9') + unicode += c - '0'; + else if (c >= 'a' && c <= 'f') + unicode += c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + unicode += c - 'A' + 10; + else + return addError( + "Bad unicode escape sequence in string: hexadecimal digit expected.", + token, + current); + } + ret_unicode = static_cast(unicode); + return true; +} + +bool +Reader::addError(const JSONCPP_STRING& message, Token& token, Location extra) { + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = extra; + errors_.push_back(info); + return false; +} + +bool Reader::recoverFromError(TokenType skipUntilToken) { + size_t const errorCount = errors_.size(); + Token skip; + for (;;) { + if (!readToken(skip)) + errors_.resize(errorCount); // discard errors caused by recovery + if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream) + break; + } + errors_.resize(errorCount); + return false; +} + +bool Reader::addErrorAndRecover(const JSONCPP_STRING& message, + Token& token, + TokenType skipUntilToken) { + addError(message, token); + return recoverFromError(skipUntilToken); +} + +Value& Reader::currentValue() { return *(nodes_.top()); } + +Reader::Char Reader::getNextChar() { + if (current_ == end_) + return 0; + return *current_++; +} + +void Reader::getLocationLineAndColumn(Location location, + int& line, + int& column) const { + Location current = begin_; + Location lastLineStart = current; + line = 0; + while (current < location && current != end_) { + Char c = *current++; + if (c == '\r') { + if (*current == '\n') + ++current; + lastLineStart = current; + ++line; + } else if (c == '\n') { + lastLineStart = current; + ++line; + } + } + // column & line start at 1 + column = int(location - lastLineStart) + 1; + ++line; +} + +JSONCPP_STRING Reader::getLocationLineAndColumn(Location location) const { + int line, column; + getLocationLineAndColumn(location, line, column); + char buffer[18 + 16 + 16 + 1]; + snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column); + return buffer; +} + +// Deprecated. Preserved for backward compatibility +JSONCPP_STRING Reader::getFormatedErrorMessages() const { + return getFormattedErrorMessages(); +} + +JSONCPP_STRING Reader::getFormattedErrorMessages() const { + JSONCPP_STRING formattedMessage; + for (Errors::const_iterator itError = errors_.begin(); + itError != errors_.end(); + ++itError) { + const ErrorInfo& error = *itError; + formattedMessage += + "* " + getLocationLineAndColumn(error.token_.start_) + "\n"; + formattedMessage += " " + error.message_ + "\n"; + if (error.extra_) + formattedMessage += + "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n"; + } + return formattedMessage; +} + +std::vector Reader::getStructuredErrors() const { + std::vector allErrors; + for (Errors::const_iterator itError = errors_.begin(); + itError != errors_.end(); + ++itError) { + const ErrorInfo& error = *itError; + Reader::StructuredError structured; + structured.offset_start = error.token_.start_ - begin_; + structured.offset_limit = error.token_.end_ - begin_; + structured.message = error.message_; + allErrors.push_back(structured); + } + return allErrors; +} + +bool Reader::pushError(const Value& value, const JSONCPP_STRING& message) { + ptrdiff_t const length = end_ - begin_; + if(value.getOffsetStart() > length + || value.getOffsetLimit() > length) + return false; + Token token; + token.type_ = tokenError; + token.start_ = begin_ + value.getOffsetStart(); + token.end_ = end_ + value.getOffsetLimit(); + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = 0; + errors_.push_back(info); + return true; +} + +bool Reader::pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra) { + ptrdiff_t const length = end_ - begin_; + if(value.getOffsetStart() > length + || value.getOffsetLimit() > length + || extra.getOffsetLimit() > length) + return false; + Token token; + token.type_ = tokenError; + token.start_ = begin_ + value.getOffsetStart(); + token.end_ = begin_ + value.getOffsetLimit(); + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = begin_ + extra.getOffsetStart(); + errors_.push_back(info); + return true; +} + +bool Reader::good() const { + return !errors_.size(); +} + +// exact copy of Features +class OurFeatures { +public: + static OurFeatures all(); + bool allowComments_; + bool strictRoot_; + bool allowDroppedNullPlaceholders_; + bool allowNumericKeys_; + bool allowSingleQuotes_; + bool failIfExtra_; + bool rejectDupKeys_; + bool allowSpecialFloats_; + int stackLimit_; +}; // OurFeatures + +// exact copy of Implementation of class Features +// //////////////////////////////// + +OurFeatures OurFeatures::all() { return OurFeatures(); } + +// Implementation of class Reader +// //////////////////////////////// + +// exact copy of Reader, renamed to OurReader +class OurReader { +public: + typedef char Char; + typedef const Char* Location; + struct StructuredError { + ptrdiff_t offset_start; + ptrdiff_t offset_limit; + JSONCPP_STRING message; + }; + + OurReader(OurFeatures const& features); + bool parse(const char* beginDoc, + const char* endDoc, + Value& root, + bool collectComments = true); + JSONCPP_STRING getFormattedErrorMessages() const; + std::vector getStructuredErrors() const; + bool pushError(const Value& value, const JSONCPP_STRING& message); + bool pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra); + bool good() const; + +private: + OurReader(OurReader const&); // no impl + void operator=(OurReader const&); // no impl + + enum TokenType { + tokenEndOfStream = 0, + tokenObjectBegin, + tokenObjectEnd, + tokenArrayBegin, + tokenArrayEnd, + tokenString, + tokenNumber, + tokenTrue, + tokenFalse, + tokenNull, + tokenNaN, + tokenPosInf, + tokenNegInf, + tokenArraySeparator, + tokenMemberSeparator, + tokenComment, + tokenError + }; + + class Token { + public: + TokenType type_; + Location start_; + Location end_; + }; + + class ErrorInfo { + public: + Token token_; + JSONCPP_STRING message_; + Location extra_; + }; + + typedef std::deque Errors; + + bool readToken(Token& token); + void skipSpaces(); + bool match(Location pattern, int patternLength); + bool readComment(); + bool readCStyleComment(); + bool readCppStyleComment(); + bool readString(); + bool readStringSingleQuote(); + bool readNumber(bool checkInf); + bool readValue(); + bool readObject(Token& token); + bool readArray(Token& token); + bool decodeNumber(Token& token); + bool decodeNumber(Token& token, Value& decoded); + bool decodeString(Token& token); + bool decodeString(Token& token, JSONCPP_STRING& decoded); + bool decodeDouble(Token& token); + bool decodeDouble(Token& token, Value& decoded); + bool decodeUnicodeCodePoint(Token& token, + Location& current, + Location end, + unsigned int& unicode); + bool decodeUnicodeEscapeSequence(Token& token, + Location& current, + Location end, + unsigned int& unicode); + bool addError(const JSONCPP_STRING& message, Token& token, Location extra = 0); + bool recoverFromError(TokenType skipUntilToken); + bool addErrorAndRecover(const JSONCPP_STRING& message, + Token& token, + TokenType skipUntilToken); + void skipUntilSpace(); + Value& currentValue(); + Char getNextChar(); + void + getLocationLineAndColumn(Location location, int& line, int& column) const; + JSONCPP_STRING getLocationLineAndColumn(Location location) const; + void addComment(Location begin, Location end, CommentPlacement placement); + void skipCommentTokens(Token& token); + + typedef std::stack Nodes; + Nodes nodes_; + Errors errors_; + JSONCPP_STRING document_; + Location begin_; + Location end_; + Location current_; + Location lastValueEnd_; + Value* lastValue_; + JSONCPP_STRING commentsBefore_; + int stackDepth_; + + OurFeatures const features_; + bool collectComments_; +}; // OurReader + +// complete copy of Read impl, for OurReader + +OurReader::OurReader(OurFeatures const& features) + : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(), + lastValue_(), commentsBefore_(), + stackDepth_(0), + features_(features), collectComments_() { +} + +bool OurReader::parse(const char* beginDoc, + const char* endDoc, + Value& root, + bool collectComments) { + if (!features_.allowComments_) { + collectComments = false; + } + + begin_ = beginDoc; + end_ = endDoc; + collectComments_ = collectComments; + current_ = begin_; + lastValueEnd_ = 0; + lastValue_ = 0; + commentsBefore_ = ""; + errors_.clear(); + while (!nodes_.empty()) + nodes_.pop(); + nodes_.push(&root); + + stackDepth_ = 0; + bool successful = readValue(); + Token token; + skipCommentTokens(token); + if (features_.failIfExtra_) { + if (token.type_ != tokenError && token.type_ != tokenEndOfStream) { + addError("Extra non-whitespace after JSON value.", token); + return false; + } + } + if (collectComments_ && !commentsBefore_.empty()) + root.setComment(commentsBefore_, commentAfter); + if (features_.strictRoot_) { + if (!root.isArray() && !root.isObject()) { + // Set error location to start of doc, ideally should be first token found + // in doc + token.type_ = tokenError; + token.start_ = beginDoc; + token.end_ = endDoc; + addError( + "A valid JSON document must be either an array or an object value.", + token); + return false; + } + } + return successful; +} + +bool OurReader::readValue() { + if (stackDepth_ >= features_.stackLimit_) throwRuntimeError("Exceeded stackLimit in readValue()."); + ++stackDepth_; + Token token; + skipCommentTokens(token); + bool successful = true; + + if (collectComments_ && !commentsBefore_.empty()) { + currentValue().setComment(commentsBefore_, commentBefore); + commentsBefore_ = ""; + } + + switch (token.type_) { + case tokenObjectBegin: + successful = readObject(token); + currentValue().setOffsetLimit(current_ - begin_); + break; + case tokenArrayBegin: + successful = readArray(token); + currentValue().setOffsetLimit(current_ - begin_); + break; + case tokenNumber: + successful = decodeNumber(token); + break; + case tokenString: + successful = decodeString(token); + break; + case tokenTrue: + { + Value v(true); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenFalse: + { + Value v(false); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenNull: + { + Value v; + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenNaN: + { + Value v(std::numeric_limits::quiet_NaN()); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenPosInf: + { + Value v(std::numeric_limits::infinity()); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenNegInf: + { + Value v(-std::numeric_limits::infinity()); + currentValue().swapPayload(v); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + } + break; + case tokenArraySeparator: + case tokenObjectEnd: + case tokenArrayEnd: + if (features_.allowDroppedNullPlaceholders_) { + // "Un-read" the current token and mark the current value as a null + // token. + current_--; + Value v; + currentValue().swapPayload(v); + currentValue().setOffsetStart(current_ - begin_ - 1); + currentValue().setOffsetLimit(current_ - begin_); + break; + } // else, fall through ... + default: + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return addError("Syntax error: value, object or array expected.", token); + } + + if (collectComments_) { + lastValueEnd_ = current_; + lastValue_ = ¤tValue(); + } + + --stackDepth_; + return successful; +} + +void OurReader::skipCommentTokens(Token& token) { + if (features_.allowComments_) { + do { + readToken(token); + } while (token.type_ == tokenComment); + } else { + readToken(token); + } +} + +bool OurReader::readToken(Token& token) { + skipSpaces(); + token.start_ = current_; + Char c = getNextChar(); + bool ok = true; + switch (c) { + case '{': + token.type_ = tokenObjectBegin; + break; + case '}': + token.type_ = tokenObjectEnd; + break; + case '[': + token.type_ = tokenArrayBegin; + break; + case ']': + token.type_ = tokenArrayEnd; + break; + case '"': + token.type_ = tokenString; + ok = readString(); + break; + case '\'': + if (features_.allowSingleQuotes_) { + token.type_ = tokenString; + ok = readStringSingleQuote(); + break; + } // else continue + case '/': + token.type_ = tokenComment; + ok = readComment(); + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + token.type_ = tokenNumber; + readNumber(false); + break; + case '-': + if (readNumber(true)) { + token.type_ = tokenNumber; + } else { + token.type_ = tokenNegInf; + ok = features_.allowSpecialFloats_ && match("nfinity", 7); + } + break; + case 't': + token.type_ = tokenTrue; + ok = match("rue", 3); + break; + case 'f': + token.type_ = tokenFalse; + ok = match("alse", 4); + break; + case 'n': + token.type_ = tokenNull; + ok = match("ull", 3); + break; + case 'N': + if (features_.allowSpecialFloats_) { + token.type_ = tokenNaN; + ok = match("aN", 2); + } else { + ok = false; + } + break; + case 'I': + if (features_.allowSpecialFloats_) { + token.type_ = tokenPosInf; + ok = match("nfinity", 7); + } else { + ok = false; + } + break; + case ',': + token.type_ = tokenArraySeparator; + break; + case ':': + token.type_ = tokenMemberSeparator; + break; + case 0: + token.type_ = tokenEndOfStream; + break; + default: + ok = false; + break; + } + if (!ok) + token.type_ = tokenError; + token.end_ = current_; + return true; +} + +void OurReader::skipSpaces() { + while (current_ != end_) { + Char c = *current_; + if (c == ' ' || c == '\t' || c == '\r' || c == '\n') + ++current_; + else + break; + } +} + +bool OurReader::match(Location pattern, int patternLength) { + if (end_ - current_ < patternLength) + return false; + int index = patternLength; + while (index--) + if (current_[index] != pattern[index]) + return false; + current_ += patternLength; + return true; +} + +bool OurReader::readComment() { + Location commentBegin = current_ - 1; + Char c = getNextChar(); + bool successful = false; + if (c == '*') + successful = readCStyleComment(); + else if (c == '/') + successful = readCppStyleComment(); + if (!successful) + return false; + + if (collectComments_) { + CommentPlacement placement = commentBefore; + if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) { + if (c != '*' || !containsNewLine(commentBegin, current_)) + placement = commentAfterOnSameLine; + } + + addComment(commentBegin, current_, placement); + } + return true; +} + +void +OurReader::addComment(Location begin, Location end, CommentPlacement placement) { + assert(collectComments_); + const JSONCPP_STRING& normalized = normalizeEOL(begin, end); + if (placement == commentAfterOnSameLine) { + assert(lastValue_ != 0); + lastValue_->setComment(normalized, placement); + } else { + commentsBefore_ += normalized; + } +} + +bool OurReader::readCStyleComment() { + while (current_ != end_) { + Char c = getNextChar(); + if (c == '*' && *current_ == '/') + break; + } + return getNextChar() == '/'; +} + +bool OurReader::readCppStyleComment() { + while (current_ != end_) { + Char c = getNextChar(); + if (c == '\n') + break; + if (c == '\r') { + // Consume DOS EOL. It will be normalized in addComment. + if (current_ != end_ && *current_ == '\n') + getNextChar(); + // Break on Moc OS 9 EOL. + break; + } + } + return true; +} + +bool OurReader::readNumber(bool checkInf) { + const char *p = current_; + if (checkInf && p != end_ && *p == 'I') { + current_ = ++p; + return false; + } + char c = '0'; // stopgap for already consumed character + // integral part + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : 0; + // fractional part + if (c == '.') { + c = (current_ = p) < end_ ? *p++ : 0; + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : 0; + } + // exponential part + if (c == 'e' || c == 'E') { + c = (current_ = p) < end_ ? *p++ : 0; + if (c == '+' || c == '-') + c = (current_ = p) < end_ ? *p++ : 0; + while (c >= '0' && c <= '9') + c = (current_ = p) < end_ ? *p++ : 0; + } + return true; +} +bool OurReader::readString() { + Char c = 0; + while (current_ != end_) { + c = getNextChar(); + if (c == '\\') + getNextChar(); + else if (c == '"') + break; + } + return c == '"'; +} + + +bool OurReader::readStringSingleQuote() { + Char c = 0; + while (current_ != end_) { + c = getNextChar(); + if (c == '\\') + getNextChar(); + else if (c == '\'') + break; + } + return c == '\''; +} + +bool OurReader::readObject(Token& tokenStart) { + Token tokenName; + JSONCPP_STRING name; + Value init(objectValue); + currentValue().swapPayload(init); + currentValue().setOffsetStart(tokenStart.start_ - begin_); + while (readToken(tokenName)) { + bool initialTokenOk = true; + while (tokenName.type_ == tokenComment && initialTokenOk) + initialTokenOk = readToken(tokenName); + if (!initialTokenOk) + break; + if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object + return true; + name = ""; + if (tokenName.type_ == tokenString) { + if (!decodeString(tokenName, name)) + return recoverFromError(tokenObjectEnd); + } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) { + Value numberName; + if (!decodeNumber(tokenName, numberName)) + return recoverFromError(tokenObjectEnd); + name = numberName.asString(); + } else { + break; + } + + Token colon; + if (!readToken(colon) || colon.type_ != tokenMemberSeparator) { + return addErrorAndRecover( + "Missing ':' after object member name", colon, tokenObjectEnd); + } + if (name.length() >= (1U<<30)) throwRuntimeError("keylength >= 2^30"); + if (features_.rejectDupKeys_ && currentValue().isMember(name)) { + JSONCPP_STRING msg = "Duplicate key: '" + name + "'"; + return addErrorAndRecover( + msg, tokenName, tokenObjectEnd); + } + Value& value = currentValue()[name]; + nodes_.push(&value); + bool ok = readValue(); + nodes_.pop(); + if (!ok) // error already set + return recoverFromError(tokenObjectEnd); + + Token comma; + if (!readToken(comma) || + (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator && + comma.type_ != tokenComment)) { + return addErrorAndRecover( + "Missing ',' or '}' in object declaration", comma, tokenObjectEnd); + } + bool finalizeTokenOk = true; + while (comma.type_ == tokenComment && finalizeTokenOk) + finalizeTokenOk = readToken(comma); + if (comma.type_ == tokenObjectEnd) + return true; + } + return addErrorAndRecover( + "Missing '}' or object member name", tokenName, tokenObjectEnd); +} + +bool OurReader::readArray(Token& tokenStart) { + Value init(arrayValue); + currentValue().swapPayload(init); + currentValue().setOffsetStart(tokenStart.start_ - begin_); + skipSpaces(); + if (*current_ == ']') // empty array + { + Token endArray; + readToken(endArray); + return true; + } + int index = 0; + for (;;) { + Value& value = currentValue()[index++]; + nodes_.push(&value); + bool ok = readValue(); + nodes_.pop(); + if (!ok) // error already set + return recoverFromError(tokenArrayEnd); + + Token token; + // Accept Comment after last item in the array. + ok = readToken(token); + while (token.type_ == tokenComment && ok) { + ok = readToken(token); + } + bool badTokenType = + (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd); + if (!ok || badTokenType) { + return addErrorAndRecover( + "Missing ',' or ']' in array declaration", token, tokenArrayEnd); + } + if (token.type_ == tokenArrayEnd) + break; + } + return true; +} + +bool OurReader::decodeNumber(Token& token) { + Value decoded; + if (!decodeNumber(token, decoded)) + return false; + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool OurReader::decodeNumber(Token& token, Value& decoded) { + // Attempts to parse the number as an integer. If the number is + // larger than the maximum supported value of an integer then + // we decode the number as a double. + Location current = token.start_; + bool isNegative = *current == '-'; + if (isNegative) + ++current; + // TODO: Help the compiler do the div and mod at compile time or get rid of them. + Value::LargestUInt maxIntegerValue = + isNegative ? Value::LargestUInt(-Value::minLargestInt) + : Value::maxLargestUInt; + Value::LargestUInt threshold = maxIntegerValue / 10; + Value::LargestUInt value = 0; + while (current < token.end_) { + Char c = *current++; + if (c < '0' || c > '9') + return decodeDouble(token, decoded); + Value::UInt digit(static_cast(c - '0')); + if (value >= threshold) { + // We've hit or exceeded the max value divided by 10 (rounded down). If + // a) we've only just touched the limit, b) this is the last digit, and + // c) it's small enough to fit in that rounding delta, we're okay. + // Otherwise treat this number as a double to avoid overflow. + if (value > threshold || current != token.end_ || + digit > maxIntegerValue % 10) { + return decodeDouble(token, decoded); + } + } + value = value * 10 + digit; + } + if (isNegative) + decoded = -Value::LargestInt(value); + else if (value <= Value::LargestUInt(Value::maxInt)) + decoded = Value::LargestInt(value); + else + decoded = value; + return true; +} + +bool OurReader::decodeDouble(Token& token) { + Value decoded; + if (!decodeDouble(token, decoded)) + return false; + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool OurReader::decodeDouble(Token& token, Value& decoded) { + double value = 0; + const int bufferSize = 32; + int count; + ptrdiff_t const length = token.end_ - token.start_; + + // Sanity check to avoid buffer overflow exploits. + if (length < 0) { + return addError("Unable to parse token length", token); + } + size_t const ulength = static_cast(length); + + // Avoid using a string constant for the format control string given to + // sscanf, as this can cause hard to debug crashes on OS X. See here for more + // info: + // + // http://developer.apple.com/library/mac/#DOCUMENTATION/DeveloperTools/gcc-4.0.1/gcc/Incompatibilities.html + char format[] = "%lf"; + + if (length <= bufferSize) { + Char buffer[bufferSize + 1]; + memcpy(buffer, token.start_, ulength); + buffer[length] = 0; + count = sscanf(buffer, format, &value); + } else { + JSONCPP_STRING buffer(token.start_, token.end_); + count = sscanf(buffer.c_str(), format, &value); + } + + if (count != 1) + return addError("'" + JSONCPP_STRING(token.start_, token.end_) + + "' is not a number.", + token); + decoded = value; + return true; +} + +bool OurReader::decodeString(Token& token) { + JSONCPP_STRING decoded_string; + if (!decodeString(token, decoded_string)) + return false; + Value decoded(decoded_string); + currentValue().swapPayload(decoded); + currentValue().setOffsetStart(token.start_ - begin_); + currentValue().setOffsetLimit(token.end_ - begin_); + return true; +} + +bool OurReader::decodeString(Token& token, JSONCPP_STRING& decoded) { + decoded.reserve(static_cast(token.end_ - token.start_ - 2)); + Location current = token.start_ + 1; // skip '"' + Location end = token.end_ - 1; // do not include '"' + while (current != end) { + Char c = *current++; + if (c == '"') + break; + else if (c == '\\') { + if (current == end) + return addError("Empty escape sequence in string", token, current); + Char escape = *current++; + switch (escape) { + case '"': + decoded += '"'; + break; + case '/': + decoded += '/'; + break; + case '\\': + decoded += '\\'; + break; + case 'b': + decoded += '\b'; + break; + case 'f': + decoded += '\f'; + break; + case 'n': + decoded += '\n'; + break; + case 'r': + decoded += '\r'; + break; + case 't': + decoded += '\t'; + break; + case 'u': { + unsigned int unicode; + if (!decodeUnicodeCodePoint(token, current, end, unicode)) + return false; + decoded += codePointToUTF8(unicode); + } break; + default: + return addError("Bad escape sequence in string", token, current); + } + } else { + decoded += c; + } + } + return true; +} + +bool OurReader::decodeUnicodeCodePoint(Token& token, + Location& current, + Location end, + unsigned int& unicode) { + + if (!decodeUnicodeEscapeSequence(token, current, end, unicode)) + return false; + if (unicode >= 0xD800 && unicode <= 0xDBFF) { + // surrogate pairs + if (end - current < 6) + return addError( + "additional six characters expected to parse unicode surrogate pair.", + token, + current); + unsigned int surrogatePair; + if (*(current++) == '\\' && *(current++) == 'u') { + if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) { + unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF); + } else + return false; + } else + return addError("expecting another \\u token to begin the second half of " + "a unicode surrogate pair", + token, + current); + } + return true; +} + +bool OurReader::decodeUnicodeEscapeSequence(Token& token, + Location& current, + Location end, + unsigned int& ret_unicode) { + if (end - current < 4) + return addError( + "Bad unicode escape sequence in string: four digits expected.", + token, + current); + int unicode = 0; + for (int index = 0; index < 4; ++index) { + Char c = *current++; + unicode *= 16; + if (c >= '0' && c <= '9') + unicode += c - '0'; + else if (c >= 'a' && c <= 'f') + unicode += c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + unicode += c - 'A' + 10; + else + return addError( + "Bad unicode escape sequence in string: hexadecimal digit expected.", + token, + current); + } + ret_unicode = static_cast(unicode); + return true; +} + +bool +OurReader::addError(const JSONCPP_STRING& message, Token& token, Location extra) { + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = extra; + errors_.push_back(info); + return false; +} + +bool OurReader::recoverFromError(TokenType skipUntilToken) { + size_t errorCount = errors_.size(); + Token skip; + for (;;) { + if (!readToken(skip)) + errors_.resize(errorCount); // discard errors caused by recovery + if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream) + break; + } + errors_.resize(errorCount); + return false; +} + +bool OurReader::addErrorAndRecover(const JSONCPP_STRING& message, + Token& token, + TokenType skipUntilToken) { + addError(message, token); + return recoverFromError(skipUntilToken); +} + +Value& OurReader::currentValue() { return *(nodes_.top()); } + +OurReader::Char OurReader::getNextChar() { + if (current_ == end_) + return 0; + return *current_++; +} + +void OurReader::getLocationLineAndColumn(Location location, + int& line, + int& column) const { + Location current = begin_; + Location lastLineStart = current; + line = 0; + while (current < location && current != end_) { + Char c = *current++; + if (c == '\r') { + if (*current == '\n') + ++current; + lastLineStart = current; + ++line; + } else if (c == '\n') { + lastLineStart = current; + ++line; + } + } + // column & line start at 1 + column = int(location - lastLineStart) + 1; + ++line; +} + +JSONCPP_STRING OurReader::getLocationLineAndColumn(Location location) const { + int line, column; + getLocationLineAndColumn(location, line, column); + char buffer[18 + 16 + 16 + 1]; + snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column); + return buffer; +} + +JSONCPP_STRING OurReader::getFormattedErrorMessages() const { + JSONCPP_STRING formattedMessage; + for (Errors::const_iterator itError = errors_.begin(); + itError != errors_.end(); + ++itError) { + const ErrorInfo& error = *itError; + formattedMessage += + "* " + getLocationLineAndColumn(error.token_.start_) + "\n"; + formattedMessage += " " + error.message_ + "\n"; + if (error.extra_) + formattedMessage += + "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n"; + } + return formattedMessage; +} + +std::vector OurReader::getStructuredErrors() const { + std::vector allErrors; + for (Errors::const_iterator itError = errors_.begin(); + itError != errors_.end(); + ++itError) { + const ErrorInfo& error = *itError; + OurReader::StructuredError structured; + structured.offset_start = error.token_.start_ - begin_; + structured.offset_limit = error.token_.end_ - begin_; + structured.message = error.message_; + allErrors.push_back(structured); + } + return allErrors; +} + +bool OurReader::pushError(const Value& value, const JSONCPP_STRING& message) { + ptrdiff_t length = end_ - begin_; + if(value.getOffsetStart() > length + || value.getOffsetLimit() > length) + return false; + Token token; + token.type_ = tokenError; + token.start_ = begin_ + value.getOffsetStart(); + token.end_ = end_ + value.getOffsetLimit(); + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = 0; + errors_.push_back(info); + return true; +} + +bool OurReader::pushError(const Value& value, const JSONCPP_STRING& message, const Value& extra) { + ptrdiff_t length = end_ - begin_; + if(value.getOffsetStart() > length + || value.getOffsetLimit() > length + || extra.getOffsetLimit() > length) + return false; + Token token; + token.type_ = tokenError; + token.start_ = begin_ + value.getOffsetStart(); + token.end_ = begin_ + value.getOffsetLimit(); + ErrorInfo info; + info.token_ = token; + info.message_ = message; + info.extra_ = begin_ + extra.getOffsetStart(); + errors_.push_back(info); + return true; +} + +bool OurReader::good() const { + return !errors_.size(); +} + + +class OurCharReader : public CharReader { + bool const collectComments_; + OurReader reader_; +public: + OurCharReader( + bool collectComments, + OurFeatures const& features) + : collectComments_(collectComments) + , reader_(features) + {} + bool parse( + char const* beginDoc, char const* endDoc, + Value* root, JSONCPP_STRING* errs) JSONCPP_OVERRIDE { + bool ok = reader_.parse(beginDoc, endDoc, *root, collectComments_); + if (errs) { + *errs = reader_.getFormattedErrorMessages(); + } + return ok; + } +}; + +CharReaderBuilder::CharReaderBuilder() +{ + setDefaults(&settings_); +} +CharReaderBuilder::~CharReaderBuilder() +{} +CharReader* CharReaderBuilder::newCharReader() const +{ + bool collectComments = settings_["collectComments"].asBool(); + OurFeatures features = OurFeatures::all(); + features.allowComments_ = settings_["allowComments"].asBool(); + features.strictRoot_ = settings_["strictRoot"].asBool(); + features.allowDroppedNullPlaceholders_ = settings_["allowDroppedNullPlaceholders"].asBool(); + features.allowNumericKeys_ = settings_["allowNumericKeys"].asBool(); + features.allowSingleQuotes_ = settings_["allowSingleQuotes"].asBool(); + features.stackLimit_ = settings_["stackLimit"].asInt(); + features.failIfExtra_ = settings_["failIfExtra"].asBool(); + features.rejectDupKeys_ = settings_["rejectDupKeys"].asBool(); + features.allowSpecialFloats_ = settings_["allowSpecialFloats"].asBool(); + return new OurCharReader(collectComments, features); +} +static void getValidReaderKeys(std::set* valid_keys) +{ + valid_keys->clear(); + valid_keys->insert("collectComments"); + valid_keys->insert("allowComments"); + valid_keys->insert("strictRoot"); + valid_keys->insert("allowDroppedNullPlaceholders"); + valid_keys->insert("allowNumericKeys"); + valid_keys->insert("allowSingleQuotes"); + valid_keys->insert("stackLimit"); + valid_keys->insert("failIfExtra"); + valid_keys->insert("rejectDupKeys"); + valid_keys->insert("allowSpecialFloats"); +} +bool CharReaderBuilder::validate(Json::Value* invalid) const +{ + Json::Value my_invalid; + if (!invalid) invalid = &my_invalid; // so we do not need to test for NULL + Json::Value& inv = *invalid; + std::set valid_keys; + getValidReaderKeys(&valid_keys); + Value::Members keys = settings_.getMemberNames(); + size_t n = keys.size(); + for (size_t i = 0; i < n; ++i) { + JSONCPP_STRING const& key = keys[i]; + if (valid_keys.find(key) == valid_keys.end()) { + inv[key] = settings_[key]; + } + } + return 0u == inv.size(); +} +Value& CharReaderBuilder::operator[](JSONCPP_STRING key) +{ + return settings_[key]; +} +// static +void CharReaderBuilder::strictMode(Json::Value* settings) +{ +//! [CharReaderBuilderStrictMode] + (*settings)["allowComments"] = false; + (*settings)["strictRoot"] = true; + (*settings)["allowDroppedNullPlaceholders"] = false; + (*settings)["allowNumericKeys"] = false; + (*settings)["allowSingleQuotes"] = false; + (*settings)["stackLimit"] = 1000; + (*settings)["failIfExtra"] = true; + (*settings)["rejectDupKeys"] = true; + (*settings)["allowSpecialFloats"] = false; +//! [CharReaderBuilderStrictMode] +} +// static +void CharReaderBuilder::setDefaults(Json::Value* settings) +{ +//! [CharReaderBuilderDefaults] + (*settings)["collectComments"] = true; + (*settings)["allowComments"] = true; + (*settings)["strictRoot"] = false; + (*settings)["allowDroppedNullPlaceholders"] = false; + (*settings)["allowNumericKeys"] = false; + (*settings)["allowSingleQuotes"] = false; + (*settings)["stackLimit"] = 1000; + (*settings)["failIfExtra"] = false; + (*settings)["rejectDupKeys"] = false; + (*settings)["allowSpecialFloats"] = false; +//! [CharReaderBuilderDefaults] +} + +////////////////////////////////// +// global functions + +bool parseFromStream( + CharReader::Factory const& fact, JSONCPP_ISTREAM& sin, + Value* root, JSONCPP_STRING* errs) +{ + JSONCPP_OSTRINGSTREAM ssin; + ssin << sin.rdbuf(); + JSONCPP_STRING doc = ssin.str(); + char const* begin = doc.data(); + char const* end = begin + doc.size(); + // Note that we do not actually need a null-terminator. + CharReaderPtr const reader(fact.newCharReader()); + return reader->parse(begin, end, root, errs); +} + +JSONCPP_ISTREAM& operator>>(JSONCPP_ISTREAM& sin, Value& root) { + CharReaderBuilder b; + JSONCPP_STRING errs; + bool ok = parseFromStream(b, sin, &root, &errs); + if (!ok) { + fprintf(stderr, + "Error from reader: %s", + errs.c_str()); + + throwRuntimeError(errs); + } + return sin; +} + +} // namespace Json + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: src/lib_json/json_reader.cpp +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: src/lib_json/json_valueiterator.inl +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2007-2010 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +// included by json_value.cpp + +namespace Json { + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class ValueIteratorBase +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +ValueIteratorBase::ValueIteratorBase() + : current_(), isNull_(true) { +} + +ValueIteratorBase::ValueIteratorBase( + const Value::ObjectValues::iterator& current) + : current_(current), isNull_(false) {} + +Value& ValueIteratorBase::deref() const { + return current_->second; +} + +void ValueIteratorBase::increment() { + ++current_; +} + +void ValueIteratorBase::decrement() { + --current_; +} + +ValueIteratorBase::difference_type +ValueIteratorBase::computeDistance(const SelfType& other) const { +#ifdef JSON_USE_CPPTL_SMALLMAP + return other.current_ - current_; +#else + // Iterator for null value are initialized using the default + // constructor, which initialize current_ to the default + // std::map::iterator. As begin() and end() are two instance + // of the default std::map::iterator, they can not be compared. + // To allow this, we handle this comparison specifically. + if (isNull_ && other.isNull_) { + return 0; + } + + // Usage of std::distance is not portable (does not compile with Sun Studio 12 + // RogueWave STL, + // which is the one used by default). + // Using a portable hand-made version for non random iterator instead: + // return difference_type( std::distance( current_, other.current_ ) ); + difference_type myDistance = 0; + for (Value::ObjectValues::iterator it = current_; it != other.current_; + ++it) { + ++myDistance; + } + return myDistance; +#endif +} + +bool ValueIteratorBase::isEqual(const SelfType& other) const { + if (isNull_) { + return other.isNull_; + } + return current_ == other.current_; +} + +void ValueIteratorBase::copy(const SelfType& other) { + current_ = other.current_; + isNull_ = other.isNull_; +} + +Value ValueIteratorBase::key() const { + const Value::CZString czstring = (*current_).first; + if (czstring.data()) { + if (czstring.isStaticString()) + return Value(StaticString(czstring.data())); + return Value(czstring.data(), czstring.data() + czstring.length()); + } + return Value(czstring.index()); +} + +UInt ValueIteratorBase::index() const { + const Value::CZString czstring = (*current_).first; + if (!czstring.data()) + return czstring.index(); + return Value::UInt(-1); +} + +JSONCPP_STRING ValueIteratorBase::name() const { + char const* keey; + char const* end; + keey = memberName(&end); + if (!keey) return JSONCPP_STRING(); + return JSONCPP_STRING(keey, end); +} + +char const* ValueIteratorBase::memberName() const { + const char* cname = (*current_).first.data(); + return cname ? cname : ""; +} + +char const* ValueIteratorBase::memberName(char const** end) const { + const char* cname = (*current_).first.data(); + if (!cname) { + *end = NULL; + return NULL; + } + *end = cname + (*current_).first.length(); + return cname; +} + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class ValueConstIterator +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +ValueConstIterator::ValueConstIterator() {} + +ValueConstIterator::ValueConstIterator( + const Value::ObjectValues::iterator& current) + : ValueIteratorBase(current) {} + +ValueConstIterator::ValueConstIterator(ValueIterator const& other) + : ValueIteratorBase(other) {} + +ValueConstIterator& ValueConstIterator:: +operator=(const ValueIteratorBase& other) { + copy(other); + return *this; +} + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class ValueIterator +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +ValueIterator::ValueIterator() {} + +ValueIterator::ValueIterator(const Value::ObjectValues::iterator& current) + : ValueIteratorBase(current) {} + +ValueIterator::ValueIterator(const ValueConstIterator& other) + : ValueIteratorBase(other) { + throwRuntimeError("ConstIterator to Iterator should never be allowed."); +} + +ValueIterator::ValueIterator(const ValueIterator& other) + : ValueIteratorBase(other) {} + +ValueIterator& ValueIterator::operator=(const SelfType& other) { + copy(other); + return *this; +} + +} // namespace Json + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: src/lib_json/json_valueiterator.inl +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: src/lib_json/json_value.cpp +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2011 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include +#endif // if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include +#include +#include +#ifdef JSON_USE_CPPTL +#include +#endif +#include // size_t +#include // min() + +#define JSON_ASSERT_UNREACHABLE assert(false) + +namespace Json { + +// This is a walkaround to avoid the static initialization of Value::null. +// kNull must be word-aligned to avoid crashing on ARM. We use an alignment of +// 8 (instead of 4) as a bit of future-proofing. +#if defined(__ARMEL__) +#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment))) +#else +#define ALIGNAS(byte_alignment) +#endif +static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 }; +const unsigned char& kNullRef = kNull[0]; +const Value& Value::null = reinterpret_cast(kNullRef); +const Value& Value::nullRef = null; + +const Int Value::minInt = Int(~(UInt(-1) / 2)); +const Int Value::maxInt = Int(UInt(-1) / 2); +const UInt Value::maxUInt = UInt(-1); +#if defined(JSON_HAS_INT64) +const Int64 Value::minInt64 = Int64(~(UInt64(-1) / 2)); +const Int64 Value::maxInt64 = Int64(UInt64(-1) / 2); +const UInt64 Value::maxUInt64 = UInt64(-1); +// The constant is hard-coded because some compiler have trouble +// converting Value::maxUInt64 to a double correctly (AIX/xlC). +// Assumes that UInt64 is a 64 bits integer. +static const double maxUInt64AsDouble = 18446744073709551615.0; +#endif // defined(JSON_HAS_INT64) +const LargestInt Value::minLargestInt = LargestInt(~(LargestUInt(-1) / 2)); +const LargestInt Value::maxLargestInt = LargestInt(LargestUInt(-1) / 2); +const LargestUInt Value::maxLargestUInt = LargestUInt(-1); + +#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) +template +static inline bool InRange(double d, T min, U max) { + // The casts can lose precision, but we are looking only for + // an approximate range. Might fail on edge cases though. ~cdunn + //return d >= static_cast(min) && d <= static_cast(max); + return d >= min && d <= max; +} +#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) +static inline double integerToDouble(Json::UInt64 value) { + return static_cast(Int64(value / 2)) * 2.0 + static_cast(Int64(value & 1)); +} + +template static inline double integerToDouble(T value) { + return static_cast(value); +} + +template +static inline bool InRange(double d, T min, U max) { + return d >= integerToDouble(min) && d <= integerToDouble(max); +} +#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + +/** Duplicates the specified string value. + * @param value Pointer to the string to duplicate. Must be zero-terminated if + * length is "unknown". + * @param length Length of the value. if equals to unknown, then it will be + * computed using strlen(value). + * @return Pointer on the duplicate instance of string. + */ +static inline char* duplicateStringValue(const char* value, + size_t length) +{ + // Avoid an integer overflow in the call to malloc below by limiting length + // to a sane value. + if (length >= static_cast(Value::maxInt)) + length = Value::maxInt - 1; + + char* newString = static_cast(malloc(length + 1)); + if (newString == NULL) { + throwRuntimeError( + "in Json::Value::duplicateStringValue(): " + "Failed to allocate string value buffer"); + } + memcpy(newString, value, length); + newString[length] = 0; + return newString; +} + +/* Record the length as a prefix. + */ +static inline char* duplicateAndPrefixStringValue( + const char* value, + unsigned int length) +{ + // Avoid an integer overflow in the call to malloc below by limiting length + // to a sane value. + JSON_ASSERT_MESSAGE(length <= static_cast(Value::maxInt) - sizeof(unsigned) - 1U, + "in Json::Value::duplicateAndPrefixStringValue(): " + "length too big for prefixing"); + unsigned actualLength = length + static_cast(sizeof(unsigned)) + 1U; + char* newString = static_cast(malloc(actualLength)); + if (newString == 0) { + throwRuntimeError( + "in Json::Value::duplicateAndPrefixStringValue(): " + "Failed to allocate string value buffer"); + } + *reinterpret_cast(newString) = length; + memcpy(newString + sizeof(unsigned), value, length); + newString[actualLength - 1U] = 0; // to avoid buffer over-run accidents by users later + return newString; +} +inline static void decodePrefixedString( + bool isPrefixed, char const* prefixed, + unsigned* length, char const** value) +{ + if (!isPrefixed) { + *length = static_cast(strlen(prefixed)); + *value = prefixed; + } else { + *length = *reinterpret_cast(prefixed); + *value = prefixed + sizeof(unsigned); + } +} +/** Free the string duplicated by duplicateStringValue()/duplicateAndPrefixStringValue(). + */ +#if JSONCPP_USING_SECURE_MEMORY +static inline void releasePrefixedStringValue(char* value) { + unsigned length = 0; + char const* valueDecoded; + decodePrefixedString(true, value, &length, &valueDecoded); + size_t const size = sizeof(unsigned) + length + 1U; + memset(value, 0, size); + free(value); +} +static inline void releaseStringValue(char* value, unsigned length) { + // length==0 => we allocated the strings memory + size_t size = (length==0) ? strlen(value) : length; + memset(value, 0, size); + free(value); +} +#else // !JSONCPP_USING_SECURE_MEMORY +static inline void releasePrefixedStringValue(char* value) { + free(value); +} +static inline void releaseStringValue(char* value, unsigned) { + free(value); +} +#endif // JSONCPP_USING_SECURE_MEMORY + +} // namespace Json + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ValueInternals... +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +#if !defined(JSON_IS_AMALGAMATION) + +#include "json_valueiterator.inl" +#endif // if !defined(JSON_IS_AMALGAMATION) + +namespace Json { + +Exception::Exception(JSONCPP_STRING const& msg) + : msg_(msg) +{} +Exception::~Exception() throw() +{} +char const* Exception::what() const throw() +{ + return msg_.c_str(); +} +RuntimeError::RuntimeError(JSONCPP_STRING const& msg) + : Exception(msg) +{} +LogicError::LogicError(JSONCPP_STRING const& msg) + : Exception(msg) +{} +JSONCPP_NORETURN void throwRuntimeError(JSONCPP_STRING const& msg) +{ + throw RuntimeError(msg); +} +JSONCPP_NORETURN void throwLogicError(JSONCPP_STRING const& msg) +{ + throw LogicError(msg); +} + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class Value::CommentInfo +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +Value::CommentInfo::CommentInfo() : comment_(0) +{} + +Value::CommentInfo::~CommentInfo() { + if (comment_) + releaseStringValue(comment_, 0u); +} + +void Value::CommentInfo::setComment(const char* text, size_t len) { + if (comment_) { + releaseStringValue(comment_, 0u); + comment_ = 0; + } + JSON_ASSERT(text != 0); + JSON_ASSERT_MESSAGE( + text[0] == '\0' || text[0] == '/', + "in Json::Value::setComment(): Comments must start with /"); + // It seems that /**/ style comments are acceptable as well. + comment_ = duplicateStringValue(text, len); +} + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class Value::CZString +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +// Notes: policy_ indicates if the string was allocated when +// a string is stored. + +Value::CZString::CZString(ArrayIndex aindex) : cstr_(0), index_(aindex) {} + +Value::CZString::CZString(char const* str, unsigned ulength, DuplicationPolicy allocate) + : cstr_(str) { + // allocate != duplicate + storage_.policy_ = allocate & 0x3; + storage_.length_ = ulength & 0x3FFFFFFF; +} + +Value::CZString::CZString(const CZString& other) { + cstr_ = (other.storage_.policy_ != noDuplication && other.cstr_ != 0 + ? duplicateStringValue(other.cstr_, other.storage_.length_) + : other.cstr_); + storage_.policy_ = static_cast(other.cstr_ + ? (static_cast(other.storage_.policy_) == noDuplication + ? noDuplication : duplicate) + : static_cast(other.storage_.policy_)) & 3U; + storage_.length_ = other.storage_.length_; +} + +#if JSON_HAS_RVALUE_REFERENCES +Value::CZString::CZString(CZString&& other) + : cstr_(other.cstr_), index_(other.index_) { + other.cstr_ = nullptr; +} +#endif + +Value::CZString::~CZString() { + if (cstr_ && storage_.policy_ == duplicate) { + releaseStringValue(const_cast(cstr_), storage_.length_ + 1u); //+1 for null terminating character for sake of completeness but not actually necessary + } +} + +void Value::CZString::swap(CZString& other) { + std::swap(cstr_, other.cstr_); + std::swap(index_, other.index_); +} + +Value::CZString& Value::CZString::operator=(CZString other) { + swap(other); + return *this; +} + +bool Value::CZString::operator<(const CZString& other) const { + if (!cstr_) return index_ < other.index_; + //return strcmp(cstr_, other.cstr_) < 0; + // Assume both are strings. + unsigned this_len = this->storage_.length_; + unsigned other_len = other.storage_.length_; + unsigned min_len = std::min(this_len, other_len); + JSON_ASSERT(this->cstr_ && other.cstr_); + int comp = memcmp(this->cstr_, other.cstr_, min_len); + if (comp < 0) return true; + if (comp > 0) return false; + return (this_len < other_len); +} + +bool Value::CZString::operator==(const CZString& other) const { + if (!cstr_) return index_ == other.index_; + //return strcmp(cstr_, other.cstr_) == 0; + // Assume both are strings. + unsigned this_len = this->storage_.length_; + unsigned other_len = other.storage_.length_; + if (this_len != other_len) return false; + JSON_ASSERT(this->cstr_ && other.cstr_); + int comp = memcmp(this->cstr_, other.cstr_, this_len); + return comp == 0; +} + +ArrayIndex Value::CZString::index() const { return index_; } + +//const char* Value::CZString::c_str() const { return cstr_; } +const char* Value::CZString::data() const { return cstr_; } +unsigned Value::CZString::length() const { return storage_.length_; } +bool Value::CZString::isStaticString() const { return storage_.policy_ == noDuplication; } + +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// class Value::Value +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// +// ////////////////////////////////////////////////////////////////// + +/*! \internal Default constructor initialization must be equivalent to: + * memset( this, 0, sizeof(Value) ) + * This optimization is used in ValueInternalMap fast allocator. + */ +Value::Value(ValueType vtype) { + initBasic(vtype); + switch (vtype) { + case nullValue: + break; + case intValue: + case uintValue: + value_.int_ = 0; + break; + case realValue: + value_.real_ = 0.0; + break; + case stringValue: + value_.string_ = 0; + break; + case arrayValue: + case objectValue: + value_.map_ = new ObjectValues(); + break; + case booleanValue: + value_.bool_ = false; + break; + default: + JSON_ASSERT_UNREACHABLE; + } +} + +Value::Value(Int value) { + initBasic(intValue); + value_.int_ = value; +} + +Value::Value(UInt value) { + initBasic(uintValue); + value_.uint_ = value; +} +#if defined(JSON_HAS_INT64) +Value::Value(Int64 value) { + initBasic(intValue); + value_.int_ = value; +} +Value::Value(UInt64 value) { + initBasic(uintValue); + value_.uint_ = value; +} +#endif // defined(JSON_HAS_INT64) + +Value::Value(double value) { + initBasic(realValue); + value_.real_ = value; +} + +Value::Value(const char* value) { + initBasic(stringValue, true); + value_.string_ = duplicateAndPrefixStringValue(value, static_cast(strlen(value))); +} + +Value::Value(const char* beginValue, const char* endValue) { + initBasic(stringValue, true); + value_.string_ = + duplicateAndPrefixStringValue(beginValue, static_cast(endValue - beginValue)); +} + +Value::Value(const JSONCPP_STRING& value) { + initBasic(stringValue, true); + value_.string_ = + duplicateAndPrefixStringValue(value.data(), static_cast(value.length())); +} + +Value::Value(const StaticString& value) { + initBasic(stringValue); + value_.string_ = const_cast(value.c_str()); +} + +#ifdef JSON_USE_CPPTL +Value::Value(const CppTL::ConstString& value) { + initBasic(stringValue, true); + value_.string_ = duplicateAndPrefixStringValue(value, static_cast(value.length())); +} +#endif + +Value::Value(bool value) { + initBasic(booleanValue); + value_.bool_ = value; +} + +Value::Value(Value const& other) + : type_(other.type_), allocated_(false) + , + comments_(0), start_(other.start_), limit_(other.limit_) +{ + switch (type_) { + case nullValue: + case intValue: + case uintValue: + case realValue: + case booleanValue: + value_ = other.value_; + break; + case stringValue: + if (other.value_.string_ && other.allocated_) { + unsigned len; + char const* str; + decodePrefixedString(other.allocated_, other.value_.string_, + &len, &str); + value_.string_ = duplicateAndPrefixStringValue(str, len); + allocated_ = true; + } else { + value_.string_ = other.value_.string_; + allocated_ = false; + } + break; + case arrayValue: + case objectValue: + value_.map_ = new ObjectValues(*other.value_.map_); + break; + default: + JSON_ASSERT_UNREACHABLE; + } + if (other.comments_) { + comments_ = new CommentInfo[numberOfCommentPlacement]; + for (int comment = 0; comment < numberOfCommentPlacement; ++comment) { + const CommentInfo& otherComment = other.comments_[comment]; + if (otherComment.comment_) + comments_[comment].setComment( + otherComment.comment_, strlen(otherComment.comment_)); + } + } +} + +#if JSON_HAS_RVALUE_REFERENCES +// Move constructor +Value::Value(Value&& other) { + initBasic(nullValue); + swap(other); +} +#endif + +Value::~Value() { + switch (type_) { + case nullValue: + case intValue: + case uintValue: + case realValue: + case booleanValue: + break; + case stringValue: + if (allocated_) + releasePrefixedStringValue(value_.string_); + break; + case arrayValue: + case objectValue: + delete value_.map_; + break; + default: + JSON_ASSERT_UNREACHABLE; + } + + if (comments_) + delete[] comments_; + + value_.uint_ = 0; +} + +Value& Value::operator=(Value other) { + swap(other); + return *this; +} + +void Value::swapPayload(Value& other) { + ValueType temp = type_; + type_ = other.type_; + other.type_ = temp; + std::swap(value_, other.value_); + int temp2 = allocated_; + allocated_ = other.allocated_; + other.allocated_ = temp2 & 0x1; +} + +void Value::swap(Value& other) { + swapPayload(other); + std::swap(comments_, other.comments_); + std::swap(start_, other.start_); + std::swap(limit_, other.limit_); +} + +ValueType Value::type() const { return type_; } + +int Value::compare(const Value& other) const { + if (*this < other) + return -1; + if (*this > other) + return 1; + return 0; +} + +bool Value::operator<(const Value& other) const { + int typeDelta = type_ - other.type_; + if (typeDelta) + return typeDelta < 0 ? true : false; + switch (type_) { + case nullValue: + return false; + case intValue: + return value_.int_ < other.value_.int_; + case uintValue: + return value_.uint_ < other.value_.uint_; + case realValue: + return value_.real_ < other.value_.real_; + case booleanValue: + return value_.bool_ < other.value_.bool_; + case stringValue: + { + if ((value_.string_ == 0) || (other.value_.string_ == 0)) { + if (other.value_.string_) return true; + else return false; + } + unsigned this_len; + unsigned other_len; + char const* this_str; + char const* other_str; + decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); + decodePrefixedString(other.allocated_, other.value_.string_, &other_len, &other_str); + unsigned min_len = std::min(this_len, other_len); + JSON_ASSERT(this_str && other_str); + int comp = memcmp(this_str, other_str, min_len); + if (comp < 0) return true; + if (comp > 0) return false; + return (this_len < other_len); + } + case arrayValue: + case objectValue: { + int delta = int(value_.map_->size() - other.value_.map_->size()); + if (delta) + return delta < 0; + return (*value_.map_) < (*other.value_.map_); + } + default: + JSON_ASSERT_UNREACHABLE; + } + return false; // unreachable +} + +bool Value::operator<=(const Value& other) const { return !(other < *this); } + +bool Value::operator>=(const Value& other) const { return !(*this < other); } + +bool Value::operator>(const Value& other) const { return other < *this; } + +bool Value::operator==(const Value& other) const { + // if ( type_ != other.type_ ) + // GCC 2.95.3 says: + // attempt to take address of bit-field structure member `Json::Value::type_' + // Beats me, but a temp solves the problem. + int temp = other.type_; + if (type_ != temp) + return false; + switch (type_) { + case nullValue: + return true; + case intValue: + return value_.int_ == other.value_.int_; + case uintValue: + return value_.uint_ == other.value_.uint_; + case realValue: + return value_.real_ == other.value_.real_; + case booleanValue: + return value_.bool_ == other.value_.bool_; + case stringValue: + { + if ((value_.string_ == 0) || (other.value_.string_ == 0)) { + return (value_.string_ == other.value_.string_); + } + unsigned this_len; + unsigned other_len; + char const* this_str; + char const* other_str; + decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); + decodePrefixedString(other.allocated_, other.value_.string_, &other_len, &other_str); + if (this_len != other_len) return false; + JSON_ASSERT(this_str && other_str); + int comp = memcmp(this_str, other_str, this_len); + return comp == 0; + } + case arrayValue: + case objectValue: + return value_.map_->size() == other.value_.map_->size() && + (*value_.map_) == (*other.value_.map_); + default: + JSON_ASSERT_UNREACHABLE; + } + return false; // unreachable +} + +bool Value::operator!=(const Value& other) const { return !(*this == other); } + +const char* Value::asCString() const { + JSON_ASSERT_MESSAGE(type_ == stringValue, + "in Json::Value::asCString(): requires stringValue"); + if (value_.string_ == 0) return 0; + unsigned this_len; + char const* this_str; + decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); + return this_str; +} + +#if JSONCPP_USING_SECURE_MEMORY +unsigned Value::getCStringLength() const { + JSON_ASSERT_MESSAGE(type_ == stringValue, + "in Json::Value::asCString(): requires stringValue"); + if (value_.string_ == 0) return 0; + unsigned this_len; + char const* this_str; + decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); + return this_len; +} +#endif + +bool Value::getString(char const** str, char const** cend) const { + if (type_ != stringValue) return false; + if (value_.string_ == 0) return false; + unsigned length; + decodePrefixedString(this->allocated_, this->value_.string_, &length, str); + *cend = *str + length; + return true; +} + +JSONCPP_STRING Value::asString() const { + switch (type_) { + case nullValue: + return ""; + case stringValue: + { + if (value_.string_ == 0) return ""; + unsigned this_len; + char const* this_str; + decodePrefixedString(this->allocated_, this->value_.string_, &this_len, &this_str); + return JSONCPP_STRING(this_str, this_len); + } + case booleanValue: + return value_.bool_ ? "true" : "false"; + case intValue: + return valueToString(value_.int_); + case uintValue: + return valueToString(value_.uint_); + case realValue: + return valueToString(value_.real_); + default: + JSON_FAIL_MESSAGE("Type is not convertible to string"); + } +} + +#ifdef JSON_USE_CPPTL +CppTL::ConstString Value::asConstString() const { + unsigned len; + char const* str; + decodePrefixedString(allocated_, value_.string_, + &len, &str); + return CppTL::ConstString(str, len); +} +#endif + +Value::Int Value::asInt() const { + switch (type_) { + case intValue: + JSON_ASSERT_MESSAGE(isInt(), "LargestInt out of Int range"); + return Int(value_.int_); + case uintValue: + JSON_ASSERT_MESSAGE(isInt(), "LargestUInt out of Int range"); + return Int(value_.uint_); + case realValue: + JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt, maxInt), + "double out of Int range"); + return Int(value_.real_); + case nullValue: + return 0; + case booleanValue: + return value_.bool_ ? 1 : 0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to Int."); +} + +Value::UInt Value::asUInt() const { + switch (type_) { + case intValue: + JSON_ASSERT_MESSAGE(isUInt(), "LargestInt out of UInt range"); + return UInt(value_.int_); + case uintValue: + JSON_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range"); + return UInt(value_.uint_); + case realValue: + JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt), + "double out of UInt range"); + return UInt(value_.real_); + case nullValue: + return 0; + case booleanValue: + return value_.bool_ ? 1 : 0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to UInt."); +} + +#if defined(JSON_HAS_INT64) + +Value::Int64 Value::asInt64() const { + switch (type_) { + case intValue: + return Int64(value_.int_); + case uintValue: + JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range"); + return Int64(value_.uint_); + case realValue: + JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt64, maxInt64), + "double out of Int64 range"); + return Int64(value_.real_); + case nullValue: + return 0; + case booleanValue: + return value_.bool_ ? 1 : 0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to Int64."); +} + +Value::UInt64 Value::asUInt64() const { + switch (type_) { + case intValue: + JSON_ASSERT_MESSAGE(isUInt64(), "LargestInt out of UInt64 range"); + return UInt64(value_.int_); + case uintValue: + return UInt64(value_.uint_); + case realValue: + JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt64), + "double out of UInt64 range"); + return UInt64(value_.real_); + case nullValue: + return 0; + case booleanValue: + return value_.bool_ ? 1 : 0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to UInt64."); +} +#endif // if defined(JSON_HAS_INT64) + +LargestInt Value::asLargestInt() const { +#if defined(JSON_NO_INT64) + return asInt(); +#else + return asInt64(); +#endif +} + +LargestUInt Value::asLargestUInt() const { +#if defined(JSON_NO_INT64) + return asUInt(); +#else + return asUInt64(); +#endif +} + +double Value::asDouble() const { + switch (type_) { + case intValue: + return static_cast(value_.int_); + case uintValue: +#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + return static_cast(value_.uint_); +#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + return integerToDouble(value_.uint_); +#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + case realValue: + return value_.real_; + case nullValue: + return 0.0; + case booleanValue: + return value_.bool_ ? 1.0 : 0.0; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to double."); +} + +float Value::asFloat() const { + switch (type_) { + case intValue: + return static_cast(value_.int_); + case uintValue: +#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + return static_cast(value_.uint_); +#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + // This can fail (silently?) if the value is bigger than MAX_FLOAT. + return static_cast(integerToDouble(value_.uint_)); +#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION) + case realValue: + return static_cast(value_.real_); + case nullValue: + return 0.0; + case booleanValue: + return value_.bool_ ? 1.0f : 0.0f; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to float."); +} + +bool Value::asBool() const { + switch (type_) { + case booleanValue: + return value_.bool_; + case nullValue: + return false; + case intValue: + return value_.int_ ? true : false; + case uintValue: + return value_.uint_ ? true : false; + case realValue: + // This is kind of strange. Not recommended. + return (value_.real_ != 0.0) ? true : false; + default: + break; + } + JSON_FAIL_MESSAGE("Value is not convertible to bool."); +} + +bool Value::isConvertibleTo(ValueType other) const { + switch (other) { + case nullValue: + return (isNumeric() && asDouble() == 0.0) || + (type_ == booleanValue && value_.bool_ == false) || + (type_ == stringValue && asString() == "") || + (type_ == arrayValue && value_.map_->size() == 0) || + (type_ == objectValue && value_.map_->size() == 0) || + type_ == nullValue; + case intValue: + return isInt() || + (type_ == realValue && InRange(value_.real_, minInt, maxInt)) || + type_ == booleanValue || type_ == nullValue; + case uintValue: + return isUInt() || + (type_ == realValue && InRange(value_.real_, 0, maxUInt)) || + type_ == booleanValue || type_ == nullValue; + case realValue: + return isNumeric() || type_ == booleanValue || type_ == nullValue; + case booleanValue: + return isNumeric() || type_ == booleanValue || type_ == nullValue; + case stringValue: + return isNumeric() || type_ == booleanValue || type_ == stringValue || + type_ == nullValue; + case arrayValue: + return type_ == arrayValue || type_ == nullValue; + case objectValue: + return type_ == objectValue || type_ == nullValue; + } + JSON_ASSERT_UNREACHABLE; + return false; +} + +/// Number of values in array or object +ArrayIndex Value::size() const { + switch (type_) { + case nullValue: + case intValue: + case uintValue: + case realValue: + case booleanValue: + case stringValue: + return 0; + case arrayValue: // size of the array is highest index + 1 + if (!value_.map_->empty()) { + ObjectValues::const_iterator itLast = value_.map_->end(); + --itLast; + return (*itLast).first.index() + 1; + } + return 0; + case objectValue: + return ArrayIndex(value_.map_->size()); + } + JSON_ASSERT_UNREACHABLE; + return 0; // unreachable; +} + +bool Value::empty() const { + if (isNull() || isArray() || isObject()) + return size() == 0u; + else + return false; +} + +bool Value::operator!() const { return isNull(); } + +void Value::clear() { + JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue || + type_ == objectValue, + "in Json::Value::clear(): requires complex value"); + start_ = 0; + limit_ = 0; + switch (type_) { + case arrayValue: + case objectValue: + value_.map_->clear(); + break; + default: + break; + } +} + +void Value::resize(ArrayIndex newSize) { + JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue, + "in Json::Value::resize(): requires arrayValue"); + if (type_ == nullValue) + *this = Value(arrayValue); + ArrayIndex oldSize = size(); + if (newSize == 0) + clear(); + else if (newSize > oldSize) + (*this)[newSize - 1]; + else { + for (ArrayIndex index = newSize; index < oldSize; ++index) { + value_.map_->erase(index); + } + JSON_ASSERT(size() == newSize); + } +} + +Value& Value::operator[](ArrayIndex index) { + JSON_ASSERT_MESSAGE( + type_ == nullValue || type_ == arrayValue, + "in Json::Value::operator[](ArrayIndex): requires arrayValue"); + if (type_ == nullValue) + *this = Value(arrayValue); + CZString key(index); + ObjectValues::iterator it = value_.map_->lower_bound(key); + if (it != value_.map_->end() && (*it).first == key) + return (*it).second; + + ObjectValues::value_type defaultValue(key, nullRef); + it = value_.map_->insert(it, defaultValue); + return (*it).second; +} + +Value& Value::operator[](int index) { + JSON_ASSERT_MESSAGE( + index >= 0, + "in Json::Value::operator[](int index): index cannot be negative"); + return (*this)[ArrayIndex(index)]; +} + +const Value& Value::operator[](ArrayIndex index) const { + JSON_ASSERT_MESSAGE( + type_ == nullValue || type_ == arrayValue, + "in Json::Value::operator[](ArrayIndex)const: requires arrayValue"); + if (type_ == nullValue) + return nullRef; + CZString key(index); + ObjectValues::const_iterator it = value_.map_->find(key); + if (it == value_.map_->end()) + return nullRef; + return (*it).second; +} + +const Value& Value::operator[](int index) const { + JSON_ASSERT_MESSAGE( + index >= 0, + "in Json::Value::operator[](int index) const: index cannot be negative"); + return (*this)[ArrayIndex(index)]; +} + +void Value::initBasic(ValueType vtype, bool allocated) { + type_ = vtype; + allocated_ = allocated; + comments_ = 0; + start_ = 0; + limit_ = 0; +} + +// Access an object value by name, create a null member if it does not exist. +// @pre Type of '*this' is object or null. +// @param key is null-terminated. +Value& Value::resolveReference(const char* key) { + JSON_ASSERT_MESSAGE( + type_ == nullValue || type_ == objectValue, + "in Json::Value::resolveReference(): requires objectValue"); + if (type_ == nullValue) + *this = Value(objectValue); + CZString actualKey( + key, static_cast(strlen(key)), CZString::noDuplication); // NOTE! + ObjectValues::iterator it = value_.map_->lower_bound(actualKey); + if (it != value_.map_->end() && (*it).first == actualKey) + return (*it).second; + + ObjectValues::value_type defaultValue(actualKey, nullRef); + it = value_.map_->insert(it, defaultValue); + Value& value = (*it).second; + return value; +} + +// @param key is not null-terminated. +Value& Value::resolveReference(char const* key, char const* cend) +{ + JSON_ASSERT_MESSAGE( + type_ == nullValue || type_ == objectValue, + "in Json::Value::resolveReference(key, end): requires objectValue"); + if (type_ == nullValue) + *this = Value(objectValue); + CZString actualKey( + key, static_cast(cend-key), CZString::duplicateOnCopy); + ObjectValues::iterator it = value_.map_->lower_bound(actualKey); + if (it != value_.map_->end() && (*it).first == actualKey) + return (*it).second; + + ObjectValues::value_type defaultValue(actualKey, nullRef); + it = value_.map_->insert(it, defaultValue); + Value& value = (*it).second; + return value; +} + +Value Value::get(ArrayIndex index, const Value& defaultValue) const { + const Value* value = &((*this)[index]); + return value == &nullRef ? defaultValue : *value; +} + +bool Value::isValidIndex(ArrayIndex index) const { return index < size(); } + +Value const* Value::find(char const* key, char const* cend) const +{ + JSON_ASSERT_MESSAGE( + type_ == nullValue || type_ == objectValue, + "in Json::Value::find(key, end, found): requires objectValue or nullValue"); + if (type_ == nullValue) return NULL; + CZString actualKey(key, static_cast(cend-key), CZString::noDuplication); + ObjectValues::const_iterator it = value_.map_->find(actualKey); + if (it == value_.map_->end()) return NULL; + return &(*it).second; +} +const Value& Value::operator[](const char* key) const +{ + Value const* found = find(key, key + strlen(key)); + if (!found) return nullRef; + return *found; +} +Value const& Value::operator[](JSONCPP_STRING const& key) const +{ + Value const* found = find(key.data(), key.data() + key.length()); + if (!found) return nullRef; + return *found; +} + +Value& Value::operator[](const char* key) { + return resolveReference(key, key + strlen(key)); +} + +Value& Value::operator[](const JSONCPP_STRING& key) { + return resolveReference(key.data(), key.data() + key.length()); +} + +Value& Value::operator[](const StaticString& key) { + return resolveReference(key.c_str()); +} + +#ifdef JSON_USE_CPPTL +Value& Value::operator[](const CppTL::ConstString& key) { + return resolveReference(key.c_str(), key.end_c_str()); +} +Value const& Value::operator[](CppTL::ConstString const& key) const +{ + Value const* found = find(key.c_str(), key.end_c_str()); + if (!found) return nullRef; + return *found; +} +#endif + +Value& Value::append(const Value& value) { return (*this)[size()] = value; } + +Value Value::get(char const* key, char const* cend, Value const& defaultValue) const +{ + Value const* found = find(key, cend); + return !found ? defaultValue : *found; +} +Value Value::get(char const* key, Value const& defaultValue) const +{ + return get(key, key + strlen(key), defaultValue); +} +Value Value::get(JSONCPP_STRING const& key, Value const& defaultValue) const +{ + return get(key.data(), key.data() + key.length(), defaultValue); +} + + +bool Value::removeMember(const char* key, const char* cend, Value* removed) +{ + if (type_ != objectValue) { + return false; + } + CZString actualKey(key, static_cast(cend-key), CZString::noDuplication); + ObjectValues::iterator it = value_.map_->find(actualKey); + if (it == value_.map_->end()) + return false; + *removed = it->second; + value_.map_->erase(it); + return true; +} +bool Value::removeMember(const char* key, Value* removed) +{ + return removeMember(key, key + strlen(key), removed); +} +bool Value::removeMember(JSONCPP_STRING const& key, Value* removed) +{ + return removeMember(key.data(), key.data() + key.length(), removed); +} +Value Value::removeMember(const char* key) +{ + JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue, + "in Json::Value::removeMember(): requires objectValue"); + if (type_ == nullValue) + return nullRef; + + Value removed; // null + removeMember(key, key + strlen(key), &removed); + return removed; // still null if removeMember() did nothing +} +Value Value::removeMember(const JSONCPP_STRING& key) +{ + return removeMember(key.c_str()); +} + +bool Value::removeIndex(ArrayIndex index, Value* removed) { + if (type_ != arrayValue) { + return false; + } + CZString key(index); + ObjectValues::iterator it = value_.map_->find(key); + if (it == value_.map_->end()) { + return false; + } + *removed = it->second; + ArrayIndex oldSize = size(); + // shift left all items left, into the place of the "removed" + for (ArrayIndex i = index; i < (oldSize - 1); ++i){ + CZString keey(i); + (*value_.map_)[keey] = (*this)[i + 1]; + } + // erase the last one ("leftover") + CZString keyLast(oldSize - 1); + ObjectValues::iterator itLast = value_.map_->find(keyLast); + value_.map_->erase(itLast); + return true; +} + +#ifdef JSON_USE_CPPTL +Value Value::get(const CppTL::ConstString& key, + const Value& defaultValue) const { + return get(key.c_str(), key.end_c_str(), defaultValue); +} +#endif + +bool Value::isMember(char const* key, char const* cend) const +{ + Value const* value = find(key, cend); + return NULL != value; +} +bool Value::isMember(char const* key) const +{ + return isMember(key, key + strlen(key)); +} +bool Value::isMember(JSONCPP_STRING const& key) const +{ + return isMember(key.data(), key.data() + key.length()); +} + +#ifdef JSON_USE_CPPTL +bool Value::isMember(const CppTL::ConstString& key) const { + return isMember(key.c_str(), key.end_c_str()); +} +#endif + +Value::Members Value::getMemberNames() const { + JSON_ASSERT_MESSAGE( + type_ == nullValue || type_ == objectValue, + "in Json::Value::getMemberNames(), value must be objectValue"); + if (type_ == nullValue) + return Value::Members(); + Members members; + members.reserve(value_.map_->size()); + ObjectValues::const_iterator it = value_.map_->begin(); + ObjectValues::const_iterator itEnd = value_.map_->end(); + for (; it != itEnd; ++it) { + members.push_back(JSONCPP_STRING((*it).first.data(), + (*it).first.length())); + } + return members; +} +// +//# ifdef JSON_USE_CPPTL +// EnumMemberNames +// Value::enumMemberNames() const +//{ +// if ( type_ == objectValue ) +// { +// return CppTL::Enum::any( CppTL::Enum::transform( +// CppTL::Enum::keys( *(value_.map_), CppTL::Type() ), +// MemberNamesTransform() ) ); +// } +// return EnumMemberNames(); +//} +// +// +// EnumValues +// Value::enumValues() const +//{ +// if ( type_ == objectValue || type_ == arrayValue ) +// return CppTL::Enum::anyValues( *(value_.map_), +// CppTL::Type() ); +// return EnumValues(); +//} +// +//# endif + +static bool IsIntegral(double d) { + double integral_part; + return modf(d, &integral_part) == 0.0; +} + +bool Value::isNull() const { return type_ == nullValue; } + +bool Value::isBool() const { return type_ == booleanValue; } + +bool Value::isInt() const { + switch (type_) { + case intValue: + return value_.int_ >= minInt && value_.int_ <= maxInt; + case uintValue: + return value_.uint_ <= UInt(maxInt); + case realValue: + return value_.real_ >= minInt && value_.real_ <= maxInt && + IsIntegral(value_.real_); + default: + break; + } + return false; +} + +bool Value::isUInt() const { + switch (type_) { + case intValue: + return value_.int_ >= 0 && LargestUInt(value_.int_) <= LargestUInt(maxUInt); + case uintValue: + return value_.uint_ <= maxUInt; + case realValue: + return value_.real_ >= 0 && value_.real_ <= maxUInt && + IsIntegral(value_.real_); + default: + break; + } + return false; +} + +bool Value::isInt64() const { +#if defined(JSON_HAS_INT64) + switch (type_) { + case intValue: + return true; + case uintValue: + return value_.uint_ <= UInt64(maxInt64); + case realValue: + // Note that maxInt64 (= 2^63 - 1) is not exactly representable as a + // double, so double(maxInt64) will be rounded up to 2^63. Therefore we + // require the value to be strictly less than the limit. + return value_.real_ >= double(minInt64) && + value_.real_ < double(maxInt64) && IsIntegral(value_.real_); + default: + break; + } +#endif // JSON_HAS_INT64 + return false; +} + +bool Value::isUInt64() const { +#if defined(JSON_HAS_INT64) + switch (type_) { + case intValue: + return value_.int_ >= 0; + case uintValue: + return true; + case realValue: + // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a + // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we + // require the value to be strictly less than the limit. + return value_.real_ >= 0 && value_.real_ < maxUInt64AsDouble && + IsIntegral(value_.real_); + default: + break; + } +#endif // JSON_HAS_INT64 + return false; +} + +bool Value::isIntegral() const { +#if defined(JSON_HAS_INT64) + return isInt64() || isUInt64(); +#else + return isInt() || isUInt(); +#endif +} + +bool Value::isDouble() const { return type_ == realValue || isIntegral(); } + +bool Value::isNumeric() const { return isIntegral() || isDouble(); } + +bool Value::isString() const { return type_ == stringValue; } + +bool Value::isArray() const { return type_ == arrayValue; } + +bool Value::isObject() const { return type_ == objectValue; } + +void Value::setComment(const char* comment, size_t len, CommentPlacement placement) { + if (!comments_) + comments_ = new CommentInfo[numberOfCommentPlacement]; + if ((len > 0) && (comment[len-1] == '\n')) { + // Always discard trailing newline, to aid indentation. + len -= 1; + } + comments_[placement].setComment(comment, len); +} + +void Value::setComment(const char* comment, CommentPlacement placement) { + setComment(comment, strlen(comment), placement); +} + +void Value::setComment(const JSONCPP_STRING& comment, CommentPlacement placement) { + setComment(comment.c_str(), comment.length(), placement); +} + +bool Value::hasComment(CommentPlacement placement) const { + return comments_ != 0 && comments_[placement].comment_ != 0; +} + +JSONCPP_STRING Value::getComment(CommentPlacement placement) const { + if (hasComment(placement)) + return comments_[placement].comment_; + return ""; +} + +void Value::setOffsetStart(ptrdiff_t start) { start_ = start; } + +void Value::setOffsetLimit(ptrdiff_t limit) { limit_ = limit; } + +ptrdiff_t Value::getOffsetStart() const { return start_; } + +ptrdiff_t Value::getOffsetLimit() const { return limit_; } + +JSONCPP_STRING Value::toStyledString() const { + StyledWriter writer; + return writer.write(*this); +} + +Value::const_iterator Value::begin() const { + switch (type_) { + case arrayValue: + case objectValue: + if (value_.map_) + return const_iterator(value_.map_->begin()); + break; + default: + break; + } + return const_iterator(); +} + +Value::const_iterator Value::end() const { + switch (type_) { + case arrayValue: + case objectValue: + if (value_.map_) + return const_iterator(value_.map_->end()); + break; + default: + break; + } + return const_iterator(); +} + +Value::iterator Value::begin() { + switch (type_) { + case arrayValue: + case objectValue: + if (value_.map_) + return iterator(value_.map_->begin()); + break; + default: + break; + } + return iterator(); +} + +Value::iterator Value::end() { + switch (type_) { + case arrayValue: + case objectValue: + if (value_.map_) + return iterator(value_.map_->end()); + break; + default: + break; + } + return iterator(); +} + +// class PathArgument +// ////////////////////////////////////////////////////////////////// + +PathArgument::PathArgument() : key_(), index_(), kind_(kindNone) {} + +PathArgument::PathArgument(ArrayIndex index) + : key_(), index_(index), kind_(kindIndex) {} + +PathArgument::PathArgument(const char* key) + : key_(key), index_(), kind_(kindKey) {} + +PathArgument::PathArgument(const JSONCPP_STRING& key) + : key_(key.c_str()), index_(), kind_(kindKey) {} + +// class Path +// ////////////////////////////////////////////////////////////////// + +Path::Path(const JSONCPP_STRING& path, + const PathArgument& a1, + const PathArgument& a2, + const PathArgument& a3, + const PathArgument& a4, + const PathArgument& a5) { + InArgs in; + in.push_back(&a1); + in.push_back(&a2); + in.push_back(&a3); + in.push_back(&a4); + in.push_back(&a5); + makePath(path, in); +} + +void Path::makePath(const JSONCPP_STRING& path, const InArgs& in) { + const char* current = path.c_str(); + const char* end = current + path.length(); + InArgs::const_iterator itInArg = in.begin(); + while (current != end) { + if (*current == '[') { + ++current; + if (*current == '%') + addPathInArg(path, in, itInArg, PathArgument::kindIndex); + else { + ArrayIndex index = 0; + for (; current != end && *current >= '0' && *current <= '9'; ++current) + index = index * 10 + ArrayIndex(*current - '0'); + args_.push_back(index); + } + if (current == end || *current++ != ']') + invalidPath(path, int(current - path.c_str())); + } else if (*current == '%') { + addPathInArg(path, in, itInArg, PathArgument::kindKey); + ++current; + } else if (*current == '.') { + ++current; + } else { + const char* beginName = current; + while (current != end && !strchr("[.", *current)) + ++current; + args_.push_back(JSONCPP_STRING(beginName, current)); + } + } +} + +void Path::addPathInArg(const JSONCPP_STRING& /*path*/, + const InArgs& in, + InArgs::const_iterator& itInArg, + PathArgument::Kind kind) { + if (itInArg == in.end()) { + // Error: missing argument %d + } else if ((*itInArg)->kind_ != kind) { + // Error: bad argument type + } else { + args_.push_back(**itInArg); + } +} + +void Path::invalidPath(const JSONCPP_STRING& /*path*/, int /*location*/) { + // Error: invalid path. +} + +const Value& Path::resolve(const Value& root) const { + const Value* node = &root; + for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) { + const PathArgument& arg = *it; + if (arg.kind_ == PathArgument::kindIndex) { + if (!node->isArray() || !node->isValidIndex(arg.index_)) { + // Error: unable to resolve path (array value expected at position... + } + node = &((*node)[arg.index_]); + } else if (arg.kind_ == PathArgument::kindKey) { + if (!node->isObject()) { + // Error: unable to resolve path (object value expected at position...) + } + node = &((*node)[arg.key_]); + if (node == &Value::nullRef) { + // Error: unable to resolve path (object has no member named '' at + // position...) + } + } + } + return *node; +} + +Value Path::resolve(const Value& root, const Value& defaultValue) const { + const Value* node = &root; + for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) { + const PathArgument& arg = *it; + if (arg.kind_ == PathArgument::kindIndex) { + if (!node->isArray() || !node->isValidIndex(arg.index_)) + return defaultValue; + node = &((*node)[arg.index_]); + } else if (arg.kind_ == PathArgument::kindKey) { + if (!node->isObject()) + return defaultValue; + node = &((*node)[arg.key_]); + if (node == &Value::nullRef) + return defaultValue; + } + } + return *node; +} + +Value& Path::make(Value& root) const { + Value* node = &root; + for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) { + const PathArgument& arg = *it; + if (arg.kind_ == PathArgument::kindIndex) { + if (!node->isArray()) { + // Error: node is not an array at position ... + } + node = &((*node)[arg.index_]); + } else if (arg.kind_ == PathArgument::kindKey) { + if (!node->isObject()) { + // Error: node is not an object at position... + } + node = &((*node)[arg.key_]); + } + } + return *node; +} + +} // namespace Json + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: src/lib_json/json_value.cpp +// ////////////////////////////////////////////////////////////////////// + + + + + + +// ////////////////////////////////////////////////////////////////////// +// Beginning of content of file: src/lib_json/json_writer.cpp +// ////////////////////////////////////////////////////////////////////// + +// Copyright 2011 Baptiste Lepilleur +// Distributed under MIT license, or public domain if desired and +// recognized in your jurisdiction. +// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE + +#if !defined(JSON_IS_AMALGAMATION) +#include +#include "json_tool.h" +#endif // if !defined(JSON_IS_AMALGAMATION) +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(_MSC_VER) && _MSC_VER >= 1200 && _MSC_VER < 1800 // Between VC++ 6.0 and VC++ 11.0 +#include +#define isfinite _finite +#elif defined(__sun) && defined(__SVR4) //Solaris +#if !defined(isfinite) +#include +#define isfinite finite +#endif +#elif defined(_AIX) +#if !defined(isfinite) +#include +#define isfinite finite +#endif +#elif defined(__hpux) +#if !defined(isfinite) +#if defined(__ia64) && !defined(finite) +#define isfinite(x) ((sizeof(x) == sizeof(float) ? \ + _Isfinitef(x) : _IsFinite(x))) +#else +#include +#define isfinite finite +#endif +#endif +#else +#include +#if !(defined(__QNXNTO__)) // QNX already defines isfinite +#define isfinite std::isfinite +#endif +#endif + +#if defined(_MSC_VER) +#if !defined(WINCE) && defined(__STDC_SECURE_LIB__) && _MSC_VER >= 1500 // VC++ 9.0 and above +#define snprintf sprintf_s +#elif _MSC_VER >= 1900 // VC++ 14.0 and above +#define snprintf std::snprintf +#else +#define snprintf _snprintf +#endif +#elif defined(__ANDROID__) || defined(__QNXNTO__) +#define snprintf snprintf +#elif __cplusplus >= 201103L +#if !defined(__MINGW32__) && !defined(__CYGWIN__) +// #define snprintf std::snprintf +#endif +#endif + +#if defined(__BORLANDC__) +#include +#define isfinite _finite +#define snprintf _snprintf +#endif + +#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0 +// Disable warning about strdup being deprecated. +#pragma warning(disable : 4996) +#endif + +namespace Json { + +#if __cplusplus >= 201103L || (defined(_CPPLIB_VER) && _CPPLIB_VER >= 520) +typedef std::unique_ptr StreamWriterPtr; +#else +typedef std::auto_ptr StreamWriterPtr; +#endif + +static bool containsControlCharacter(const char* str) { + while (*str) { + if (isControlCharacter(*(str++))) + return true; + } + return false; +} + +static bool containsControlCharacter0(const char* str, unsigned len) { + char const* end = str + len; + while (end != str) { + if (isControlCharacter(*str) || 0==*str) + return true; + ++str; + } + return false; +} + +JSONCPP_STRING valueToString(LargestInt value) { + UIntToStringBuffer buffer; + char* current = buffer + sizeof(buffer); + if (value == Value::minLargestInt) { + uintToString(LargestUInt(Value::maxLargestInt) + 1, current); + *--current = '-'; + } else if (value < 0) { + uintToString(LargestUInt(-value), current); + *--current = '-'; + } else { + uintToString(LargestUInt(value), current); + } + assert(current >= buffer); + return current; +} + +JSONCPP_STRING valueToString(LargestUInt value) { + UIntToStringBuffer buffer; + char* current = buffer + sizeof(buffer); + uintToString(value, current); + assert(current >= buffer); + return current; +} + +#if defined(JSON_HAS_INT64) + +JSONCPP_STRING valueToString(Int value) { + return valueToString(LargestInt(value)); +} + +JSONCPP_STRING valueToString(UInt value) { + return valueToString(LargestUInt(value)); +} + +#endif // # if defined(JSON_HAS_INT64) + +JSONCPP_STRING valueToString(double value, bool useSpecialFloats, unsigned int precision) { + // Allocate a buffer that is more than large enough to store the 16 digits of + // precision requested below. + char buffer[32]; + int len = -1; + + char formatString[6]; + sprintf(formatString, "%%.%dg", precision); + + // Print into the buffer. We need not request the alternative representation + // that always has a decimal point because JSON doesn't distingish the + // concepts of reals and integers. + if (isfinite(value)) { + len = snprintf(buffer, sizeof(buffer), formatString, value); + } else { + // IEEE standard states that NaN values will not compare to themselves + if (value != value) { + len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "NaN" : "null"); + } else if (value < 0) { + len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "-Infinity" : "-1e+9999"); + } else { + len = snprintf(buffer, sizeof(buffer), useSpecialFloats ? "Infinity" : "1e+9999"); + } + // For those, we do not need to call fixNumLoc, but it is fast. + } + assert(len >= 0); + fixNumericLocale(buffer, buffer + len); + return buffer; +} + +JSONCPP_STRING valueToString(double value) { return valueToString(value, false, 17); } + +JSONCPP_STRING valueToString(bool value) { return value ? "true" : "false"; } + +JSONCPP_STRING valueToQuotedString(const char* value) { + if (value == NULL) + return ""; + // Not sure how to handle unicode... + if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL && + !containsControlCharacter(value)) + return JSONCPP_STRING("\"") + value + "\""; + // We have to walk value and escape any special characters. + // Appending to JSONCPP_STRING is not efficient, but this should be rare. + // (Note: forward slashes are *not* rare, but I am not escaping them.) + JSONCPP_STRING::size_type maxsize = + strlen(value) * 2 + 3; // allescaped+quotes+NULL + JSONCPP_STRING result; + result.reserve(maxsize); // to avoid lots of mallocs + result += "\""; + for (const char* c = value; *c != 0; ++c) { + switch (*c) { + case '\"': + result += "\\\""; + break; + case '\\': + result += "\\\\"; + break; + case '\b': + result += "\\b"; + break; + case '\f': + result += "\\f"; + break; + case '\n': + result += "\\n"; + break; + case '\r': + result += "\\r"; + break; + case '\t': + result += "\\t"; + break; + // case '/': + // Even though \/ is considered a legal escape in JSON, a bare + // slash is also legal, so I see no reason to escape it. + // (I hope I am not misunderstanding something. + // blep notes: actually escaping \/ may be useful in javascript to avoid (*c); + result += oss.str(); + } else { + result += *c; + } + break; + } + } + result += "\""; + return result; +} + +// https://github.com/upcaste/upcaste/blob/master/src/upcore/src/cstring/strnpbrk.cpp +static char const* strnpbrk(char const* s, char const* accept, size_t n) { + assert((s || !n) && accept); + + char const* const end = s + n; + for (char const* cur = s; cur < end; ++cur) { + int const c = *cur; + for (char const* a = accept; *a; ++a) { + if (*a == c) { + return cur; + } + } + } + return NULL; +} +static JSONCPP_STRING valueToQuotedStringN(const char* value, unsigned length) { + if (value == NULL) + return ""; + // Not sure how to handle unicode... + if (strnpbrk(value, "\"\\\b\f\n\r\t", length) == NULL && + !containsControlCharacter0(value, length)) + return JSONCPP_STRING("\"") + value + "\""; + // We have to walk value and escape any special characters. + // Appending to JSONCPP_STRING is not efficient, but this should be rare. + // (Note: forward slashes are *not* rare, but I am not escaping them.) + JSONCPP_STRING::size_type maxsize = + length * 2 + 3; // allescaped+quotes+NULL + JSONCPP_STRING result; + result.reserve(maxsize); // to avoid lots of mallocs + result += "\""; + char const* end = value + length; + for (const char* c = value; c != end; ++c) { + switch (*c) { + case '\"': + result += "\\\""; + break; + case '\\': + result += "\\\\"; + break; + case '\b': + result += "\\b"; + break; + case '\f': + result += "\\f"; + break; + case '\n': + result += "\\n"; + break; + case '\r': + result += "\\r"; + break; + case '\t': + result += "\\t"; + break; + // case '/': + // Even though \/ is considered a legal escape in JSON, a bare + // slash is also legal, so I see no reason to escape it. + // (I hope I am not misunderstanding something.) + // blep notes: actually escaping \/ may be useful in javascript to avoid (*c); + result += oss.str(); + } else { + result += *c; + } + break; + } + } + result += "\""; + return result; +} + +// Class Writer +// ////////////////////////////////////////////////////////////////// +Writer::~Writer() {} + +// Class FastWriter +// ////////////////////////////////////////////////////////////////// + +FastWriter::FastWriter() + : yamlCompatiblityEnabled_(false), dropNullPlaceholders_(false), + omitEndingLineFeed_(false) {} + +void FastWriter::enableYAMLCompatibility() { yamlCompatiblityEnabled_ = true; } + +void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; } + +void FastWriter::omitEndingLineFeed() { omitEndingLineFeed_ = true; } + +JSONCPP_STRING FastWriter::write(const Value& root) { + document_ = ""; + writeValue(root); + if (!omitEndingLineFeed_) + document_ += "\n"; + return document_; +} + +void FastWriter::writeValue(const Value& value) { + switch (value.type()) { + case nullValue: + if (!dropNullPlaceholders_) + document_ += "null"; + break; + case intValue: + document_ += valueToString(value.asLargestInt()); + break; + case uintValue: + document_ += valueToString(value.asLargestUInt()); + break; + case realValue: + document_ += valueToString(value.asDouble()); + break; + case stringValue: + { + // Is NULL possible for value.string_? + char const* str; + char const* end; + bool ok = value.getString(&str, &end); + if (ok) document_ += valueToQuotedStringN(str, static_cast(end-str)); + break; + } + case booleanValue: + document_ += valueToString(value.asBool()); + break; + case arrayValue: { + document_ += '['; + ArrayIndex size = value.size(); + for (ArrayIndex index = 0; index < size; ++index) { + if (index > 0) + document_ += ','; + writeValue(value[index]); + } + document_ += ']'; + } break; + case objectValue: { + Value::Members members(value.getMemberNames()); + document_ += '{'; + for (Value::Members::iterator it = members.begin(); it != members.end(); + ++it) { + const JSONCPP_STRING& name = *it; + if (it != members.begin()) + document_ += ','; + document_ += valueToQuotedStringN(name.data(), static_cast(name.length())); + document_ += yamlCompatiblityEnabled_ ? ": " : ":"; + writeValue(value[name]); + } + document_ += '}'; + } break; + } +} + +// Class StyledWriter +// ////////////////////////////////////////////////////////////////// + +StyledWriter::StyledWriter() + : rightMargin_(74), indentSize_(3), addChildValues_() {} + +JSONCPP_STRING StyledWriter::write(const Value& root) { + document_ = ""; + addChildValues_ = false; + indentString_ = ""; + writeCommentBeforeValue(root); + writeValue(root); + writeCommentAfterValueOnSameLine(root); + document_ += "\n"; + return document_; +} + +void StyledWriter::writeValue(const Value& value) { + switch (value.type()) { + case nullValue: + pushValue("null"); + break; + case intValue: + pushValue(valueToString(value.asLargestInt())); + break; + case uintValue: + pushValue(valueToString(value.asLargestUInt())); + break; + case realValue: + pushValue(valueToString(value.asDouble())); + break; + case stringValue: + { + // Is NULL possible for value.string_? + char const* str; + char const* end; + bool ok = value.getString(&str, &end); + if (ok) pushValue(valueToQuotedStringN(str, static_cast(end-str))); + else pushValue(""); + break; + } + case booleanValue: + pushValue(valueToString(value.asBool())); + break; + case arrayValue: + writeArrayValue(value); + break; + case objectValue: { + Value::Members members(value.getMemberNames()); + if (members.empty()) + pushValue("{}"); + else { + writeWithIndent("{"); + indent(); + Value::Members::iterator it = members.begin(); + for (;;) { + const JSONCPP_STRING& name = *it; + const Value& childValue = value[name]; + writeCommentBeforeValue(childValue); + writeWithIndent(valueToQuotedString(name.c_str())); + document_ += " : "; + writeValue(childValue); + if (++it == members.end()) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + document_ += ','; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("}"); + } + } break; + } +} + +void StyledWriter::writeArrayValue(const Value& value) { + unsigned size = value.size(); + if (size == 0) + pushValue("[]"); + else { + bool isArrayMultiLine = isMultineArray(value); + if (isArrayMultiLine) { + writeWithIndent("["); + indent(); + bool hasChildValue = !childValues_.empty(); + unsigned index = 0; + for (;;) { + const Value& childValue = value[index]; + writeCommentBeforeValue(childValue); + if (hasChildValue) + writeWithIndent(childValues_[index]); + else { + writeIndent(); + writeValue(childValue); + } + if (++index == size) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + document_ += ','; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("]"); + } else // output on a single line + { + assert(childValues_.size() == size); + document_ += "[ "; + for (unsigned index = 0; index < size; ++index) { + if (index > 0) + document_ += ", "; + document_ += childValues_[index]; + } + document_ += " ]"; + } + } +} + +bool StyledWriter::isMultineArray(const Value& value) { + ArrayIndex const size = value.size(); + bool isMultiLine = size * 3 >= rightMargin_; + childValues_.clear(); + for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { + const Value& childValue = value[index]; + isMultiLine = ((childValue.isArray() || childValue.isObject()) && + childValue.size() > 0); + } + if (!isMultiLine) // check if line length > max line length + { + childValues_.reserve(size); + addChildValues_ = true; + ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' + for (ArrayIndex index = 0; index < size; ++index) { + if (hasCommentForValue(value[index])) { + isMultiLine = true; + } + writeValue(value[index]); + lineLength += static_cast(childValues_[index].length()); + } + addChildValues_ = false; + isMultiLine = isMultiLine || lineLength >= rightMargin_; + } + return isMultiLine; +} + +void StyledWriter::pushValue(const JSONCPP_STRING& value) { + if (addChildValues_) + childValues_.push_back(value); + else + document_ += value; +} + +void StyledWriter::writeIndent() { + if (!document_.empty()) { + char last = document_[document_.length() - 1]; + if (last == ' ') // already indented + return; + if (last != '\n') // Comments may add new-line + document_ += '\n'; + } + document_ += indentString_; +} + +void StyledWriter::writeWithIndent(const JSONCPP_STRING& value) { + writeIndent(); + document_ += value; +} + +void StyledWriter::indent() { indentString_ += JSONCPP_STRING(indentSize_, ' '); } + +void StyledWriter::unindent() { + assert(indentString_.size() >= indentSize_); + indentString_.resize(indentString_.size() - indentSize_); +} + +void StyledWriter::writeCommentBeforeValue(const Value& root) { + if (!root.hasComment(commentBefore)) + return; + + document_ += "\n"; + writeIndent(); + const JSONCPP_STRING& comment = root.getComment(commentBefore); + JSONCPP_STRING::const_iterator iter = comment.begin(); + while (iter != comment.end()) { + document_ += *iter; + if (*iter == '\n' && + (iter != comment.end() && *(iter + 1) == '/')) + writeIndent(); + ++iter; + } + + // Comments are stripped of trailing newlines, so add one here + document_ += "\n"; +} + +void StyledWriter::writeCommentAfterValueOnSameLine(const Value& root) { + if (root.hasComment(commentAfterOnSameLine)) + document_ += " " + root.getComment(commentAfterOnSameLine); + + if (root.hasComment(commentAfter)) { + document_ += "\n"; + document_ += root.getComment(commentAfter); + document_ += "\n"; + } +} + +bool StyledWriter::hasCommentForValue(const Value& value) { + return value.hasComment(commentBefore) || + value.hasComment(commentAfterOnSameLine) || + value.hasComment(commentAfter); +} + +// Class StyledStreamWriter +// ////////////////////////////////////////////////////////////////// + +StyledStreamWriter::StyledStreamWriter(JSONCPP_STRING indentation) + : document_(NULL), rightMargin_(74), indentation_(indentation), + addChildValues_() {} + +void StyledStreamWriter::write(JSONCPP_OSTREAM& out, const Value& root) { + document_ = &out; + addChildValues_ = false; + indentString_ = ""; + indented_ = true; + writeCommentBeforeValue(root); + if (!indented_) writeIndent(); + indented_ = true; + writeValue(root); + writeCommentAfterValueOnSameLine(root); + *document_ << "\n"; + document_ = NULL; // Forget the stream, for safety. +} + +void StyledStreamWriter::writeValue(const Value& value) { + switch (value.type()) { + case nullValue: + pushValue("null"); + break; + case intValue: + pushValue(valueToString(value.asLargestInt())); + break; + case uintValue: + pushValue(valueToString(value.asLargestUInt())); + break; + case realValue: + pushValue(valueToString(value.asDouble())); + break; + case stringValue: + { + // Is NULL possible for value.string_? + char const* str; + char const* end; + bool ok = value.getString(&str, &end); + if (ok) pushValue(valueToQuotedStringN(str, static_cast(end-str))); + else pushValue(""); + break; + } + case booleanValue: + pushValue(valueToString(value.asBool())); + break; + case arrayValue: + writeArrayValue(value); + break; + case objectValue: { + Value::Members members(value.getMemberNames()); + if (members.empty()) + pushValue("{}"); + else { + writeWithIndent("{"); + indent(); + Value::Members::iterator it = members.begin(); + for (;;) { + const JSONCPP_STRING& name = *it; + const Value& childValue = value[name]; + writeCommentBeforeValue(childValue); + writeWithIndent(valueToQuotedString(name.c_str())); + *document_ << " : "; + writeValue(childValue); + if (++it == members.end()) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + *document_ << ","; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("}"); + } + } break; + } +} + +void StyledStreamWriter::writeArrayValue(const Value& value) { + unsigned size = value.size(); + if (size == 0) + pushValue("[]"); + else { + bool isArrayMultiLine = isMultineArray(value); + if (isArrayMultiLine) { + writeWithIndent("["); + indent(); + bool hasChildValue = !childValues_.empty(); + unsigned index = 0; + for (;;) { + const Value& childValue = value[index]; + writeCommentBeforeValue(childValue); + if (hasChildValue) + writeWithIndent(childValues_[index]); + else { + if (!indented_) writeIndent(); + indented_ = true; + writeValue(childValue); + indented_ = false; + } + if (++index == size) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + *document_ << ","; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("]"); + } else // output on a single line + { + assert(childValues_.size() == size); + *document_ << "[ "; + for (unsigned index = 0; index < size; ++index) { + if (index > 0) + *document_ << ", "; + *document_ << childValues_[index]; + } + *document_ << " ]"; + } + } +} + +bool StyledStreamWriter::isMultineArray(const Value& value) { + ArrayIndex const size = value.size(); + bool isMultiLine = size * 3 >= rightMargin_; + childValues_.clear(); + for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { + const Value& childValue = value[index]; + isMultiLine = ((childValue.isArray() || childValue.isObject()) && + childValue.size() > 0); + } + if (!isMultiLine) // check if line length > max line length + { + childValues_.reserve(size); + addChildValues_ = true; + ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' + for (ArrayIndex index = 0; index < size; ++index) { + if (hasCommentForValue(value[index])) { + isMultiLine = true; + } + writeValue(value[index]); + lineLength += static_cast(childValues_[index].length()); + } + addChildValues_ = false; + isMultiLine = isMultiLine || lineLength >= rightMargin_; + } + return isMultiLine; +} + +void StyledStreamWriter::pushValue(const JSONCPP_STRING& value) { + if (addChildValues_) + childValues_.push_back(value); + else + *document_ << value; +} + +void StyledStreamWriter::writeIndent() { + // blep intended this to look at the so-far-written string + // to determine whether we are already indented, but + // with a stream we cannot do that. So we rely on some saved state. + // The caller checks indented_. + *document_ << '\n' << indentString_; +} + +void StyledStreamWriter::writeWithIndent(const JSONCPP_STRING& value) { + if (!indented_) writeIndent(); + *document_ << value; + indented_ = false; +} + +void StyledStreamWriter::indent() { indentString_ += indentation_; } + +void StyledStreamWriter::unindent() { + assert(indentString_.size() >= indentation_.size()); + indentString_.resize(indentString_.size() - indentation_.size()); +} + +void StyledStreamWriter::writeCommentBeforeValue(const Value& root) { + if (!root.hasComment(commentBefore)) + return; + + if (!indented_) writeIndent(); + const JSONCPP_STRING& comment = root.getComment(commentBefore); + JSONCPP_STRING::const_iterator iter = comment.begin(); + while (iter != comment.end()) { + *document_ << *iter; + if (*iter == '\n' && + (iter != comment.end() && *(iter + 1) == '/')) + // writeIndent(); // would include newline + *document_ << indentString_; + ++iter; + } + indented_ = false; +} + +void StyledStreamWriter::writeCommentAfterValueOnSameLine(const Value& root) { + if (root.hasComment(commentAfterOnSameLine)) + *document_ << ' ' << root.getComment(commentAfterOnSameLine); + + if (root.hasComment(commentAfter)) { + writeIndent(); + *document_ << root.getComment(commentAfter); + } + indented_ = false; +} + +bool StyledStreamWriter::hasCommentForValue(const Value& value) { + return value.hasComment(commentBefore) || + value.hasComment(commentAfterOnSameLine) || + value.hasComment(commentAfter); +} + +////////////////////////// +// BuiltStyledStreamWriter + +/// Scoped enums are not available until C++11. +struct CommentStyle { + /// Decide whether to write comments. + enum Enum { + None, ///< Drop all comments. + Most, ///< Recover odd behavior of previous versions (not implemented yet). + All ///< Keep all comments. + }; +}; + +struct BuiltStyledStreamWriter : public StreamWriter +{ + BuiltStyledStreamWriter( + JSONCPP_STRING const& indentation, + CommentStyle::Enum cs, + JSONCPP_STRING const& colonSymbol, + JSONCPP_STRING const& nullSymbol, + JSONCPP_STRING const& endingLineFeedSymbol, + bool useSpecialFloats, + unsigned int precision); + int write(Value const& root, JSONCPP_OSTREAM* sout) JSONCPP_OVERRIDE; +private: + void writeValue(Value const& value); + void writeArrayValue(Value const& value); + bool isMultineArray(Value const& value); + void pushValue(JSONCPP_STRING const& value); + void writeIndent(); + void writeWithIndent(JSONCPP_STRING const& value); + void indent(); + void unindent(); + void writeCommentBeforeValue(Value const& root); + void writeCommentAfterValueOnSameLine(Value const& root); + static bool hasCommentForValue(const Value& value); + + typedef std::vector ChildValues; + + ChildValues childValues_; + JSONCPP_STRING indentString_; + unsigned int rightMargin_; + JSONCPP_STRING indentation_; + CommentStyle::Enum cs_; + JSONCPP_STRING colonSymbol_; + JSONCPP_STRING nullSymbol_; + JSONCPP_STRING endingLineFeedSymbol_; + bool addChildValues_ : 1; + bool indented_ : 1; + bool useSpecialFloats_ : 1; + unsigned int precision_; +}; +BuiltStyledStreamWriter::BuiltStyledStreamWriter( + JSONCPP_STRING const& indentation, + CommentStyle::Enum cs, + JSONCPP_STRING const& colonSymbol, + JSONCPP_STRING const& nullSymbol, + JSONCPP_STRING const& endingLineFeedSymbol, + bool useSpecialFloats, + unsigned int precision) + : rightMargin_(74) + , indentation_(indentation) + , cs_(cs) + , colonSymbol_(colonSymbol) + , nullSymbol_(nullSymbol) + , endingLineFeedSymbol_(endingLineFeedSymbol) + , addChildValues_(false) + , indented_(false) + , useSpecialFloats_(useSpecialFloats) + , precision_(precision) +{ +} +int BuiltStyledStreamWriter::write(Value const& root, JSONCPP_OSTREAM* sout) +{ + sout_ = sout; + addChildValues_ = false; + indented_ = true; + indentString_ = ""; + writeCommentBeforeValue(root); + if (!indented_) writeIndent(); + indented_ = true; + writeValue(root); + writeCommentAfterValueOnSameLine(root); + *sout_ << endingLineFeedSymbol_; + sout_ = NULL; + return 0; +} +void BuiltStyledStreamWriter::writeValue(Value const& value) { + switch (value.type()) { + case nullValue: + pushValue(nullSymbol_); + break; + case intValue: + pushValue(valueToString(value.asLargestInt())); + break; + case uintValue: + pushValue(valueToString(value.asLargestUInt())); + break; + case realValue: + pushValue(valueToString(value.asDouble(), useSpecialFloats_, precision_)); + break; + case stringValue: + { + // Is NULL is possible for value.string_? + char const* str; + char const* end; + bool ok = value.getString(&str, &end); + if (ok) pushValue(valueToQuotedStringN(str, static_cast(end-str))); + else pushValue(""); + break; + } + case booleanValue: + pushValue(valueToString(value.asBool())); + break; + case arrayValue: + writeArrayValue(value); + break; + case objectValue: { + Value::Members members(value.getMemberNames()); + if (members.empty()) + pushValue("{}"); + else { + writeWithIndent("{"); + indent(); + Value::Members::iterator it = members.begin(); + for (;;) { + JSONCPP_STRING const& name = *it; + Value const& childValue = value[name]; + writeCommentBeforeValue(childValue); + writeWithIndent(valueToQuotedStringN(name.data(), static_cast(name.length()))); + *sout_ << colonSymbol_; + writeValue(childValue); + if (++it == members.end()) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + *sout_ << ","; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("}"); + } + } break; + } +} + +void BuiltStyledStreamWriter::writeArrayValue(Value const& value) { + unsigned size = value.size(); + if (size == 0) + pushValue("[]"); + else { + bool isMultiLine = (cs_ == CommentStyle::All) || isMultineArray(value); + if (isMultiLine) { + writeWithIndent("["); + indent(); + bool hasChildValue = !childValues_.empty(); + unsigned index = 0; + for (;;) { + Value const& childValue = value[index]; + writeCommentBeforeValue(childValue); + if (hasChildValue) + writeWithIndent(childValues_[index]); + else { + if (!indented_) writeIndent(); + indented_ = true; + writeValue(childValue); + indented_ = false; + } + if (++index == size) { + writeCommentAfterValueOnSameLine(childValue); + break; + } + *sout_ << ","; + writeCommentAfterValueOnSameLine(childValue); + } + unindent(); + writeWithIndent("]"); + } else // output on a single line + { + assert(childValues_.size() == size); + *sout_ << "["; + if (!indentation_.empty()) *sout_ << " "; + for (unsigned index = 0; index < size; ++index) { + if (index > 0) + *sout_ << ", "; + *sout_ << childValues_[index]; + } + if (!indentation_.empty()) *sout_ << " "; + *sout_ << "]"; + } + } +} + +bool BuiltStyledStreamWriter::isMultineArray(Value const& value) { + ArrayIndex const size = value.size(); + bool isMultiLine = size * 3 >= rightMargin_; + childValues_.clear(); + for (ArrayIndex index = 0; index < size && !isMultiLine; ++index) { + Value const& childValue = value[index]; + isMultiLine = ((childValue.isArray() || childValue.isObject()) && + childValue.size() > 0); + } + if (!isMultiLine) // check if line length > max line length + { + childValues_.reserve(size); + addChildValues_ = true; + ArrayIndex lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]' + for (ArrayIndex index = 0; index < size; ++index) { + if (hasCommentForValue(value[index])) { + isMultiLine = true; + } + writeValue(value[index]); + lineLength += static_cast(childValues_[index].length()); + } + addChildValues_ = false; + isMultiLine = isMultiLine || lineLength >= rightMargin_; + } + return isMultiLine; +} + +void BuiltStyledStreamWriter::pushValue(JSONCPP_STRING const& value) { + if (addChildValues_) + childValues_.push_back(value); + else + *sout_ << value; +} + +void BuiltStyledStreamWriter::writeIndent() { + // blep intended this to look at the so-far-written string + // to determine whether we are already indented, but + // with a stream we cannot do that. So we rely on some saved state. + // The caller checks indented_. + + if (!indentation_.empty()) { + // In this case, drop newlines too. + *sout_ << '\n' << indentString_; + } +} + +void BuiltStyledStreamWriter::writeWithIndent(JSONCPP_STRING const& value) { + if (!indented_) writeIndent(); + *sout_ << value; + indented_ = false; +} + +void BuiltStyledStreamWriter::indent() { indentString_ += indentation_; } + +void BuiltStyledStreamWriter::unindent() { + assert(indentString_.size() >= indentation_.size()); + indentString_.resize(indentString_.size() - indentation_.size()); +} + +void BuiltStyledStreamWriter::writeCommentBeforeValue(Value const& root) { + if (cs_ == CommentStyle::None) return; + if (!root.hasComment(commentBefore)) + return; + + if (!indented_) writeIndent(); + const JSONCPP_STRING& comment = root.getComment(commentBefore); + JSONCPP_STRING::const_iterator iter = comment.begin(); + while (iter != comment.end()) { + *sout_ << *iter; + if (*iter == '\n' && + (iter != comment.end() && *(iter + 1) == '/')) + // writeIndent(); // would write extra newline + *sout_ << indentString_; + ++iter; + } + indented_ = false; +} + +void BuiltStyledStreamWriter::writeCommentAfterValueOnSameLine(Value const& root) { + if (cs_ == CommentStyle::None) return; + if (root.hasComment(commentAfterOnSameLine)) + *sout_ << " " + root.getComment(commentAfterOnSameLine); + + if (root.hasComment(commentAfter)) { + writeIndent(); + *sout_ << root.getComment(commentAfter); + } +} + +// static +bool BuiltStyledStreamWriter::hasCommentForValue(const Value& value) { + return value.hasComment(commentBefore) || + value.hasComment(commentAfterOnSameLine) || + value.hasComment(commentAfter); +} + +/////////////// +// StreamWriter + +StreamWriter::StreamWriter() + : sout_(NULL) +{ +} +StreamWriter::~StreamWriter() +{ +} +StreamWriter::Factory::~Factory() +{} +StreamWriterBuilder::StreamWriterBuilder() +{ + setDefaults(&settings_); +} +StreamWriterBuilder::~StreamWriterBuilder() +{} +StreamWriter* StreamWriterBuilder::newStreamWriter() const +{ + JSONCPP_STRING indentation = settings_["indentation"].asString(); + JSONCPP_STRING cs_str = settings_["commentStyle"].asString(); + bool eyc = settings_["enableYAMLCompatibility"].asBool(); + bool dnp = settings_["dropNullPlaceholders"].asBool(); + bool usf = settings_["useSpecialFloats"].asBool(); + unsigned int pre = settings_["precision"].asUInt(); + CommentStyle::Enum cs = CommentStyle::All; + if (cs_str == "All") { + cs = CommentStyle::All; + } else if (cs_str == "None") { + cs = CommentStyle::None; + } else { + throwRuntimeError("commentStyle must be 'All' or 'None'"); + } + JSONCPP_STRING colonSymbol = " : "; + if (eyc) { + colonSymbol = ": "; + } else if (indentation.empty()) { + colonSymbol = ":"; + } + JSONCPP_STRING nullSymbol = "null"; + if (dnp) { + nullSymbol = ""; + } + if (pre > 17) pre = 17; + JSONCPP_STRING endingLineFeedSymbol = ""; + return new BuiltStyledStreamWriter( + indentation, cs, + colonSymbol, nullSymbol, endingLineFeedSymbol, usf, pre); +} +static void getValidWriterKeys(std::set* valid_keys) +{ + valid_keys->clear(); + valid_keys->insert("indentation"); + valid_keys->insert("commentStyle"); + valid_keys->insert("enableYAMLCompatibility"); + valid_keys->insert("dropNullPlaceholders"); + valid_keys->insert("useSpecialFloats"); + valid_keys->insert("precision"); +} +bool StreamWriterBuilder::validate(Json::Value* invalid) const +{ + Json::Value my_invalid; + if (!invalid) invalid = &my_invalid; // so we do not need to test for NULL + Json::Value& inv = *invalid; + std::set valid_keys; + getValidWriterKeys(&valid_keys); + Value::Members keys = settings_.getMemberNames(); + size_t n = keys.size(); + for (size_t i = 0; i < n; ++i) { + JSONCPP_STRING const& key = keys[i]; + if (valid_keys.find(key) == valid_keys.end()) { + inv[key] = settings_[key]; + } + } + return 0u == inv.size(); +} +Value& StreamWriterBuilder::operator[](JSONCPP_STRING key) +{ + return settings_[key]; +} +// static +void StreamWriterBuilder::setDefaults(Json::Value* settings) +{ + //! [StreamWriterBuilderDefaults] + (*settings)["commentStyle"] = "All"; + (*settings)["indentation"] = "\t"; + (*settings)["enableYAMLCompatibility"] = false; + (*settings)["dropNullPlaceholders"] = false; + (*settings)["useSpecialFloats"] = false; + (*settings)["precision"] = 17; + //! [StreamWriterBuilderDefaults] +} + +JSONCPP_STRING writeString(StreamWriter::Factory const& builder, Value const& root) { + JSONCPP_OSTRINGSTREAM sout; + StreamWriterPtr const writer(builder.newStreamWriter()); + writer->write(root, &sout); + return sout.str(); +} + +JSONCPP_OSTREAM& operator<<(JSONCPP_OSTREAM& sout, Value const& root) { + StreamWriterBuilder builder; + StreamWriterPtr const writer(builder.newStreamWriter()); + writer->write(root, &sout); + return sout; +} + +} // namespace Json + +// ////////////////////////////////////////////////////////////////////// +// End of content of file: src/lib_json/json_writer.cpp +// ////////////////////////////////////////////////////////////////////// + + + + diff --git a/source/lib.h b/source/lib.h index d157805..b7f555d 100755 --- a/source/lib.h +++ b/source/lib.h @@ -37,5 +37,3 @@ along with make_cdn_cia. If not, see . #include "types.h" #include "utils.h" - - diff --git a/source/main.cpp b/source/main.cpp index ec5193d..43139dc 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -27,32 +27,35 @@ #include <3ds.h> -#include "tinyxml2.h" #include "utils.h" +#include "eshop/eshop.h" #include "data.h" #include "menu.h" - +#include "json/json.h" +#include "ConsoleProgressPrinter/ConsoleProgressPrinter.h" static const u16 top = 0x140; static std::string region = "ALL"; static bool bExit = false; - +int sourceDataType; +Json::Value sourceData; +ConsoleProgressPrinter progressBar(0); std::string upper(std::string s) { - std::string ups; - - for(unsigned int i = 0; i < s.size(); i++) - { - ups.push_back(std::toupper(s[i])); - } - - return ups; + std::string ups; + + for(unsigned int i = 0; i < s.size(); i++) + { + ups.push_back(std::toupper(s[i])); + } + + return ups; } struct display_item { - int ld; - int index; + int ld; + int index; }; bool compareByLD(const display_item &a, const display_item &b) @@ -60,7 +63,8 @@ bool compareByLD(const display_item &a, const display_item &b) return a.ld < b.ld; } -bool FileExists (std::string name){ +bool FileExists (std::string name) +{ struct stat buffer; return (stat (name.c_str(), &buffer) == 0); } @@ -70,18 +74,21 @@ int mkpath(std::string s,mode_t mode) size_t pre=0,pos; std::string dir; int mdret = 0; - if(s[s.size()-1]!='/'){ + if (s[s.size()-1]!='/') + { s+='/'; } - while((pos=s.find_first_of('/',pre))!=std::string::npos){ + while((pos=s.find_first_of('/',pre))!=std::string::npos) + { dir=s.substr(0,pos++); pre=pos; - if(dir.size()==0) continue; // if leading / first time is 0 length - if((mdret=mkdir(dir.c_str(),mode)) && errno!=EEXIST){ + if (dir.size()==0) continue; // if leading / first time is 0 length + if ((mdret=mkdir(dir.c_str(),mode)) && errno!=EEXIST) + { return mdret; } } - return mdret; + return mdret; } char parse_hex(char c) @@ -100,31 +107,27 @@ char* parse_string(const std::string & s) return buffer; } -void CreateTicket(std::string titleId, std::string encTitleKey, char* titleVersion, std::string outputFullPath) +std::string GetTicket(std::string titleId, std::string encTitleKey, char* titleVersion) { - std::ofstream ofs; - ofs.open(outputFullPath, std::ofstream::out | std::ofstream::binary | std::ofstream::trunc); + std::ostringstream ofs; ofs.write(tikTemp, 0xA50); - ofs.close(); - ofs.open(outputFullPath, std::ofstream::out | std::ofstream::in | std::ofstream::binary); ofs.seekp(top+0xA6, std::ios::beg); ofs.write(titleVersion, 0x2); ofs.seekp(top+0x9C, std::ios::beg); ofs.write(parse_string(titleId), 0x8); ofs.seekp(top+0x7F, std::ios::beg); ofs.write(parse_string(encTitleKey), 0x10); - ofs.close(); + return ofs.str(); } - - void removeForbiddenChar(std::string* s) { std::string::iterator it; std::string illegalChars = "\\/:?\"<>|"; - for (it = s->begin() ; it < s->end() ; ++it){ + for (it = s->begin() ; it < s->end() ; ++it) + { bool found = illegalChars.find(*it) != std::string::npos; - if(found) + if (found) { *it = ' '; } @@ -143,17 +146,37 @@ std::string ToHex(const std::string& s) } +void load_JSON_data() +{ + printf("loading horns.json...\n"); + std::ifstream ifs("/TIKdevil/horns.json"); + Json::Reader reader; + Json::Value obj; + reader.parse(ifs, obj); + sourceData = obj; // array of characters + + if (sourceData[0]["titleID"].isString()) + { + sourceDataType = JSON_TYPE_ONLINE; + } else if (sourceData[0]["titleid"].isString()) + { + sourceDataType = JSON_TYPE_HORNS; + } +} + + std::string get_file_contents(const char *filename) { - std::ifstream in(filename, std::ios::in | std::ios::binary); - if (in) - { - return(std::string((std::istreambuf_iterator(in)), std::istreambuf_iterator())); - } - throw(errno); + std::ifstream in(filename, std::ios::in | std::ios::binary); + if (in) + { + return(std::string((std::istreambuf_iterator(in)), std::istreambuf_iterator())); + } + throw(errno); } -int util_compare_u64(const void* e1, const void* e2) { +int util_compare_u64(const void* e1, const void* e2) +{ u64 id1 = *(u64*) e1; u64 id2 = *(u64*) e2; @@ -162,463 +185,521 @@ int util_compare_u64(const void* e1, const void* e2) { std::vector util_get_installed_tickets() { - std::vector vTickets; - Result res = 0; + std::vector vTickets; + Result res = 0; u32 ticketCount = 0; - if(R_SUCCEEDED(res = AM_GetTicketCount(&ticketCount))) { + if (R_SUCCEEDED(res = AM_GetTicketCount(&ticketCount))) + { u64* ticketIDs = (u64*) calloc(ticketCount, sizeof(u64)); - if(ticketIDs != NULL) { - if(R_SUCCEEDED(res = AM_GetTicketList(&ticketCount, ticketCount, 0, ticketIDs))) { + if (ticketIDs != NULL) + { + if (R_SUCCEEDED(res = AM_GetTicketList(&ticketCount, ticketCount, 0, ticketIDs))) + { qsort(ticketIDs, ticketCount, sizeof(u64), util_compare_u64); - char cur[34]; - for(u32 i = 0; i < ticketCount && R_SUCCEEDED(res); i++) { - sprintf(cur,"%016llX", ticketIDs[i]); - vTickets.push_back(cur); - } - } - } - } - return vTickets; + char cur[34]; + for(u32 i = 0; i < ticketCount && R_SUCCEEDED(res); i++) + { + sprintf(cur,"%016llX", ticketIDs[i]); + vTickets.push_back(cur); + } + } + } + } + return vTickets; +} + +bool is_game_installed(u64* titleID){ + AM_TitleEntry entry; + return ( + R_SUCCEEDED(AM_GetTitleInfo(MEDIATYPE_SD, 1, titleID, &entry)) || + R_SUCCEEDED(AM_GetTitleInfo(MEDIATYPE_NAND, 1, titleID, &entry)) + ); } -void action_download() +bool is_ticket_installed(std::vector &vNANDTiks, std::string &titleId) { - printf("Downloading 3ds.nfshost.com page..."); - - mkpath("/TIKdevil/", 0777); - mkpath("/TIKdevil/tickets/", 0777); - FILE *oh = fopen("/TIKdevil/fullpage", "wb"); - Result sres = DownloadFile("http://3ds.nfshost.com/", oh, true); - fclose(oh); - if (sres != 0) - { - printf("Could not download file.\n"); - } - - printf("done!\n\n"); + for(unsigned int foo =0; foo < vNANDTiks.size(); foo++) + { + std::string curTik = vNANDTiks.at(foo); + std::transform(curTik.begin(), curTik.end(), curTik.begin(), ::tolower); + if (titleId == curTik) + { + return true; + } + } + return false; } -void action_table_strip() +void action_missing_tickets(std::vector &vEncTitleKey, std::vector &vTitleID, std::vector &vTitleRegion, int &n, std::string regionFilter, bool del) { - printf("Stripping table...\n"); - printf(" Phase 1..."); - std::string divBuffer = get_file_contents("/TIKdevil/fullpage"); - std::string buf = divBuffer.substr((divBuffer.find("") + 8), (divBuffer.find("") - divBuffer.find(""))); - int totSize = buf.size(); - int lastPrint=0; - printf("done!\n\n"); - - printf(" Phase 2...\n "); - while(buf.find("") != std::string::npos) + // Set up the reading of json + if (check_JSON(del == false)) { - int curPos = buf.find(""); - buf.erase(buf.find(""), 101); - int progress=curPos*100/totSize; - if((progress%10==0 and progress>lastPrint)or(progress==0 and lastPrint==0)){ - printf("%d%% ", progress); - lastPrint = progress+1; - } - } - printf("100%%\n Done!\n\n Phase 3...\n "); - lastPrint=0; - while(buf.find("") != std::string::npos) - { - int curPos = buf.find(""); - buf.erase(buf.find(""), 96); - int progress=curPos*100/totSize; - if((progress%10==0 and progress>lastPrint)or(progress==0 and lastPrint==0)){ - printf("%d%% ", progress); - lastPrint = progress+1; - } + load_JSON_data(); + } else + return; + + if (del == false) + { + printf("Checking for already installed tiks...\n\n"); + } else { + printf("Checking for out of region tiks not in use...\n\n"); } - printf("100%%\n Done!\n\nWriting to file..."); - FILE *fp = fopen ("/TIKdevil/table", "w+"); - fprintf(fp, "%s", buf.c_str()); - fclose(fp); - printf("done!\n\n"); -} + n = 0; -void action_missing_tickets(std::vector &vEncTitleKey, std::vector &vTitleID, std::vector &vTitleRegion, int &n, std::string regionFilter, bool del) -{ - printf("Checking for already installed tiks...\n"); - tinyxml2::XMLDocument xmlDoc; - xmlDoc.LoadFile( "/TIKdevil/table" ); - std::vector vNANDTiks = util_get_installed_tickets(); - - tinyxml2::XMLElement * pTR = xmlDoc.FirstChildElement("tr"); + const char* ctitleId = nullptr; const char* cencTitleKey = nullptr; - const char* ctitleType = nullptr; const char* ctitleName = nullptr; - const char* ctitleRegion = nullptr; - + + std::string titleType; std::string titleId; std::string encTitleKey; std::string titleRegion; - std::string curTik; - - while (pTR != nullptr) - { - int i=1; - tinyxml2::XMLElement * pTD = pTR->FirstChildElement("td"); - while (pTD != nullptr) + bool isNotSystemTitle; + + if(sourceData.size() > 0){ + progressBar.reset(); + progressBar.setMax(sourceData.size() - 1); + } + + for (unsigned int i = 0; i < sourceData.size(); i++) + { + progressBar.updateProgress(i); + // Check that the encTitleKey isn't null + if (sourceData[i]["encTitleKey"].isNull()) { - const char* sOut = pTD->GetText(); - switch (i) - { - case(1): - ctitleId = sOut; - break; - case(3): - cencTitleKey = sOut; - break; - case(4): - ctitleType = sOut; - break; - case(5): - ctitleName = sOut; - break; - case(6): - ctitleRegion = sOut; - break; - } - pTD = pTD->NextSiblingElement("td"); - i++; + continue; } - if(del == false) + ctitleId = sourceData[i]["titleID"].asCString(); + cencTitleKey = sourceData[i]["encTitleKey"].asCString(); + ctitleName = sourceData[i]["name"].asCString(); + + titleId = ctitleId; + titleRegion = sourceData[i]["region"].asString(); + titleType = sourceData[i]["titleID"].asString().substr(4,4); + + isNotSystemTitle = (titleType == ESHOP_GAMEAPP or titleType == ESHOP_DLC or titleType == ESHOP_DSIWARE); + + if ( + ctitleId == NULL || + cencTitleKey == NULL || + ctitleName == NULL || + isNotSystemTitle == false + ) + { + // We don't want this ticket, skip it. + continue; + } + + if (del == false) { - - if(strcmp(regionFilter.c_str(), "ALL")) + if ( + ( + titleRegion == regionFilter || + titleRegion == "ALL" || + titleRegion == "" + ) || + regionFilter == "ALL" + ) { - if(ctitleId != NULL and cencTitleKey != NULL and ctitleName != NULL and (not(strcmp(ctitleType, "eShop/Application")) or not(strcmp(ctitleType, "DLC"))) and(not(strcmp(ctitleRegion, regionFilter.c_str())))) - { - titleId = ctitleId; - bool found = false; - for(unsigned int foo =0; foo < vNANDTiks.size(); foo++) - { - curTik = vNANDTiks.at(foo); - std::transform(curTik.begin(), curTik.end(), curTik.begin(), ::tolower); - if(titleId == curTik) - { - found=true; - } - } - if(found==false) - { - n++; - - encTitleKey = cencTitleKey; - encTitleKey.erase(remove_if(encTitleKey.begin(), encTitleKey.end(), isspace), encTitleKey.end()); - titleRegion = ctitleRegion; - - vTitleID.push_back(titleId); - vEncTitleKey.push_back(encTitleKey); - vTitleRegion.push_back(titleRegion); - } - } - } else { - if(ctitleId != NULL and cencTitleKey != NULL and ctitleName != NULL and (not(strcmp(ctitleType, "eShop/Application")) or not(strcmp(ctitleType, "DLC")))) + // add it if it isn't a system title and the region matches + if (is_ticket_installed(vNANDTiks, titleId)==false) { - titleId = ctitleId; - bool found = false; - for(unsigned int foo =0; foo < vNANDTiks.size(); foo++) - { - curTik = vNANDTiks.at(foo); - std::transform(curTik.begin(), curTik.end(), curTik.begin(), ::tolower); - if(titleId == curTik) - { - found=true; - } - } - if(found==false) - { - encTitleKey = cencTitleKey; - encTitleKey.erase(remove_if(encTitleKey.begin(), encTitleKey.end(), isspace), encTitleKey.end()); - n++; - vTitleID.push_back(titleId); - vEncTitleKey.push_back(encTitleKey); - } + n++; + + encTitleKey = cencTitleKey; + encTitleKey.erase(remove_if (encTitleKey.begin(), encTitleKey.end(), isspace), encTitleKey.end()); + + vTitleID.push_back(titleId); + vEncTitleKey.push_back(encTitleKey); + vTitleRegion.push_back(titleRegion); } } } else { - u64 curr; - if(strcmp(regionFilter.c_str(), "ALL")) + u64 curr = strtoull(ctitleId, NULL, 16); + + if ( + ( + ( + ( + regionFilter != "REGION FREE" && + titleRegion != regionFilter && + titleRegion != "ALL" && + titleRegion != "" + ) || + ( + regionFilter == "REGION FREE" && + ( + titleRegion != "ALL" && + titleRegion != "" + ) + ) + ) || + regionFilter == "ALL" + ) && !is_game_installed(&curr) + ) { - if(ctitleId != NULL and cencTitleKey != NULL and ctitleName != NULL and (not(strcmp(ctitleType, "eShop/Application")) or not(strcmp(ctitleType, "DLC"))) and(strcmp(ctitleRegion, regionFilter.c_str()))) - { - n++; - curr = strtoull(ctitleId, NULL, 16) ; - AM_DeleteTicket(curr); - } - } else { - if(ctitleId != NULL and cencTitleKey != NULL and ctitleName != NULL and (not(strcmp(ctitleType, "eShop/Application")) or not(strcmp(ctitleType, "DLC")))) - { + // If region matches selection and it not a system title + if (is_ticket_installed(vNANDTiks, titleId)==true) + { n++; - curr = strtoull(ctitleId, NULL, 16) ; - AM_DeleteTicket(curr); + + vTitleID.push_back(titleId); } } } - pTR = pTR->NextSiblingElement("tr"); + } - if(del==false)printf("Missing tickets: %d\n\n", n); - else if(del==true)printf("Deleted tickets: %d\n\n", n); -} -void action_generate(std::vector vEncTitleKey,std::vector vTitleID, int index) -{ - printf("Generating missing tickets...\n "); - char titleVersion[2] = {0x00, 0x00}; - int genlastPrint = 0; - for (unsigned int i =0; i < vTitleID.size(); i++) - { - CreateTicket(vTitleID.at(i), vEncTitleKey.at(i), titleVersion, "/TIKdevil/tickets/" + vTitleID.at(i) + ".tik"); - int genprogress = i*100/index; - if((genprogress%10==0 and genprogress>genlastPrint)or(genprogress==0 and genlastPrint==0)){ - printf("%d%% ", genprogress); - genlastPrint = genprogress+1; - } + if (sourceData.size() > 0){ + printf("\n\n"); + } + + if (del==false) + { + printf("Missing tickets: %d", n); + } + else if (del==true) + { + printf("Tickets to delete: %d", n); } - printf("100%%\n Done!\n\n"); } +void action_delete(std::vector vTitleID) +{ + if(vTitleID.size() > 0) + { + printf("\n\nRemoving out of region tickets...\n\n"); + progressBar.reset(); + progressBar.setMax(vTitleID.size() - 1); + for (unsigned int i =0; i < vTitleID.size(); i++) + { -void action_install(std::vector vTitleID, int index) -{ - printf("Installing Tickets...\n "); - - Handle hTik; - u32 writtenbyte; - int instlastPrint = 0; - for (unsigned int i =0; i < vTitleID.size(); i++) - { - std::string cID = "/TIKdevil/tickets/"; - cID.append(vTitleID.at(i)); - cID.append(".tik"); - AM_InstallTicketBegin(&hTik); - std::string curr = get_file_contents(cID.c_str()); - FSFILE_Write(hTik, &writtenbyte, 0, curr.c_str(), 0x150000, 0); - AM_InstallTicketFinish(hTik); - int instprogress = i*100/index; - if((instprogress%10==0 and instprogress>instlastPrint)or(instprogress==0 and instlastPrint==0)){ - printf("%d%% ", instprogress); - instlastPrint = instprogress+1; - } - } - printf("100%%\n Done!\n\n"); + u64 curr = strtoull(vTitleID[i].c_str(), NULL, 16); + AM_DeleteTicket(curr); + + progressBar.updateProgress(i); + + hidScanInput(); + + u32 keys = hidKeysDown(); + + if(keys == KEY_B){ + printf("\n\nB button pressed, aborting...\n"); + return; + } + } + } + printf("\n\nDone!\n"); } -void action_clean(std::vector vTitleID) +void action_install(std::vector vEncTitleKey,std::vector vTitleID) { - printf("Cleaning temp files..."); - for (unsigned int i =0; i < vTitleID.size(); i++) - { - std::string rem = "/TIKdevil/tickets/"; - rem.append(vTitleID.at(i)); - rem.append(".tik"); - remove(rem.c_str()); - } - - printf("done!\n"); + if(vTitleID.size() > 0) + { + printf("\n\nInstalling missing tickets...\n\n"); + char titleVersion[2] = {0x00, 0x00}; + Handle hTik; + u32 writtenbyte; + + progressBar.reset(); + progressBar.setMax(vTitleID.size() - 1); + + for (unsigned int i =0; i < vTitleID.size(); i++) + { + + AM_InstallTicketBegin(&hTik); + std::string curr = GetTicket(vTitleID.at(i), vEncTitleKey.at(i), titleVersion); + FSFILE_Write(hTik, &writtenbyte, 0, curr.c_str(), 0x150000, 0); + AM_InstallTicketFinish(hTik); + + progressBar.updateProgress(i); + + hidScanInput(); + + u32 keys = hidKeysDown(); + + if(keys == KEY_B){ + printf("\n\nB button pressed, aborting...\n"); + return; + } + } + } + printf("\n\nDone!\n"); } -void action_about() + +void action_about(gfxScreen_t screen) { - consoleClear(); - - printf(CONSOLE_RED "\n\n\n TIKdevil by Kyraminol\n\n" CONSOLE_RESET); - printf(" Generate only missing tickets\n"); - printf(" and directly install them!\n\n\n"); - printf(CONSOLE_BLUE " Special thanks to:\n"); - printf(" cearp, Drakia, steveice10.\n" CONSOLE_RESET); - wait_key_specific("\n\n Press A to continue.\n", KEY_A); + PrintConsole infoConsole; + PrintConsole* currentConsole = consoleSelect(&infoConsole); + consoleInit(screen, &infoConsole); + + consoleClear(); + + printf(CONSOLE_RED "\n\n\n TIKdevil " VERSION_STRING " by Kyraminol\n\n" CONSOLE_RESET); + printf(" Generate only missing tickets\n"); + printf(" and directly install them!\n\n\n"); + printf(CONSOLE_BLUE " Special thanks to:\n\n" CONSOLE_RESET); + printf(" cearp, Drakia, steveice10, Mmcx125,\n and DanTheMan827.\n" CONSOLE_RESET); + printf("\n\n Commit: " REVISION_STRING); + + consoleSelect(currentConsole); } void action_toggle_region() { - if(region == "ALL")region = "EUR"; - else if(region == "EUR") region = "USA"; - else if(region == "USA") region = "JPN"; - else if(region == "JPN") region = "ALL"; + if (region == "REGION FREE")region = "ALL"; + else if (region == "ALL") region = "EUR"; + else if (region == "EUR") region = "USA"; + else if (region == "USA") region = "JPN"; + else if (region == "JPN") region = "CHN"; + else if (region == "CHN") region = "KOR"; + else if (region == "KOR") region = "TWN"; + else if (region == "TWN") region = "REGION FREE"; } -int action_getconfirm(){ +int action_getconfirm(bool removing) +{ int ret = 0; - char msg[32]; - sprintf(msg, "Region set to %s are you sure?", region.c_str()); - if(region=="ALL"){ - const char *confirm[] = { - "No! Return me to main menu.", - "Yes, but select EUR.", - "Yes, but select USA.", - "Yes, but select JPN.", - "ARR ARR SELECT THEM ALL." - }; - char foo[2]; + + char msg[72]; + + if (region == "ALL") + { + sprintf(msg, "Region set to ALL are you sure?"); + const char *confirm[] = { + "No, take me to main menu.", + "No, I only want EUR.", + "No, I only want USA.", + "No, I only want JPN.", + "No, I only want CHN.", + "No, I only want KOR.", + "No, I only want TWN.", + "No, I only want region free.", + "ARR ARR SELECT THEM ALL." + }; while(ret==0) { - sprintf(foo, " "); - int result = menu_draw(msg, foo, 0, sizeof(confirm) / sizeof(char*), confirm); + ret = 1; + int result = menu_draw(msg, " ", 0, sizeof(confirm) / sizeof(char*), confirm); switch (result) { case 0: - ret=-1; break; + ret = -1; + break; + case 1: - ret=1; region = "EUR"; break; + region = "EUR"; + break; + case 2: - ret=1; region = "USA"; break; + region = "USA"; + break; + case 3: - ret=1; region = "JPN"; break; + region = "JPN"; + break; + case 4: - ret=1; break; + region = "CHN"; + break; + + case 5: + region = "KOR"; + break; + + case 6: + region = "TWN"; + break; + + case 7: + region = "REGION FREE"; + break; + + case 8: break; + + default: + ret = 0; + break; } - clear_screen(GFX_BOTTOM); } consoleClear(); } else { - const char *confirm[] = { - "No! Return me to main menu.", - "Yes, continue with my selection.", - "Yes, but select EUR.", - "Yes, but select USA.", - "Yes, but select JPN.", - "ARR ARR SELECT THEM ALL." - }; - char foo[2]; - while(ret==0) - { - - sprintf(foo, " "); - int result = menu_draw(msg, foo, 0, sizeof(confirm) / sizeof(char*), confirm); - switch (result) - { - case 0: - ret=-1; break; - case 1: - ret=1; break; - case 2: - ret=1; region = "EUR"; break; - case 3: - ret=1; region = "USA"; break; - case 4: - ret=1; region = "JPN"; break; - case 5: - ret=1; region = "ALL"; break; - } - clear_screen(GFX_BOTTOM); + printf("Region set to %s, press A to continue,\nor any other to cancel.", region.c_str()); + u32 keys = wait_key(); + if (keys == KEY_A) + { + ret = 1; + } else { + ret = -1; } consoleClear(); } - return ret; -} + if (removing == true && region == "ALL") + { + printf(CONSOLE_RED); + printf("\nDanger, Will Robinson!"); + printf("\nThis will remove all tickets not in use." CONSOLE_RESET "\n"); + printf("\nPress A to continue,\nor any other to cancel.\n\n"); + u32 keys = wait_key(); + + if (keys == KEY_A) + { + ret = 1; + } else { + ret = -1; + } + } + if (removing == true && region == "REGION FREE") + { + printf(CONSOLE_RED); + printf("\nDanger, Will Robinson!"); + printf("\nThis will remove all tickets not in use.\n"); + printf("\nRegion free tickets will not be removed." CONSOLE_RESET "\n"); + printf("\nPress A to continue,\nor any other to cancel.\n\n"); + + u32 keys = wait_key(); + + if (keys & KEY_A) + { + ret = 1; + } else { + ret = -1; + } + } + + return ret; +} void select_oneclick() { consoleClear(); - int w = action_getconfirm(); - if(w<0)return; - action_download(); - action_table_strip(); + int w = action_getconfirm(false); + if (w<0)return; std::vector Keys; std::vector IDs; std::vector Regions; int n; action_missing_tickets(Keys, IDs, Regions, n, region, false); - action_generate(Keys, IDs, n); - action_install(IDs, n); - action_clean(IDs); - wait_key_specific("\n Press A to continue.\n", KEY_A); + action_install(Keys, IDs); + printf("\nPress A to open eShop."); + printf("\nPress B to return to the main menu."); + while(true) + { + u32 keys = wait_key(); + switch(keys) + { + case KEY_A: launch_eshop(); break; + case KEY_B: return; + } + } } - - -void select_removeout(){ +void select_removeout() +{ consoleClear(); - int w = action_getconfirm(); - if(w<0)return; + int w = action_getconfirm(true); + if (w<0)return; + printf("Deleting selected tickets...\n"); + std::vector Keys; std::vector IDs; std::vector Regions; int n; - action_missing_tickets(Keys, IDs, Regions, n, region, true); - printf("Done!"); + + action_missing_tickets(Keys, IDs, Regions, n, region, true); + action_delete(IDs); wait_key_specific("\nPress A to continue.\n", KEY_A); } bool menu_main_keypress(int selected, u32 key, void*) { - if (key & KEY_A) - { - switch (selected) - { - case 0: - select_oneclick(); - break; + if (key & KEY_A) + { + switch (selected) + { + case 0: + select_oneclick(); + break; + case 1: select_removeout(); - break; - - - case 2: - action_about(); break; - case 3: - bExit = true; break; - } - return true; - } - else if (key & KEY_L) - { - action_toggle_region(); - return true; - } + break; - return false; + case 2: + launch_eshop(); + break; + + case 3: + bExit = true; + break; + } + return true; + } + else if (key & KEY_L) + { + action_toggle_region(); + return true; + } + + return false; } void menu_main() { - const char *options[] = { + char footer[37]; + const char *options[] = { "Update your Tickets!", "Remove out-of-region tickets", - "About TIKdevil", - "Exit", - }; - char footer[37]; + "Launch eShop", + "Exit", + }; - while (!bExit) - { + while (!bExit) + { sprintf(footer, "Region: [%s] (Press L to change)", region.c_str()); menu_multkey_draw("TIKdevil by Kyraminol", footer, 0, sizeof(options) / sizeof(char*), options, NULL, menu_main_keypress); - clear_screen(GFX_BOTTOM); - } + } } int main(int argc, const char* argv[]) { - u32 *soc_sharedmem, soc_sharedmem_size = 0x100000; - gfxInitDefault(); - consoleInit(GFX_TOP, NULL); - - httpcInit(0); - soc_sharedmem = (u32 *)memalign(0x1000, soc_sharedmem_size); - socInit(soc_sharedmem, soc_sharedmem_size); - sslcInit(0); + u32 *soc_sharedmem, soc_sharedmem_size = 0x100000; + gfxInitDefault(); + consoleInit(GFX_TOP, NULL); + + httpcInit(0); + soc_sharedmem = (u32 *)memalign(0x1000, soc_sharedmem_size); + socInit(soc_sharedmem, soc_sharedmem_size); + sslcInit(0); amInit(); - AM_InitializeExternalTitleDatabase(false); + cfguInit(); + AM_InitializeExternalTitleDatabase(false); + + init_menu(GFX_TOP); + + // Make sure the TIKdevil directory exists on the SD card + mkpath("/TIKdevil/", 0777); + + // Load the region from system secure info + region = GetSystemRegion(); + + action_about(GFX_BOTTOM); + menu_main(); - init_menu(GFX_TOP); - menu_main(); - + cfguExit(); amExit(); - gfxExit(); - httpcExit(); - socExit(); - sslcExit(); + gfxExit(); + httpcExit(); + socExit(); + sslcExit(); } diff --git a/source/menu.c b/source/menu.c index fcb2319..4ffaea8 100644 --- a/source/menu.c +++ b/source/menu.c @@ -13,273 +13,273 @@ ConsoleMenu currentMenu; void init_menu(gfxScreen_t screen) { - // Create our new console, initialize it, and switch back to the previous console - currentMenu.menuConsole = *consoleGetDefault(); - PrintConsole* currentConsole = consoleSelect(¤tMenu.menuConsole); - consoleInit(screen, ¤tMenu.menuConsole); + // Create our new console, initialize it, and switch back to the previous console + currentMenu.menuConsole = *consoleGetDefault(); + PrintConsole* currentConsole = consoleSelect(¤tMenu.menuConsole); + consoleInit(screen, ¤tMenu.menuConsole); - consoleSelect(currentConsole); + consoleSelect(currentConsole); } void menu_draw_string(const char* str, int pos_x, int pos_y, const char* color) { - currentMenu.menuConsole.cursorX = pos_x; - currentMenu.menuConsole.cursorY = pos_y; - printf("%s%s%s", color, str, CONSOLE_RESET); + currentMenu.menuConsole.cursorX = pos_x; + currentMenu.menuConsole.cursorY = pos_y; + printf("%s%s%s", color, str, CONSOLE_RESET); - gfxFlushBuffers(); + gfxFlushBuffers(); } void menu_draw_string_full(const char* str, int pos_y, const char* color) { - currentMenu.menuConsole.cursorX = 0; - currentMenu.menuConsole.cursorY = pos_y; - printf(color); - - if (currentMenu.menuConsole.consoleWidth == 50) - { - printf("%-50s", str); - } - else - { - printf("%-40s", str); - } - printf(CONSOLE_RESET); - - gfxFlushBuffers(); + currentMenu.menuConsole.cursorX = 0; + currentMenu.menuConsole.cursorY = pos_y; + printf(color); + + if (currentMenu.menuConsole.consoleWidth == 50) + { + printf("%-50s", str); + } + else + { + printf("%-40s", str); + } + printf(CONSOLE_RESET); + + gfxFlushBuffers(); } int menu_draw(const char *title, const char* footer, int back, int count, const char *options[]) { - int selected = 0; - - // Select our menu console and clear the screen - PrintConsole* currentConsole = consoleSelect(¤tMenu.menuConsole); - consoleClear(); - - int current = 0; - int pos_y_text[count]; - int current_pos_y = 0; - - // Draw the header - menu_draw_string(title, 0, current_pos_y++, CONSOLE_RED); - - // Draw the menu - pos_y_text[0] = current_pos_y; - menu_draw_string(options[0], 1, current_pos_y++, CONSOLE_REVERSE); - // Don't allow the menu to draw beyond the edge of the screen, just truncate if so - for (int i = 1; i < count && i < (currentMenu.menuConsole.consoleHeight - 2); i++) { - pos_y_text[i] = current_pos_y; - menu_draw_string(options[i], 1, current_pos_y++, CONSOLE_WHITE); - } - - // Draw the footer if one is provided - if (footer != NULL) - { - current_pos_y = currentMenu.menuConsole.consoleHeight - 1; - menu_draw_string_full(footer, current_pos_y, CONSOLE_BLUE CONSOLE_REVERSE); - } - - while (true) { - u32 key = wait_key(); - - if (key & KEY_UP) { - menu_draw_string(options[current], 1, pos_y_text[current], CONSOLE_WHITE); - - if (current <= 0) { - current = count - 1; - } else { - current--; - } - - menu_draw_string(options[current], 1, pos_y_text[current], CONSOLE_REVERSE); - } else if (key & KEY_DOWN) { - menu_draw_string(options[current], 1, pos_y_text[current], CONSOLE_WHITE); - - if (current >= count - 1) { - current = 0; - } else { - current++; - } - - menu_draw_string(options[current], 1, pos_y_text[current], CONSOLE_REVERSE); - } else if (key & KEY_RIGHT) { - menu_draw_string(options[current], 1, pos_y_text[current], CONSOLE_WHITE); - - current += 5; - if (current >= count) current = count - 1; - - menu_draw_string(options[current], 1, pos_y_text[current], CONSOLE_REVERSE); - } else if (key & KEY_LEFT) { - menu_draw_string(options[current], 1, pos_y_text[current], CONSOLE_WHITE); - - current -= 5; - if (current < 0) current = 0; - - menu_draw_string(options[current], 1, pos_y_text[current], CONSOLE_REVERSE); - } else if (key & KEY_A) { - selected = current; - break; - } else if ((key & KEY_B) && back) { - selected = -1; - break; - } - } - - // Reselect the original console - consoleSelect(currentConsole); - return selected; + int selected = 0; + + // Select our menu console and clear the screen + PrintConsole* currentConsole = consoleSelect(¤tMenu.menuConsole); + consoleClear(); + + int current = 0; + int pos_y_text[count]; + int current_pos_y = 0; + + // Draw the header + menu_draw_string(title, 0, current_pos_y++, CONSOLE_RED); + + // Draw the menu + pos_y_text[0] = current_pos_y; + menu_draw_string(options[0], 1, current_pos_y++, CONSOLE_REVERSE); + // Don't allow the menu to draw beyond the edge of the screen, just truncate if so + for (int i = 1; i < count && i < (currentMenu.menuConsole.consoleHeight - 2); i++) { + pos_y_text[i] = current_pos_y; + menu_draw_string(options[i], 1, current_pos_y++, CONSOLE_WHITE); + } + + // Draw the footer if one is provided + if (footer != NULL) + { + current_pos_y = currentMenu.menuConsole.consoleHeight - 1; + menu_draw_string_full(footer, current_pos_y, CONSOLE_BLUE CONSOLE_REVERSE); + } + + while (true) { + u32 key = wait_key(); + + if (key & KEY_UP) { + menu_draw_string(options[current], 1, pos_y_text[current], CONSOLE_WHITE); + + if (current <= 0) { + current = count - 1; + } else { + current--; + } + + menu_draw_string(options[current], 1, pos_y_text[current], CONSOLE_REVERSE); + } else if (key & KEY_DOWN) { + menu_draw_string(options[current], 1, pos_y_text[current], CONSOLE_WHITE); + + if (current >= count - 1) { + current = 0; + } else { + current++; + } + + menu_draw_string(options[current], 1, pos_y_text[current], CONSOLE_REVERSE); + } else if (key & KEY_RIGHT) { + menu_draw_string(options[current], 1, pos_y_text[current], CONSOLE_WHITE); + + current += 5; + if (current >= count) current = count - 1; + + menu_draw_string(options[current], 1, pos_y_text[current], CONSOLE_REVERSE); + } else if (key & KEY_LEFT) { + menu_draw_string(options[current], 1, pos_y_text[current], CONSOLE_WHITE); + + current -= 5; + if (current < 0) current = 0; + + menu_draw_string(options[current], 1, pos_y_text[current], CONSOLE_REVERSE); + } else if (key & KEY_A) { + selected = current; + break; + } else if ((key & KEY_B) && back) { + selected = -1; + break; + } + } + + // Reselect the original console + consoleSelect(currentConsole); + return selected; } void menu_multkey_draw(const char *title, const char* footer, int back, int count, const char *options[], void* data, bool (*callback)(int result, u32 key, void* data)) { - int selected = 0; - - // Select our menu console and clear the screen - PrintConsole* currentConsole = consoleSelect(¤tMenu.menuConsole); - consoleClear(); - - int current = 0; - int pos_y_text[count]; - int current_pos_y = 0; - - // Draw the header - menu_draw_string(title, 0, current_pos_y++, CONSOLE_RED); - - // Draw the menu - pos_y_text[0] = current_pos_y; - menu_draw_string(options[0], 1, current_pos_y++, CONSOLE_REVERSE); - - // Don't allow the menu to draw beyond the edge of the screen, just truncate if so - for (int i = 1; i < count && i < (currentMenu.menuConsole.consoleHeight - 2); i++) { - pos_y_text[i] = current_pos_y; - menu_draw_string(options[i], 1, current_pos_y++, CONSOLE_WHITE); - } - - // Draw the footer if one is provided - if (footer != NULL) - { - current_pos_y = currentMenu.menuConsole.consoleHeight - 1; - menu_draw_string_full(footer, current_pos_y, CONSOLE_BLUE CONSOLE_REVERSE); - } - - while (true) { - u32 key = wait_key(); - - if (key & KEY_UP) { - menu_draw_string(options[current], 1, pos_y_text[current], CONSOLE_WHITE); - - if (current <= 0) { - current = count - 1; - } else { - current--; - } - - menu_draw_string(options[current], 1, pos_y_text[current], CONSOLE_REVERSE); - } else if (key & KEY_DOWN) { - menu_draw_string(options[current], 1, pos_y_text[current], CONSOLE_WHITE); - - if (current >= count - 1) { - current = 0; - } else { - current++; - } - - menu_draw_string(options[current], 1, pos_y_text[current], CONSOLE_REVERSE); - } else if (key & KEY_RIGHT) { - menu_draw_string(options[current], 1, pos_y_text[current], CONSOLE_WHITE); - - current += 5; - if (current >= count) current = count - 1; - - menu_draw_string(options[current], 1, pos_y_text[current], CONSOLE_REVERSE); - } else if (key & KEY_LEFT) { - menu_draw_string(options[current], 1, pos_y_text[current], CONSOLE_WHITE); - - current -= 5; - if (current < 0) current = 0; - - menu_draw_string(options[current], 1, pos_y_text[current], CONSOLE_REVERSE); - } else if (callback(current, key, data)) { - break; - } - } - - // Reselect the original console - consoleSelect(currentConsole); + // int selected = 0; + + // Select our menu console and clear the screen + PrintConsole* currentConsole = consoleSelect(¤tMenu.menuConsole); + consoleClear(); + + int current = 0; + int pos_y_text[count]; + int current_pos_y = 0; + + // Draw the header + menu_draw_string(title, 0, current_pos_y++, CONSOLE_RED); + + // Draw the menu + pos_y_text[0] = current_pos_y; + menu_draw_string(options[0], 1, current_pos_y++, CONSOLE_REVERSE); + + // Don't allow the menu to draw beyond the edge of the screen, just truncate if so + for (int i = 1; i < count && i < (currentMenu.menuConsole.consoleHeight - 2); i++) { + pos_y_text[i] = current_pos_y; + menu_draw_string(options[i], 1, current_pos_y++, CONSOLE_WHITE); + } + + // Draw the footer if one is provided + if (footer != NULL) + { + current_pos_y = currentMenu.menuConsole.consoleHeight - 1; + menu_draw_string_full(footer, current_pos_y, CONSOLE_BLUE CONSOLE_REVERSE); + } + + while (true) { + u32 key = wait_key(); + + if (key & KEY_UP) { + menu_draw_string(options[current], 1, pos_y_text[current], CONSOLE_WHITE); + + if (current <= 0) { + current = count - 1; + } else { + current--; + } + + menu_draw_string(options[current], 1, pos_y_text[current], CONSOLE_REVERSE); + } else if (key & KEY_DOWN) { + menu_draw_string(options[current], 1, pos_y_text[current], CONSOLE_WHITE); + + if (current >= count - 1) { + current = 0; + } else { + current++; + } + + menu_draw_string(options[current], 1, pos_y_text[current], CONSOLE_REVERSE); + } else if (key & KEY_RIGHT) { + menu_draw_string(options[current], 1, pos_y_text[current], CONSOLE_WHITE); + + current += 5; + if (current >= count) current = count - 1; + + menu_draw_string(options[current], 1, pos_y_text[current], CONSOLE_REVERSE); + } else if (key & KEY_LEFT) { + menu_draw_string(options[current], 1, pos_y_text[current], CONSOLE_WHITE); + + current -= 5; + if (current < 0) current = 0; + + menu_draw_string(options[current], 1, pos_y_text[current], CONSOLE_REVERSE); + } else if (callback(current, key, data)) { + break; + } + } + + // Reselect the original console + consoleSelect(currentConsole); } int *menu_draw_selection(const char *title, int count, const char *options[], const int *preselected) { - // The caller has to make sure it does not exceed MAX_SELECTED_OPTIONS - // if (count > MAX_SELECTED_OPTIONS) { - // return NULL; - // } - - // memset(selected_options, 0, sizeof(selected_options)); - - // int current = 0; - // int pos_x_text = 4 * SPACING_HORIZ; - // int pos_y_text[count]; - // int current_pos_y = 30; - - // clear_screen(GFX_TOP); - // draw_string(GFX_TOP, title, 0, 0, COLOR_TITLE); - - // pos_y_text[0] = current_pos_y; - // draw_string(GFX_TOP, "[ ]", 0, current_pos_y, COLOR_NEUTRAL); - // current_pos_y = draw_string(GFX_TOP, options[0], pos_x_text, current_pos_y, COLOR_SELECTED); - // int i; - // for (i = 1; i < count; i++) { - // current_pos_y += SPACING_VERT; - // pos_y_text[i] = current_pos_y; - // draw_string(GFX_TOP, "[ ]", 0, current_pos_y, COLOR_NEUTRAL); - // current_pos_y = draw_string(GFX_TOP, options[i], pos_x_text, current_pos_y, COLOR_NEUTRAL); - // } - // draw_string(GFX_TOP, "Press START to confirm", 0, current_pos_y + SPACING_VERT * 2, COLOR_SELECTED); - - // for (int i = 0; i < count; i++) { - // if (preselected[i]) { - // draw_character(GFX_TOP, 'x', 0 + SPACING_HORIZ, pos_y_text[i], COLOR_NEUTRAL); - // selected_options[i] = 1; - // } - // } - - // while (1) { - // u16 key = wait_key(); - - // if (key & KEY_UP) { - // draw_string(GFX_TOP, options[current], pos_x_text, pos_y_text[current], COLOR_NEUTRAL); - - // if (current <= 0) { - // current = count - 1; - // } else { - // current--; - // } - - // draw_string(GFX_TOP, options[current], pos_x_text, pos_y_text[current], COLOR_SELECTED); - // } else if (key & KEY_DOWN) { - // draw_string(GFX_TOP, options[current], pos_x_text, pos_y_text[current], COLOR_NEUTRAL); - - // if (current >= count - 1) { - // current = 0; - // } else { - // current++; - // } - - // draw_string(GFX_TOP, options[current], pos_x_text, pos_y_text[current], COLOR_SELECTED); - // } else if (key & KEY_A) { - // if (selected_options[current]) { - // draw_character(GFX_TOP, 'x', 0 + SPACING_HORIZ, pos_y_text[current], COLOR_BACKGROUND); - // selected_options[current] = 0; - // } else { - // draw_character(GFX_TOP, 'x', 0 + SPACING_HORIZ, pos_y_text[current], COLOR_NEUTRAL); - // selected_options[current] = 1; - // } - // } else if ((key & KEY_START) || (key & KEY_B)) { - // return selected_options; - // } - // } - return 0; + // The caller has to make sure it does not exceed MAX_SELECTED_OPTIONS + // if (count > MAX_SELECTED_OPTIONS) { + // return NULL; + // } + + // memset(selected_options, 0, sizeof(selected_options)); + + // int current = 0; + // int pos_x_text = 4 * SPACING_HORIZ; + // int pos_y_text[count]; + // int current_pos_y = 30; + + // clear_screen(GFX_TOP); + // draw_string(GFX_TOP, title, 0, 0, COLOR_TITLE); + + // pos_y_text[0] = current_pos_y; + // draw_string(GFX_TOP, "[ ]", 0, current_pos_y, COLOR_NEUTRAL); + // current_pos_y = draw_string(GFX_TOP, options[0], pos_x_text, current_pos_y, COLOR_SELECTED); + // int i; + // for (i = 1; i < count; i++) { + // current_pos_y += SPACING_VERT; + // pos_y_text[i] = current_pos_y; + // draw_string(GFX_TOP, "[ ]", 0, current_pos_y, COLOR_NEUTRAL); + // current_pos_y = draw_string(GFX_TOP, options[i], pos_x_text, current_pos_y, COLOR_NEUTRAL); + // } + // draw_string(GFX_TOP, "Press START to confirm", 0, current_pos_y + SPACING_VERT * 2, COLOR_SELECTED); + + // for (int i = 0; i < count; i++) { + // if (preselected[i]) { + // draw_character(GFX_TOP, 'x', 0 + SPACING_HORIZ, pos_y_text[i], COLOR_NEUTRAL); + // selected_options[i] = 1; + // } + // } + + // while (1) { + // u16 key = wait_key(); + + // if (key & KEY_UP) { + // draw_string(GFX_TOP, options[current], pos_x_text, pos_y_text[current], COLOR_NEUTRAL); + + // if (current <= 0) { + // current = count - 1; + // } else { + // current--; + // } + + // draw_string(GFX_TOP, options[current], pos_x_text, pos_y_text[current], COLOR_SELECTED); + // } else if (key & KEY_DOWN) { + // draw_string(GFX_TOP, options[current], pos_x_text, pos_y_text[current], COLOR_NEUTRAL); + + // if (current >= count - 1) { + // current = 0; + // } else { + // current++; + // } + + // draw_string(GFX_TOP, options[current], pos_x_text, pos_y_text[current], COLOR_SELECTED); + // } else if (key & KEY_A) { + // if (selected_options[current]) { + // draw_character(GFX_TOP, 'x', 0 + SPACING_HORIZ, pos_y_text[current], COLOR_BACKGROUND); + // selected_options[current] = 0; + // } else { + // draw_character(GFX_TOP, 'x', 0 + SPACING_HORIZ, pos_y_text[current], COLOR_NEUTRAL); + // selected_options[current] = 1; + // } + // } else if ((key & KEY_START) || (key & KEY_B)) { + // return selected_options; + // } + // } + return 0; } diff --git a/source/menu.h b/source/menu.h index aeaca5d..f79ac90 100644 --- a/source/menu.h +++ b/source/menu.h @@ -13,6 +13,17 @@ extern "C" { #define COLOR_SELECTED 0xFF0000 #define COLOR_BACKGROUND 0x000000 +#define CONSOLE_ESC(x) "\x1b[" #x +#define CONSOLE_RESET CONSOLE_ESC(0m) +#define CONSOLE_BLACK CONSOLE_ESC(30m) +#define CONSOLE_RED CONSOLE_ESC(31;1m) +#define CONSOLE_GREEN CONSOLE_ESC(32;1m) +#define CONSOLE_YELLOW CONSOLE_ESC(33;1m) +#define CONSOLE_BLUE CONSOLE_ESC(34;1m) +#define CONSOLE_MAGENTA CONSOLE_ESC(35;1m) +#define CONSOLE_CYAN CONSOLE_ESC(36;1m) +#define CONSOLE_WHITE CONSOLE_ESC(37;1m) + #define CONSOLE_REVERSE CONSOLE_ESC(7m) typedef struct ConsoleMenu { @@ -26,4 +37,4 @@ int *menu_draw_selection(const char *title, int count, const char *options[], co #ifdef __cplusplus } -#endif \ No newline at end of file +#endif diff --git a/source/types.h b/source/types.h index f7ea835..d1dd284 100755 --- a/source/types.h +++ b/source/types.h @@ -41,9 +41,6 @@ typedef enum typedef enum { - BIG_ENDIAN = 0, - LITTLE_ENDIAN = 1, BE = 0, LE = 1 } endianness_flag; - diff --git a/source/utils.c b/source/utils.c deleted file mode 100755 index 428bbc1..0000000 --- a/source/utils.c +++ /dev/null @@ -1,532 +0,0 @@ -/** -Copyright 2013 3DSGuy - -This file is part of make_cdn_cia. - -make_cdn_cia is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -make_cdn_cia is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with make_cdn_cia. If not, see . -**/ -#include "lib.h" -#include "utils.h" - -//MISC -void char_to_int_array(unsigned char destination[], char source[], int size, int endianness, int base) -{ - char tmp[size][2]; - unsigned char *byte_array = malloc(size*sizeof(unsigned char)); - memset(byte_array, 0, size); - memset(destination, 0, size); - memset(tmp, 0, size*2); - - for (int i = 0; i < size; i ++){ - tmp[i][0] = source[(i*2)]; - tmp[i][1] = source[((i*2)+1)]; - tmp[i][2] = '\0'; - byte_array[i] = (unsigned char)strtol(tmp[i], NULL, base); - } - endian_memcpy(destination,byte_array,size,endianness); - /** - for (int i = 0; i < size; i++){ - switch (endianness){ - case(BIG_ENDIAN): - destination[i] = byte_array[i]; - break; - case(LITTLE_ENDIAN): - destination[i] = byte_array[((size-1)-i)]; - break; - } - } - **/ - free(byte_array); -} - -void endian_memcpy(u8 *destination, u8 *source, u32 size, int endianness) -{ - for (u32 i = 0; i < size; i++){ - switch (endianness){ - case(BIG_ENDIAN): - destination[i] = source[i]; - break; - case(LITTLE_ENDIAN): - destination[i] = source[((size-1)-i)]; - break; - } - } -} - -void u8_hex_print_be(u8 *array, int len) -{ - for(int i = 0; i < len; i++) - printf("%02x",array[i]); -} - -void u8_hex_print_le(u8 *array, int len) -{ - for(int i = 0; i < len; i++) - printf("%02x",array[len - i - 1]); -} - -u32 align_value(u32 value, u32 alignment) -{ - u32 tmp = value; - while(tmp > alignment) - tmp -= alignment; - return (value + (alignment - tmp)); -} - -void resolve_flag(unsigned char flag, unsigned char *flag_bool) -{ - unsigned char bit_mask[8] = {0x80,0x40,0x20,0x10,0x8,0x4,0x2,0x1}; - for(int i = 0; i < 8; i++){ - if (flag >= bit_mask[i]){ - flag_bool[7-i] = True; - flag -= bit_mask[i]; - } - else - flag_bool[7-i] = False; - } -} - -void resolve_flag_u16(u16 flag, unsigned char *flag_bool) -{ - u16 bit_mask[16] = {0x8000,0x4000,0x2000,0x1000,0x800,0x400,0x200,0x100,0x80,0x40,0x20,0x10,0x8,0x4,0x2,0x1}; - for(int i = 0; i < 16; i++){ - if (flag >= bit_mask[i]){ - flag_bool[15-i] = True; - flag -= bit_mask[i]; - } - else - flag_bool[15-i] = False; - } -} - -//IO Related -void PrintProgress(u32 nSize, u32 nCurrent) -{ - // Don't attempt to calculate anything if we don't have a final size - if (nSize == 0) return; - - // Calculate percent and bar width - double fPercent = ((double)nCurrent / nSize) * 100.0; - u16 barDrawWidth = (fPercent / 100) * 40; - - int i = 0; - printf("% 3.2f%% ", fPercent); - for (i = 0; i < barDrawWidth; i++) - { - printf("|"); - } - printf("\r"); - - // Make sure the screen updates - gfxFlushBuffers(); - gspWaitForVBlank(); -} - -void WriteBuffer(void *buffer, u64 size, u64 offset, FILE *output) -{ - fseek_64(output,offset,SEEK_SET); - fwrite(buffer,size,1,output); -} - -void write_align_padding(FILE *output, size_t alignment) -{ - long int pos = ftell(output); - long int usedbytes = pos & (alignment - 1); - if (usedbytes) - { - long int padbytes = (alignment - usedbytes); - char* pad = (char*)malloc(padbytes); - memset(pad, 0, padbytes); - fwrite(pad, padbytes, 1, output); - free(pad); - } -} - -u64 GetFileSize_u64(char *filename) -{ - u64 size; -#ifdef _WIN32 - int fh; - u64 n; - fh = _open( filename, 0 ); - n = _lseeki64(fh, 0, SEEK_END); - _close(fh); - size = (n / sizeof(short))*2; -#else - FILE *file = fopen(filename,"rb"); - fseeko(file, 0L, SEEK_END); - size = ftello(file); - fclose(file); -#endif - return size; -} - -int TruncateFile_u64(char *filename, u64 filelen) -{ -#ifdef _WIN32 - HANDLE fh; - - LARGE_INTEGER fp; - fp.QuadPart = filelen; - - fh = CreateFile(filename, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); - if (fh == INVALID_HANDLE_VALUE) { - printf("[!] Invalid File handle\n"); - return 1; - } - - if (SetFilePointerEx(fh, fp, NULL, FILE_BEGIN) == 0 || - SetEndOfFile(fh) == 0) { - printf("[!] truncate failed\n"); - CloseHandle(fh); - return 1; - } - - CloseHandle(fh); - return 0; -#else - return truncate(filename,filelen); -#endif -} - -int fseek_64(FILE *fp, u64 file_pos, int whence) -{ -#ifdef _WIN32 - fpos_t pos = file_pos; - return fsetpos(fp,&pos); //I can't believe the 2gb problem with Windows & MINGW, maybe I have a bad installation :/ -#else - return fseeko(fp,file_pos,whence); -#endif -} - -int makedir(const char* dir) -{ -#ifdef _WIN32 - return _mkdir(dir); -#else - return mkdir(dir, 0777); -#endif -} - -char *getcwdir(char *buffer,int maxlen) -{ -#ifdef _WIN32 -return _getcwd(buffer,maxlen); -#else -return getcwd(buffer,maxlen); -#endif -} - -void DownloadFile_InternalSave(void* out, unsigned char* buffer, u32 readSize) -{ - FILE* os = (FILE*)out; - fwrite(buffer, readSize, 1, os); -} - -static u32 install_offset = 0; -void DownloadFile_InternalInstall(void* out, unsigned char* buffer, u32 readSize) -{ - u32 bytesWritten; - Handle* handle = (Handle*)out; - - FSFILE_Write(*handle, &bytesWritten, install_offset, buffer, readSize, 0); - - install_offset += bytesWritten; -} - -Result DownloadFile_Internal(const char *url, void *out, bool bProgress, - void (*write)(void* out, unsigned char* buffer, u32 readSize)) -{ - httpcContext context; - u32 fileSize = 0; - u32 procSize = 0; - Result ret = 0; - Result dlret = HTTPC_RESULTCODE_DOWNLOADPENDING; - u32 status; - u32 bufSize = 0x100000; - u32 readSize = 0; - httpcOpenContext(&context, HTTPC_METHOD_GET, (char*)url, 1); - - ret = httpcBeginRequest(&context); - if (ret != 0) goto _out; - - ret = httpcGetResponseStatusCode(&context, &status, 0); - if (ret != 0) goto _out; - - if (status != 200) - { - ret = status; - goto _out; - } - - ret = httpcGetDownloadSizeState(&context, NULL, &fileSize); - if (ret != 0) goto _out; - - { - unsigned char *buffer = (unsigned char *)linearAlloc(bufSize); - if (buffer == NULL) - { - printf("Error allocating download buffer\n"); - ret = -1; - goto _out; - } - - while (dlret == (s32)HTTPC_RESULTCODE_DOWNLOADPENDING) - { - memset(buffer, 0, bufSize); - - dlret = httpcDownloadData(&context, buffer, bufSize, &readSize); - write(out, buffer, readSize); - - procSize += readSize; - if (bProgress) - { - PrintProgress(fileSize, procSize); - } - } - linearFree(buffer); - } -_out: - httpcCloseContext(&context); - - return ret; -} - - -Result DownloadFile(const char *url, FILE *os, bool bProgress) -{ - return DownloadFile_Internal(url, os, bProgress, DownloadFile_InternalSave); -} - - -Result DownloadFileInstall(const char *url, Handle *handle, u32* offset) -{ - install_offset = *offset; - Result res = DownloadFile_Internal(url, handle, true, DownloadFile_InternalInstall); - *offset = install_offset; - return res; -} - -//Data Size conversion -/* -u16 u8_to_u16(u8 *value, u8 endianness) -{ - u16 new_value; - switch(endianness){ - case(BIG_ENDIAN): new_value = (value[1]<<0) | (value[0]<<8); break; - case(LITTLE_ENDIAN): new_value = (value[0]<<0) | (value[1]<<8); break; - } - return new_value; -} - -u32 u8_to_u32(u8 *value, u8 endianness) -{ - u32 new_value; - switch(endianness){ - case(BIG_ENDIAN): new_value = (value[3]<<0) | (value[2]<<8) | (value[1]<<16) | (value[0]<<24); break; - case(LITTLE_ENDIAN): new_value = (value[0]<<0) | (value[1]<<8) | (value[2]<<16) | (value[3]<<24); break; - } - return new_value; -}*/ - - -u64 u8_to_u64(u8 *value, u8 endianness) -{ - u64 u64_return = 0; - switch(endianness){ - case(BIG_ENDIAN): - u64_return |= (u64)value[7]<<0; - u64_return |= (u64)value[6]<<8; - u64_return |= (u64)value[5]<<16; - u64_return |= (u64)value[4]<<24; - u64_return |= (u64)value[3]<<32; - u64_return |= (u64)value[2]<<40; - u64_return |= (u64)value[1]<<48; - u64_return |= (u64)value[0]<<56; - break; - //return (value[7]<<0) | (value[6]<<8) | (value[5]<<16) | (value[4]<<24) | (value[3]<<32) | (value[2]<<40) | (value[1]<<48) | (value[0]<<56); - case(LITTLE_ENDIAN): - u64_return |= (u64)value[0]<<0; - u64_return |= (u64)value[1]<<8; - u64_return |= (u64)value[2]<<16; - u64_return |= (u64)value[3]<<24; - u64_return |= (u64)value[4]<<32; - u64_return |= (u64)value[5]<<40; - u64_return |= (u64)value[6]<<48; - u64_return |= (u64)value[7]<<56; - break; - //return (value[0]<<0) | (value[1]<<8) | (value[2]<<16) | (value[3]<<24) | (value[4]<<32) | (value[5]<<40) | (value[6]<<48) | (value[7]<<56); - } - return u64_return; -} - -int u16_to_u8(u8 *out_value, u16 in_value, u8 endianness) -{ - switch(endianness){ - case(BIG_ENDIAN): - out_value[0]=(in_value >> 8); - out_value[1]=(in_value >> 0); - break; - case(LITTLE_ENDIAN): - out_value[0]=(in_value >> 0); - out_value[1]=(in_value >> 8); - break; - } - return 0; -} - -int u32_to_u8(u8 *out_value, u32 in_value, u8 endianness) -{ - switch(endianness){ - case(BIG_ENDIAN): - out_value[0]=(in_value >> 24); - out_value[1]=(in_value >> 16); - out_value[2]=(in_value >> 8); - out_value[3]=(in_value >> 0); - break; - case(LITTLE_ENDIAN): - out_value[0]=(in_value >> 0); - out_value[1]=(in_value >> 8); - out_value[2]=(in_value >> 16); - out_value[3]=(in_value >> 24); - break; - } - return 0; -} - -int u64_to_u8(u8 *out_value, u64 in_value, u8 endianness) -{ - switch(endianness){ - case(BIG_ENDIAN): - out_value[0]=(in_value >> 56); - out_value[1]=(in_value >> 48); - out_value[2]=(in_value >> 40); - out_value[3]=(in_value >> 32); - out_value[4]=(in_value >> 24); - out_value[5]=(in_value >> 16); - out_value[6]=(in_value >> 8); - out_value[7]=(in_value >> 0); - break; - case(LITTLE_ENDIAN): - out_value[0]=(in_value >> 0); - out_value[1]=(in_value >> 8); - out_value[2]=(in_value >> 16); - out_value[3]=(in_value >> 24); - out_value[4]=(in_value >> 32); - out_value[5]=(in_value >> 40); - out_value[6]=(in_value >> 48); - out_value[7]=(in_value >> 56); - break; - } - return 0; -} - -/* -void memdump(FILE* fout, const char* prefix, const u8* data, u32 size) -{ - u32 i; - u32 prefixlen = strlen(prefix); - u32 offs = 0; - u32 line = 0; - while(size) - { - u32 max = 32; - - if (max > size) - max = size; - - if (line==0) - fprintf(fout, "%s", prefix); - else - fprintf(fout, "%*s", prefixlen, ""); - - - for(i=0; i 0) - { - return keys; - } - gfxFlushBuffers(); - gspWaitForVBlank(); - } -} - -u32 wait_key_specific(const char* message, u32 key) -{ - printf(message); - while (true) - { - u32 keys = wait_key(); - if (keys & key) - { - return keys; - } - } -} - -// Graphics Functions -void clear_screen(gfxScreen_t screen) -{ - u8* buffer1; - u8* buffer2 = NULL; - u16 width, height; - u32 bpp; - GSPGPU_FramebufferFormats format = gfxGetScreenFormat(screen); - - if (screen == GFX_TOP) - { - buffer1 = gfxGetFramebuffer(screen, GFX_LEFT, &width, &height); - buffer2 = gfxGetFramebuffer(screen, GFX_RIGHT, &width, &height); - } else { - buffer1 = gfxGetFramebuffer(screen, GFX_LEFT, &width, &height); - } - - switch (format) - { - case GSP_RGBA8_OES: - bpp = 4; - case GSP_BGR8_OES: - bpp = 3; - case GSP_RGB565_OES: - case GSP_RGB5_A1_OES: - case GSP_RGBA4_OES: - bpp = 2; - default: - bpp = 3; - } - - memset(buffer1, 0, (width * height * bpp)); - if (buffer2) - memset(buffer2, 0, (width * height * bpp)); - - gfxFlushBuffers(); - gfxSwapBuffers(); - gspWaitForVBlank(); -} \ No newline at end of file diff --git a/source/utils.cpp b/source/utils.cpp new file mode 100644 index 0000000..d24c9d8 --- /dev/null +++ b/source/utils.cpp @@ -0,0 +1,801 @@ +/** +Copyright 2013 3DSGuy + +This file is part of make_cdn_cia. + +make_cdn_cia is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +make_cdn_cia is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with make_cdn_cia. If not, see . +**/ +#include "lib.h" +#include "data/builtin_rootca_bin.h" +#include "utils.h" + +#include +#include +#include +#include +#include + +//MISC +void char_to_int_array(unsigned char destination[], char source[], int size, int endianness, int base) +{ + char tmp[size][2]; + unsigned char *byte_array = (unsigned char *)malloc(size*sizeof(unsigned char)); + memset(byte_array, 0, size); + memset(destination, 0, size); + memset(tmp, 0, size*2); + + for (int i = 0; i < size; i ++){ + tmp[i][0] = source[(i*2)]; + tmp[i][1] = source[((i*2)+1)]; + tmp[i][2] = '\0'; + byte_array[i] = (unsigned char)strtol(tmp[i], NULL, base); + } + endian_memcpy(destination,byte_array,size,endianness); + /** + for (int i = 0; i < size; i++){ + switch (endianness){ + case(BE): + destination[i] = byte_array[i]; + break; + case(LE): + destination[i] = byte_array[((size-1)-i)]; + break; + } + } + **/ + free(byte_array); +} + +void endian_memcpy(u8 *destination, u8 *source, u32 size, int endianness) +{ + for (u32 i = 0; i < size; i++){ + switch (endianness){ + case(BE): + destination[i] = source[i]; + break; + case(LE): + destination[i] = source[((size-1)-i)]; + break; + } + } +} + +void u8_hex_print_be(u8 *array, int len) +{ + for(int i = 0; i < len; i++) + printf("%02x",array[i]); +} + +void u8_hex_print_le(u8 *array, int len) +{ + for(int i = 0; i < len; i++) + printf("%02x",array[len - i - 1]); +} + +u32 align_value(u32 value, u32 alignment) +{ + u32 tmp = value; + while(tmp > alignment) + tmp -= alignment; + return (value + (alignment - tmp)); +} + +void resolve_flag(unsigned char flag, unsigned char *flag_bool) +{ + unsigned char bit_mask[8] = {0x80,0x40,0x20,0x10,0x8,0x4,0x2,0x1}; + for(int i = 0; i < 8; i++){ + if (flag >= bit_mask[i]){ + flag_bool[7-i] = True; + flag -= bit_mask[i]; + } + else + flag_bool[7-i] = False; + } +} + +void resolve_flag_u16(u16 flag, unsigned char *flag_bool) +{ + u16 bit_mask[16] = {0x8000,0x4000,0x2000,0x1000,0x800,0x400,0x200,0x100,0x80,0x40,0x20,0x10,0x8,0x4,0x2,0x1}; + for(int i = 0; i < 16; i++){ + if (flag >= bit_mask[i]){ + flag_bool[15-i] = True; + flag -= bit_mask[i]; + } + else + flag_bool[15-i] = False; + } +} + +//IO Related +void PrintProgress(u32 nSize, u32 nCurrent) +{ + // Don't attempt to calculate anything if we don't have a final size + if (nSize == 0) return; + + // Calculate percent and bar width + double fPercent = ((double)nCurrent / nSize) * 100.0; + u16 barDrawWidth = (fPercent / 100) * 40; + + int i = 0; + printf("% 3.2f%% ", fPercent); + for (i = 0; i < barDrawWidth; i++) + { + printf("|"); + } + printf("\r"); + + // Make sure the screen updates + gfxFlushBuffers(); + gspWaitForVBlank(); +} + +void WriteBuffer(void *buffer, u64 size, u64 offset, FILE *output) +{ + fseek_64(output,offset,SEEK_SET); + fwrite(buffer,size,1,output); +} + +void write_align_padding(FILE *output, size_t alignment) +{ + long int pos = ftell(output); + long int usedbytes = pos & (alignment - 1); + if (usedbytes) + { + long int padbytes = (alignment - usedbytes); + char* pad = (char*)malloc(padbytes); + memset(pad, 0, padbytes); + fwrite(pad, padbytes, 1, output); + free(pad); + } +} + +u64 GetFileSize_u64(char *filename) +{ + u64 size; +#ifdef _WIN32 + int fh; + u64 n; + fh = _open( filename, 0 ); + n = _lseeki64(fh, 0, SEEK_END); + _close(fh); + size = (n / sizeof(short))*2; +#else + FILE *file = fopen(filename,"rb"); + fseeko(file, 0L, SEEK_END); + size = ftello(file); + fclose(file); +#endif + return size; +} + +int TruncateFile_u64(char *filename, u64 filelen) +{ +#ifdef _WIN32 + HANDLE fh; + + LARGE_INTEGER fp; + fp.QuadPart = filelen; + + fh = CreateFile(filename, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); + if (fh == INVALID_HANDLE_VALUE) { + printf("[!] Invalid File handle\n"); + return 1; + } + + if (SetFilePointerEx(fh, fp, NULL, FILE_BEGIN) == 0 || + SetEndOfFile(fh) == 0) { + printf("[!] truncate failed\n"); + CloseHandle(fh); + return 1; + } + + CloseHandle(fh); + return 0; +#else + return truncate(filename,filelen); +#endif +} + +int fseek_64(FILE *fp, u64 file_pos, int whence) +{ +#ifdef _WIN32 + fpos_t pos = file_pos; + return fsetpos(fp,&pos); //I can't believe the 2gb problem with Windows & MINGW, maybe I have a bad installation :/ +#else + return fseeko(fp,file_pos,whence); +#endif +} + +int makedir(const char* dir) +{ +#ifdef _WIN32 + return _mkdir(dir); +#else + return mkdir(dir, 0777); +#endif +} + +char *getcwdir(char *buffer,int maxlen) +{ +#ifdef _WIN32 +return _getcwd(buffer,maxlen); +#else +return getcwd(buffer,maxlen); +#endif +} + +void DownloadFile_InternalSave(void* out, unsigned char* buffer, u32 readSize) +{ + FILE* os = (FILE*)out; + fwrite(buffer, readSize, 1, os); +} + +static u32 install_offset = 0; +void DownloadFile_InternalInstall(void* out, unsigned char* buffer, u32 readSize) +{ + u32 bytesWritten; + Handle* handle = (Handle*)out; + + FSFILE_Write(*handle, &bytesWritten, install_offset, buffer, readSize, 0); + + install_offset += bytesWritten; +} + +Result DownloadFile_Internal(const char *url, void *out, bool bProgress, + void (*write)(void* out, unsigned char* buffer, u32 readSize)) +{ + httpcContext context; + u32 fileSize = 0; + u32 procSize = 0; + Result ret = 0; + Result dlret = HTTPC_RESULTCODE_DOWNLOADPENDING; + u32 status; + u32 bufSize = 0x100000; + u32 readSize = 0; + httpcOpenContext(&context, HTTPC_METHOD_GET, (char*)url, 1); + + ret = httpcBeginRequest(&context); + if (ret != 0) goto _out; + + ret = httpcGetResponseStatusCode(&context, &status); + if (ret != 0) goto _out; + + if (status != 200) + { + ret = status; + goto _out; + } + + ret = httpcGetDownloadSizeState(&context, NULL, &fileSize); + if (ret != 0) goto _out; + + { + unsigned char *buffer = (unsigned char *)linearAlloc(bufSize); + if (buffer == NULL) + { + printf("Error allocating download buffer\n"); + ret = -1; + goto _out; + } + + while (dlret == (s32)HTTPC_RESULTCODE_DOWNLOADPENDING) + { + memset(buffer, 0, bufSize); + + dlret = httpcDownloadData(&context, buffer, bufSize, &readSize); + write(out, buffer, readSize); + + procSize += readSize; + if (bProgress) + { + PrintProgress(fileSize, procSize); + } + } + linearFree(buffer); + } +_out: + httpcCloseContext(&context); + + return ret; +} + +Result DownloadFileSecure_Internal(const char *hostname, const char* request, void *out, bool bProgress, + void (*write)(void* out, unsigned char* buffer, u32 readSize)) +{ + Result ret=0; + + struct addrinfo hints; + struct addrinfo *resaddr = NULL, *resaddr_cur; + int sockfd; + u8 *readbuf = (u8 *)linearAlloc(0x400); + + sslcContext sslc_context; + //u32 RootCertChain_contexthandle=0; + + sockfd = socket(AF_INET, SOCK_STREAM, 0); + if(sockfd==-1) + { + printf("Failed to create the socket.\n"); + return -1; + } + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + + if(getaddrinfo(hostname, "443", &hints, &resaddr)!=0) + { + printf("getaddrinfo() failed.\n"); + closesocket(sockfd); + return -1; + } + + for(resaddr_cur = resaddr; resaddr_cur!=NULL; resaddr_cur = resaddr_cur->ai_next) + { + if(connect(sockfd, resaddr_cur->ai_addr, resaddr_cur->ai_addrlen)==0)break; + } + + freeaddrinfo(resaddr); + + if(resaddr_cur==NULL) + { + printf("Failed to connect.\n"); + closesocket(sockfd); + return -1; + } + + /*ret = sslcCreateRootCertChain(&RootCertChain_contexthandle); + if(R_FAILED(ret)) + { + printf("sslcCreateRootCertChain() failed: 0x%08x.\n", (unsigned int)ret); + closesocket(sockfd); + return ret; + } + ret = sslcAddTrustedRootCA(RootCertChain_contexthandle, (u8*)builtin_rootca_bin, builtin_rootca_bin_len, NULL); + if(R_FAILED(ret)) + { + printf("sslcAddTrustedRootCA() failed: 0x%08x.\n", (unsigned int)ret); + closesocket(sockfd); + sslcDestroyRootCertChain(RootCertChain_contexthandle); + return ret; + }*/ + + // For the life of me can't get the 3DS to accept a Let's Encrypt cert, so for now don't verify + ret = sslcCreateContext(&sslc_context, sockfd, SSLCOPT_Default | SSLCOPT_DisableVerify, (char*)hostname); + if(R_FAILED(ret)) + { + printf("sslcCreateContext() failed: 0x%08x.\n", (unsigned int)ret); + closesocket(sockfd); + //sslcDestroyRootCertChain(RootCertChain_contexthandle); + return ret; + } + + /*ret = sslcContextSetRootCertChain(&sslc_context, RootCertChain_contexthandle); + if(R_FAILED(ret)) + { + printf("sslcContextSetRootCertChain() failed: 0x%08x.\n", (unsigned int)ret); + sslcDestroyContext(&sslc_context); + sslcDestroyRootCertChain(RootCertChain_contexthandle); + closesocket(sockfd); + return ret; + }*/ + + ret = sslcStartConnection(&sslc_context, NULL, NULL); + if(R_FAILED(ret)) + { + printf("sslcStartConnection() failed: 0x%08x.\n", (unsigned int)ret); + sslcDestroyContext(&sslc_context); + //sslcDestroyRootCertChain(RootCertChain_contexthandle); + closesocket(sockfd); + return ret; + } + + ret = sslcWrite(&sslc_context, (u8*)request, strlen(request)); + if(R_FAILED(ret)) + { + printf("sslcWrite() failed: 0x%08x.\n", (unsigned int)ret); + sslcDestroyContext(&sslc_context); + //sslcDestroyRootCertChain(RootCertChain_contexthandle); + closesocket(sockfd); + return ret; + } + + memset(readbuf, 0, 0x400); + + bool bHeaderEnded = false; + while ((ret = sslcRead(&sslc_context, readbuf, 0x400-1, false)) > 0) + { + if(R_FAILED(ret)) + { + printf("sslcWrite() failed: 0x%08x.\n", (unsigned int)ret); + sslcDestroyContext(&sslc_context); + //sslcDestroyRootCertChain(RootCertChain_contexthandle); + closesocket(sockfd); + return ret; + } + + if (!bHeaderEnded) + { + // Skip over the header, we don't really care about its contents. + // Technically there's a very slim chance this fails to find the header + char* headend = strstr((const char*)readbuf, "\r\n\r\n"); + if (headend != NULL) + { + int headlen = (headend - (char*)readbuf) + 4; + write(out, (u8*)(headend + 4), (ret - headlen)); + bHeaderEnded = true; + } + } + else + { + write(out, readbuf, ret); + } + } + + sslcDestroyContext(&sslc_context); + //sslcDestroyRootCertChain(RootCertChain_contexthandle); + + closesocket(sockfd); + + return 0; +} + +Result DownloadFile(const char *url, FILE *os, bool bProgress) +{ + if (strlen(url) > 5 && strstr(url, "https:") != NULL) + { + // For HTTPS, we assume a properly formatted URL + std::string sUrl = url; + int nHostEnd = sUrl.find("/", 8); + std::string sPath = sUrl.substr(nHostEnd); + std::string sHost = sUrl.substr(8, nHostEnd - 8); + // I am so sorry for HTTP/1.0, but I can't be bothered to write chunked data handling right now + std::string sRequest = "GET " + sPath + " HTTP/1.0\r\nUser-Agent: TIKdevil\r\nConnection: close\r\nHost: " + sHost + "\r\n\r\n"; + + return DownloadFileSecure_Internal(sHost.c_str(), sRequest.c_str(), os, bProgress, DownloadFile_InternalSave); + } + else + { + return DownloadFile_Internal(url, os, bProgress, DownloadFile_InternalSave); + } +} + +Result DownloadFileInstall(const char *url, Handle *handle, u32* offset) +{ + install_offset = *offset; + Result res = DownloadFile_Internal(url, handle, true, DownloadFile_InternalInstall); + *offset = install_offset; + return res; +} + +//Data Size conversion +/* +u16 u8_to_u16(u8 *value, u8 endianness) +{ + u16 new_value; + switch(endianness){ + case(BE): new_value = (value[1]<<0) | (value[0]<<8); break; + case(LE): new_value = (value[0]<<0) | (value[1]<<8); break; + } + return new_value; +} + +u32 u8_to_u32(u8 *value, u8 endianness) +{ + u32 new_value; + switch(endianness){ + case(BE): new_value = (value[3]<<0) | (value[2]<<8) | (value[1]<<16) | (value[0]<<24); break; + case(LE): new_value = (value[0]<<0) | (value[1]<<8) | (value[2]<<16) | (value[3]<<24); break; + } + return new_value; +}*/ + + +u64 u8_to_u64(u8 *value, u8 endianness) +{ + u64 u64_return = 0; + switch(endianness){ + case(BE): + u64_return |= (u64)value[7]<<0; + u64_return |= (u64)value[6]<<8; + u64_return |= (u64)value[5]<<16; + u64_return |= (u64)value[4]<<24; + u64_return |= (u64)value[3]<<32; + u64_return |= (u64)value[2]<<40; + u64_return |= (u64)value[1]<<48; + u64_return |= (u64)value[0]<<56; + break; + //return (value[7]<<0) | (value[6]<<8) | (value[5]<<16) | (value[4]<<24) | (value[3]<<32) | (value[2]<<40) | (value[1]<<48) | (value[0]<<56); + case(LE): + u64_return |= (u64)value[0]<<0; + u64_return |= (u64)value[1]<<8; + u64_return |= (u64)value[2]<<16; + u64_return |= (u64)value[3]<<24; + u64_return |= (u64)value[4]<<32; + u64_return |= (u64)value[5]<<40; + u64_return |= (u64)value[6]<<48; + u64_return |= (u64)value[7]<<56; + break; + //return (value[0]<<0) | (value[1]<<8) | (value[2]<<16) | (value[3]<<24) | (value[4]<<32) | (value[5]<<40) | (value[6]<<48) | (value[7]<<56); + } + return u64_return; +} + +int u16_to_u8(u8 *out_value, u16 in_value, u8 endianness) +{ + switch(endianness){ + case(BE): + out_value[0]=(in_value >> 8); + out_value[1]=(in_value >> 0); + break; + case(LE): + out_value[0]=(in_value >> 0); + out_value[1]=(in_value >> 8); + break; + } + return 0; +} + +int u32_to_u8(u8 *out_value, u32 in_value, u8 endianness) +{ + switch(endianness){ + case(BE): + out_value[0]=(in_value >> 24); + out_value[1]=(in_value >> 16); + out_value[2]=(in_value >> 8); + out_value[3]=(in_value >> 0); + break; + case(LE): + out_value[0]=(in_value >> 0); + out_value[1]=(in_value >> 8); + out_value[2]=(in_value >> 16); + out_value[3]=(in_value >> 24); + break; + } + return 0; +} + +int u64_to_u8(u8 *out_value, u64 in_value, u8 endianness) +{ + switch(endianness){ + case(BE): + out_value[0]=(in_value >> 56); + out_value[1]=(in_value >> 48); + out_value[2]=(in_value >> 40); + out_value[3]=(in_value >> 32); + out_value[4]=(in_value >> 24); + out_value[5]=(in_value >> 16); + out_value[6]=(in_value >> 8); + out_value[7]=(in_value >> 0); + break; + case(LE): + out_value[0]=(in_value >> 0); + out_value[1]=(in_value >> 8); + out_value[2]=(in_value >> 16); + out_value[3]=(in_value >> 24); + out_value[4]=(in_value >> 32); + out_value[5]=(in_value >> 40); + out_value[6]=(in_value >> 48); + out_value[7]=(in_value >> 56); + break; + } + return 0; +} + +/* +void memdump(FILE* fout, const char* prefix, const u8* data, u32 size) +{ + u32 i; + u32 prefixlen = strlen(prefix); + u32 offs = 0; + u32 line = 0; + while(size) + { + u32 max = 32; + + if (max > size) + max = size; + + if (line==0) + fprintf(fout, "%s", prefix); + else + fprintf(fout, "%*s", prefixlen, ""); + + + for(i=0; i 0) + { + return keys; + } + gfxFlushBuffers(); + gspWaitForVBlank(); + } +} + +u32 wait_key_specific(const char* message, u32 key) +{ + printf(message); + while (true) + { + u32 keys = wait_key(); + if (keys & key) + { + return keys; + } + } +} + +// Graphics Functions +void clear_screen(gfxScreen_t screen) +{ + u8* buffer1; + u8* buffer2 = NULL; + u16 width, height; + u32 bpp; + GSPGPU_FramebufferFormats format = gfxGetScreenFormat(screen); + + if (screen == GFX_TOP) + { + buffer1 = gfxGetFramebuffer(screen, GFX_LEFT, &width, &height); + buffer2 = gfxGetFramebuffer(screen, GFX_RIGHT, &width, &height); + } else { + buffer1 = gfxGetFramebuffer(screen, GFX_LEFT, &width, &height); + } + + switch (format) + { + case GSP_RGBA8_OES: + bpp = 4; + case GSP_BGR8_OES: + bpp = 3; + case GSP_RGB565_OES: + case GSP_RGB5_A1_OES: + case GSP_RGBA4_OES: + bpp = 2; + default: + bpp = 3; + } + + memset(buffer1, 0, (width * height * bpp)); + if (buffer2) + memset(buffer2, 0, (width * height * bpp)); + + gfxFlushBuffers(); + gfxSwapBuffers(); + gspWaitForVBlank(); +} + +bool download_JSON() { + printf("\nAttempting to download JSON...\n"); + + remove("/TIKdevil/horns.json.tmp"); + FILE *oh = fopen("/TIKdevil/horns.json.tmp", "wb"); + + if (oh) { + Result res = DownloadFile(JSON_URL, oh, false); + int size = ftell(oh); + fclose(oh); + if (res == 0 && size >= 0) { + remove("/TIKdevil/horns.json"); + rename("/TIKdevil/horns.json.tmp", "/TIKdevil/horns.json"); + return true; + } + } + + printf("Failed to download JSON"); + return false; +} + +bool check_JSON(bool forceUpdate = true) { + struct stat filestats; + int ret = stat("/TIKdevil/horns.json", &filestats); + + if (ret == 0) { + if (forceUpdate == true) { + return download_JSON(); + } + } else { + printf("No horns.json\n"); + + printf("\nPress A to Download, or any other key to exit.\n"); + u32 keys = wait_key(); + + if (keys & KEY_A) { + return download_JSON(); + } + return false; + } + + return true; +} + +std::string GetSystemRegion() +{ + u8 region = -1; + CFGU_SecureInfoGetRegion(®ion); + + if(region == CFG_REGION_JPN) + return "JPN"; + + if(region == CFG_REGION_USA) + return "USA"; + + if(region == CFG_REGION_EUR) + return "EUR"; + + if(region == CFG_REGION_AUS) + return "EUR"; + + if(region == CFG_REGION_CHN) + return "CHN"; + + if(region == CFG_REGION_KOR) + return "KOR"; + + if(region == CFG_REGION_TWN) + return "TWN"; + + return "REGION FREE ONLY"; +} +std::string GetSerialType(std::string sSerial) +{ + std::string sType = "Unknown"; + if (sSerial.substr(0, 3) == "TWL") + { + sType = "DSiWare"; + } + else + { + switch (sSerial.c_str()[4]) + { + case 'N': + case 'P': + sType = "Game"; + break; + case 'T': + sType = "Demo"; + break; + case 'U': + sType = "Update"; + break; + case 'M': + sType = "DLC"; + break; + } + } + + return sType; +} + +std::string upperCase(std::string input) { + for (std::string::iterator it = input.begin(); it != input.end(); ++ it) + *it = toupper(*it); + return input; +} diff --git a/source/utils.h b/source/utils.h index 0d2e266..69ab75b 100755 --- a/source/utils.h +++ b/source/utils.h @@ -19,6 +19,24 @@ along with make_cdn_cia. If not, see . #include <3ds.h> #define NUS_URL "http://ccs.cdn.c.shop.nintendowifi.net/ccs/download/" +#define JSON_URL "http://3ds.titlekeys.gq/json_enc" + +// Title ID type definitions +#define ESHOP_GAMEAPP "0000" +#define ESHOP_DLC "008c" +#define ESHOP_UPDATE "000e" +#define ESHOP_DSIWARE "8004" + +#define JSON_TYPE_HORNS 1 +#define JSON_TYPE_ONLINE 2 + +// C++ only code +#ifdef __cplusplus +#include +std::string GetSerialType(std::string sSerial); +std::string upperCase(std::string input); +std::string GetSystemRegion(); +#endif //MISC #ifdef __cplusplus @@ -31,6 +49,8 @@ void u8_hex_print_le(u8 *array, int len); u32 align_value(u32 value, u32 alignment); void resolve_flag(unsigned char flag, unsigned char *flag_bool); void resolve_flag_u16(u16 flag, unsigned char *flag_bool); +bool download_JSON(); +bool check_JSON(bool forceUpdate); //IO Related void PrintProgress(u32 nSize, u32 nCurrent); void WriteBuffer(void *buffer, u64 size, u64 offset, FILE *output);