summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile10
-rw-r--r--files/application/wifi_earth/wifi_earth/.gitignore2
-rw-r--r--files/application/wifi_earth/wifi_earth/0000_earth.NSBMD (renamed from files/application/wifi_earth/wifi_earth/narc_0000.bin)bin146564 -> 146564 bytes
-rw-r--r--files/application/wifi_earth/wifi_earth/narc_0001.NSBMD (renamed from files/application/wifi_earth/wifi_earth/narc_0001.bin)bin668 -> 668 bytes
-rw-r--r--files/application/wifi_earth/wifi_earth/narc_0002.NSBMD (renamed from files/application/wifi_earth/wifi_earth/narc_0002.bin)bin668 -> 668 bytes
-rw-r--r--files/application/wifi_earth/wifi_earth/narc_0003.NSBMD (renamed from files/application/wifi_earth/wifi_earth/narc_0003.bin)bin668 -> 668 bytes
-rw-r--r--files/application/wifi_earth/wifi_earth/narc_0004.NSBMD (renamed from files/application/wifi_earth/wifi_earth/narc_0004.bin)bin668 -> 668 bytes
-rw-r--r--files/application/wifi_earth/wifi_earth/narc_0005.NCGRbin192 -> 0 bytes
-rw-r--r--files/application/wifi_earth/wifi_earth/narc_0005.pngbin0 -> 144 bytes
-rw-r--r--files/application/wifi_earth/wifi_earth/narc_0006.NCLRbin552 -> 0 bytes
-rw-r--r--files/application/wifi_earth/wifi_earth/narc_0006.pal259
-rw-r--r--files/arc/bm_anime/narc_0000.NSBTA (renamed from files/arc/bm_anime/narc_0000.bin)bin200 -> 200 bytes
-rw-r--r--files/arc/bm_anime/narc_0001.NSBCA (renamed from files/arc/bm_anime/narc_0001.bin)bin312 -> 312 bytes
-rw-r--r--files/arc/bm_anime/narc_0002.NSBCA (renamed from files/arc/bm_anime/narc_0002.bin)bin312 -> 312 bytes
-rw-r--r--files/arc/bm_anime/narc_0003.NSBCA (renamed from files/arc/bm_anime/narc_0003.bin)bin312 -> 312 bytes
-rw-r--r--files/arc/bm_anime/narc_0004.NSBTA (renamed from files/arc/bm_anime/narc_0004.bin)bin612 -> 612 bytes
-rw-r--r--files/arc/bm_anime/narc_0005.NSBCA (renamed from files/arc/bm_anime/narc_0005.bin)bin256 -> 256 bytes
-rw-r--r--files/arc/bm_anime/narc_0006.NSBCA (renamed from files/arc/bm_anime/narc_0006.bin)bin256 -> 256 bytes
-rw-r--r--files/arc/bm_anime/narc_0007.NSBCA (renamed from files/arc/bm_anime/narc_0007.bin)bin168 -> 168 bytes
-rw-r--r--files/arc/bm_anime/narc_0008.NSBCA (renamed from files/arc/bm_anime/narc_0008.bin)bin168 -> 168 bytes
-rw-r--r--files/arc/bm_anime/narc_0009.NSBCA (renamed from files/arc/bm_anime/narc_0009.bin)bin152 -> 152 bytes
-rw-r--r--files/arc/bm_anime/narc_0010.NSBCA (renamed from files/arc/bm_anime/narc_0010.bin)bin152 -> 152 bytes
-rw-r--r--files/arc/bm_anime/narc_0011.NSBTP (renamed from files/arc/bm_anime/narc_0011.bin)bin196 -> 196 bytes
-rw-r--r--files/arc/bm_anime/narc_0012.NSBTP (renamed from files/arc/bm_anime/narc_0012.bin)bin196 -> 196 bytes
-rw-r--r--files/arc/bm_anime/narc_0013.NSBTP (renamed from files/arc/bm_anime/narc_0013.bin)bin196 -> 196 bytes
-rw-r--r--files/arc/bm_anime/narc_0014.NSBTA (renamed from files/arc/bm_anime/narc_0014.bin)bin652 -> 652 bytes
-rw-r--r--files/arc/bm_anime/narc_0015.NSBTP (renamed from files/arc/bm_anime/narc_0015.bin)bin440 -> 440 bytes
-rw-r--r--files/arc/bm_anime/narc_0016.NSBTP (renamed from files/arc/bm_anime/narc_0016.bin)bin440 -> 440 bytes
-rw-r--r--files/arc/bm_anime/narc_0017.NSBTP (renamed from files/arc/bm_anime/narc_0017.bin)bin268 -> 268 bytes
-rw-r--r--files/arc/bm_anime/narc_0018.NSBTA (renamed from files/arc/bm_anime/narc_0018.bin)bin692 -> 692 bytes
-rw-r--r--files/arc/bm_anime/narc_0019.NSBTA (renamed from files/arc/bm_anime/narc_0019.bin)bin412 -> 412 bytes
-rw-r--r--files/arc/bm_anime/narc_0020.NSBTA (renamed from files/arc/bm_anime/narc_0020.bin)bin212 -> 212 bytes
-rw-r--r--files/arc/bm_anime/narc_0021.NSBTA (renamed from files/arc/bm_anime/narc_0021.bin)bin212 -> 212 bytes
-rw-r--r--files/arc/bm_anime/narc_0022.NSBTA (renamed from files/arc/bm_anime/narc_0022.bin)bin292 -> 292 bytes
-rw-r--r--files/arc/bm_anime/narc_0023.NSBTP (renamed from files/arc/bm_anime/narc_0023.bin)bin268 -> 268 bytes
-rw-r--r--files/arc/bm_anime/narc_0024.NSBTP (renamed from files/arc/bm_anime/narc_0024.bin)bin304 -> 304 bytes
-rw-r--r--files/arc/bm_anime/narc_0025.NSBCA (renamed from files/arc/bm_anime/narc_0025.bin)bin1548 -> 1548 bytes
-rw-r--r--files/arc/bm_anime/narc_0026.NSBCA (renamed from files/arc/bm_anime/narc_0026.bin)bin1324 -> 1324 bytes
-rw-r--r--files/arc/bm_anime/narc_0027.NSBCA (renamed from files/arc/bm_anime/narc_0027.bin)bin348 -> 348 bytes
-rw-r--r--files/arc/bm_anime/narc_0028.NSBCA (renamed from files/arc/bm_anime/narc_0028.bin)bin348 -> 348 bytes
-rw-r--r--files/arc/bm_anime/narc_0029.NSBCA (renamed from files/arc/bm_anime/narc_0029.bin)bin288 -> 288 bytes
-rw-r--r--files/arc/bm_anime/narc_0030.NSBCA (renamed from files/arc/bm_anime/narc_0030.bin)bin288 -> 288 bytes
-rw-r--r--files/arc/bm_anime/narc_0031.NSBTP (renamed from files/arc/bm_anime/narc_0031.bin)bin320 -> 320 bytes
-rw-r--r--files/arc/bm_anime/narc_0032.NSBTP (renamed from files/arc/bm_anime/narc_0032.bin)bin328 -> 328 bytes
-rw-r--r--files/arc/bm_anime/narc_0033.NSBCA (renamed from files/arc/bm_anime/narc_0033.bin)bin184 -> 184 bytes
-rw-r--r--files/arc/bm_anime/narc_0034.NSBCA (renamed from files/arc/bm_anime/narc_0034.bin)bin184 -> 184 bytes
-rw-r--r--files/arc/bm_anime/narc_0035.NSBTA (renamed from files/arc/bm_anime/narc_0035.bin)bin232 -> 232 bytes
-rw-r--r--files/arc/bm_anime/narc_0036.NSBTA (renamed from files/arc/bm_anime/narc_0036.bin)bin232 -> 232 bytes
-rw-r--r--files/arc/bm_anime/narc_0037.NSBTA (renamed from files/arc/bm_anime/narc_0037.bin)bin412 -> 412 bytes
-rw-r--r--files/arc/bm_anime/narc_0038.NSBTA (renamed from files/arc/bm_anime/narc_0038.bin)bin408 -> 408 bytes
-rw-r--r--files/arc/bm_anime/narc_0039.NSBCA (renamed from files/arc/bm_anime/narc_0039.bin)bin5456 -> 5456 bytes
-rw-r--r--files/arc/bm_anime/narc_0040.NSBCA (renamed from files/arc/bm_anime/narc_0040.bin)bin5588 -> 5588 bytes
-rw-r--r--files/arc/bm_anime/narc_0041.NSBTP (renamed from files/arc/bm_anime/narc_0041.bin)bin284 -> 284 bytes
-rw-r--r--files/arc/bm_anime/narc_0042.NSBTP (renamed from files/arc/bm_anime/narc_0042.bin)bin284 -> 284 bytes
-rw-r--r--files/arc/bm_anime/narc_0043.NSBTA (renamed from files/arc/bm_anime/narc_0043.bin)bin1964 -> 1964 bytes
-rw-r--r--files/arc/bm_anime/narc_0044.NSBTA (renamed from files/arc/bm_anime/narc_0044.bin)bin288 -> 288 bytes
-rw-r--r--files/arc/bm_anime/narc_0045.NSBTA (renamed from files/arc/bm_anime/narc_0045.bin)bin2084 -> 2084 bytes
-rw-r--r--files/arc/bm_anime/narc_0046.NSBTA (renamed from files/arc/bm_anime/narc_0046.bin)bin292 -> 292 bytes
-rw-r--r--files/arc/bm_anime/narc_0047.NSBTA (renamed from files/arc/bm_anime/narc_0047.bin)bin292 -> 292 bytes
-rw-r--r--files/arc/bm_anime/narc_0048.NSBTA (renamed from files/arc/bm_anime/narc_0048.bin)bin292 -> 292 bytes
-rw-r--r--files/arc/bm_anime/narc_0049.NSBCA (renamed from files/arc/bm_anime/narc_0049.bin)bin172 -> 172 bytes
-rw-r--r--files/arc/bm_anime/narc_0050.NSBTP (renamed from files/arc/bm_anime/narc_0050.bin)bin196 -> 196 bytes
-rw-r--r--files/arc/bm_anime/narc_0051.NSBTP (renamed from files/arc/bm_anime/narc_0051.bin)bin268 -> 268 bytes
-rw-r--r--files/arc/bm_anime/narc_0052.NSBTP (renamed from files/arc/bm_anime/narc_0052.bin)bin268 -> 268 bytes
-rw-r--r--files/arc/bm_anime/narc_0053.NSBTA (renamed from files/arc/bm_anime/narc_0053.bin)bin288 -> 288 bytes
-rw-r--r--files/arc/bm_anime/narc_0054.NSBCA (renamed from files/arc/bm_anime/narc_0054.bin)bin528 -> 528 bytes
-rw-r--r--files/arc/bm_anime/narc_0055.NSBTA (renamed from files/arc/bm_anime/narc_0055.bin)bin348 -> 348 bytes
-rw-r--r--files/arc/bm_anime/narc_0056.NSBTA (renamed from files/arc/bm_anime/narc_0056.bin)bin348 -> 348 bytes
-rw-r--r--files/arc/bm_anime/narc_0057.NSBTA (renamed from files/arc/bm_anime/narc_0057.bin)bin348 -> 348 bytes
-rw-r--r--files/arc/bm_anime/narc_0058.NSBTA (renamed from files/arc/bm_anime/narc_0058.bin)bin284 -> 284 bytes
-rw-r--r--files/arc/bm_anime/narc_0059.NSBTA (renamed from files/arc/bm_anime/narc_0059.bin)bin912 -> 912 bytes
-rw-r--r--files/arc/bm_anime/narc_0060.NSBTA (renamed from files/arc/bm_anime/narc_0060.bin)bin348 -> 348 bytes
-rw-r--r--files/arc/bm_anime/narc_0061.NSBTA (renamed from files/arc/bm_anime/narc_0061.bin)bin412 -> 412 bytes
-rw-r--r--files/arc/bm_anime/narc_0062.NSBTA (renamed from files/arc/bm_anime/narc_0062.bin)bin412 -> 412 bytes
-rw-r--r--files/arc/bm_anime/narc_0063.NSBTA (renamed from files/arc/bm_anime/narc_0063.bin)bin732 -> 732 bytes
-rw-r--r--files/arc/ship_demo/narc_0000.NSBCA (renamed from files/arc/ship_demo/narc_0000.bin)bin3144 -> 3144 bytes
-rw-r--r--files/arc/ship_demo/narc_0001.NSBMA (renamed from files/arc/ship_demo/narc_0001.bin)bin224 -> 224 bytes
-rw-r--r--files/arc/ship_demo/narc_0002.NSBMD (renamed from files/arc/ship_demo/narc_0002.bin)bin19708 -> 19708 bytes
-rw-r--r--files/arc/ship_demo/narc_0003.NSBTA (renamed from files/arc/ship_demo/narc_0003.bin)bin860 -> 860 bytes
-rw-r--r--files/arc/ship_demo/narc_0004.NSBTP (renamed from files/arc/ship_demo/narc_0004.bin)bin400 -> 400 bytes
-rw-r--r--files/arc/ship_demo/narc_0005.NSBCA (renamed from files/arc/ship_demo/narc_0005.bin)bin3144 -> 3144 bytes
-rw-r--r--files/arc/ship_demo/narc_0006.NSBMA (renamed from files/arc/ship_demo/narc_0006.bin)bin224 -> 224 bytes
-rw-r--r--files/arc/ship_demo/narc_0007.NSBMD (renamed from files/arc/ship_demo/narc_0007.bin)bin18368 -> 18368 bytes
-rw-r--r--files/arc/ship_demo/narc_0008.NSBTA (renamed from files/arc/ship_demo/narc_0008.bin)bin860 -> 860 bytes
-rw-r--r--files/arc/ship_demo/narc_0009.NSBTP (renamed from files/arc/ship_demo/narc_0009.bin)bin400 -> 400 bytes
-rw-r--r--files/arc/ship_demo/narc_0010.NSBCA (renamed from files/arc/ship_demo/narc_0010.bin)bin3136 -> 3136 bytes
-rw-r--r--files/arc/ship_demo/narc_0011.NSBMA (renamed from files/arc/ship_demo/narc_0011.bin)bin224 -> 224 bytes
-rw-r--r--files/arc/ship_demo/narc_0012.NSBMD (renamed from files/arc/ship_demo/narc_0012.bin)bin18364 -> 18364 bytes
-rw-r--r--files/arc/ship_demo/narc_0013.NSBTA (renamed from files/arc/ship_demo/narc_0013.bin)bin860 -> 860 bytes
-rw-r--r--files/arc/ship_demo/narc_0014.NSBTP (renamed from files/arc/ship_demo/narc_0014.bin)bin400 -> 400 bytes
-rw-r--r--files/arc/ship_demo/narc_0015.NSBCA (renamed from files/arc/ship_demo/narc_0015.bin)bin3144 -> 3144 bytes
-rw-r--r--files/arc/ship_demo/narc_0016.NSBMA (renamed from files/arc/ship_demo/narc_0016.bin)bin224 -> 224 bytes
-rw-r--r--files/arc/ship_demo/narc_0017.NSBMD (renamed from files/arc/ship_demo/narc_0017.bin)bin19908 -> 19908 bytes
-rw-r--r--files/arc/ship_demo/narc_0018.NSBTA (renamed from files/arc/ship_demo/narc_0018.bin)bin860 -> 860 bytes
-rw-r--r--files/arc/ship_demo/narc_0019.NSBTP (renamed from files/arc/ship_demo/narc_0019.bin)bin400 -> 400 bytes
-rw-r--r--files/data/demo_climax/narc_0000.NSBMD (renamed from files/data/demo_climax/narc_0000.bin)bin71896 -> 71896 bytes
-rw-r--r--files/data/demo_climax/narc_0001.NSBTA (renamed from files/data/demo_climax/narc_0001.bin)bin2332 -> 2332 bytes
-rw-r--r--files/data/demo_climax/narc_0002.NSBCA (renamed from files/data/demo_climax/narc_0002.bin)bin11872 -> 11872 bytes
-rw-r--r--files/data/demo_climax/narc_0003.NSBMA (renamed from files/data/demo_climax/narc_0003.bin)bin1576 -> 1576 bytes
-rw-r--r--files/data/demo_climax/narc_0004.NSBMD (renamed from files/data/demo_climax/narc_0004.bin)bin1444 -> 1444 bytes
-rw-r--r--files/data/demo_climax/narc_0005.NSBMD (renamed from files/data/demo_climax/narc_0005.bin)bin1444 -> 1444 bytes
-rw-r--r--files/data/demo_climax/narc_0006.NSBMD (renamed from files/data/demo_climax/narc_0006.bin)bin1444 -> 1444 bytes
-rw-r--r--files/data/demo_climax/narc_0007.NSBMD (renamed from files/data/demo_climax/narc_0007.bin)bin18552 -> 18552 bytes
-rw-r--r--files/data/demo_climax/narc_0008.NSBCA (renamed from files/data/demo_climax/narc_0008.bin)bin178676 -> 178676 bytes
-rw-r--r--files/data/demo_climax/narc_0009.NSBMA (renamed from files/data/demo_climax/narc_0009.bin)bin2016 -> 2016 bytes
-rw-r--r--files/data/demo_climax/narc_0010.NSBTA (renamed from files/data/demo_climax/narc_0010.bin)bin11132 -> 11132 bytes
-rw-r--r--files/data/demo_climax/narc_0011.NSBVA (renamed from files/data/demo_climax/narc_0011.bin)bin3236 -> 3236 bytes
-rw-r--r--files/data/demo_climax/narc_0012.NSBMD (renamed from files/data/demo_climax/narc_0012.bin)bin70884 -> 70884 bytes
-rw-r--r--files/data/demo_climax/narc_0013.NSBCA (renamed from files/data/demo_climax/narc_0013.bin)bin31648 -> 31648 bytes
-rw-r--r--files/data/demo_climax/narc_0014.NSBMA (renamed from files/data/demo_climax/narc_0014.bin)bin9172 -> 9172 bytes
-rw-r--r--files/data/demo_climax/narc_0015.NSBMD (renamed from files/data/demo_climax/narc_0015.bin)bin48964 -> 48964 bytes
-rw-r--r--files/data/demo_climax/narc_0016.NSBCA (renamed from files/data/demo_climax/narc_0016.bin)bin2124 -> 2124 bytes
-rw-r--r--files/data/demo_climax/narc_0017.NSBMA (renamed from files/data/demo_climax/narc_0017.bin)bin2484 -> 2484 bytes
-rw-r--r--files/data/demo_climax/narc_0018.NSBTA (renamed from files/data/demo_climax/narc_0018.bin)bin1172 -> 1172 bytes
-rw-r--r--files/data/demo_climax/narc_0019.NSBVA (renamed from files/data/demo_climax/narc_0019.bin)bin340 -> 340 bytes
-rw-r--r--files/data/mmodel/fldeff/narc_0000.NSBTX (renamed from files/data/mmodel/fldeff/narc_0000.bin)bin2312 -> 2312 bytes
-rw-r--r--files/data/mmodel/fldeff/narc_0001.NSBTX (renamed from files/data/mmodel/fldeff/narc_0001.bin)bin636 -> 636 bytes
-rw-r--r--files/data/mmodel/fldeff/narc_0002.NSBTX (renamed from files/data/mmodel/fldeff/narc_0002.bin)bin792 -> 792 bytes
-rw-r--r--files/data/mmodel/fldeff/narc_0003.NSBTX (renamed from files/data/mmodel/fldeff/narc_0003.bin)bin792 -> 792 bytes
-rw-r--r--files/data/mmodel/fldeff/narc_0004.NSBTX (renamed from files/data/mmodel/fldeff/narc_0004.bin)bin308 -> 308 bytes
-rw-r--r--files/data/mmodel/fldeff/narc_0005.NSBTX (renamed from files/data/mmodel/fldeff/narc_0005.bin)bin1052 -> 1052 bytes
-rw-r--r--files/data/mmodel/fldeff/narc_0006.NSBTX (renamed from files/data/mmodel/fldeff/narc_0006.bin)bin196 -> 196 bytes
-rw-r--r--files/data/mmodel/fldeff/narc_0007.NSBTX (renamed from files/data/mmodel/fldeff/narc_0007.bin)bin592 -> 592 bytes
-rw-r--r--files/data/mmodel/fldeff/narc_0008.NSBTX (renamed from files/data/mmodel/fldeff/narc_0008.bin)bin504 -> 504 bytes
-rw-r--r--files/data/mmodel/fldeff/narc_0009.NSBTX (renamed from files/data/mmodel/fldeff/narc_0009.bin)bin520 -> 520 bytes
-rw-r--r--files/data/mmodel/fldeff/narc_0010.NSBTX (renamed from files/data/mmodel/fldeff/narc_0010.bin)bin1360 -> 1360 bytes
-rw-r--r--files/data/mmodel/fldeff/narc_0011.NSBTX (renamed from files/data/mmodel/fldeff/narc_0011.bin)bin1360 -> 1360 bytes
-rw-r--r--files/data/mmodel/mmodel/narc_0000.NSBTX (renamed from files/data/mmodel/mmodel/narc_0000.bin)bin6760 -> 6760 bytes
-rw-r--r--files/demo/title/op_demo/narc_0064.NSBMD (renamed from files/demo/title/op_demo/narc_0064.bin)bin38736 -> 38736 bytes
-rw-r--r--files/demo/title/op_demo/narc_0065.NSBMD (renamed from files/demo/title/op_demo/narc_0065.bin)bin43548 -> 43548 bytes
-rw-r--r--files/demo/title/op_demo/narc_0066.NSBMD (renamed from files/demo/title/op_demo/narc_0066.bin)bin42960 -> 42960 bytes
-rw-r--r--files/demo/title/op_demo/narc_0067.NSBMD (renamed from files/demo/title/op_demo/narc_0067.bin)bin54820 -> 54820 bytes
-rw-r--r--files/demo/title/op_demo/narc_0068.NSBMD (renamed from files/demo/title/op_demo/narc_0068.bin)bin46160 -> 46160 bytes
-rw-r--r--files/demo/title/op_demo/narc_0069.NSBMD (renamed from files/demo/title/op_demo/narc_0069.bin)bin14116 -> 14116 bytes
-rw-r--r--files/demo/title/op_demo/narc_0070.NSBTX (renamed from files/demo/title/op_demo/narc_0070.bin)bin47100 -> 47100 bytes
-rw-r--r--files/demo/title/titledemo/.gitignore1
-rw-r--r--files/demo/title/titledemo/.knarcignore1
-rw-r--r--files/demo/title/titledemo/narc_0000.NSCRbin2084 -> 0 bytes
-rw-r--r--files/demo/title/titledemo/narc_0000_map.json39
-rw-r--r--files/demo/title/titledemo/narc_0000_tileset.json14
-rw-r--r--files/demo/title/titledemo/narc_0005.NSBMD (renamed from files/demo/title/titledemo/narc_0005.bin)bin65584 -> 65584 bytes
-rw-r--r--files/demo/title/titledemo/narc_0006.NSBMD (renamed from files/demo/title/titledemo/narc_0006.bin)bin51572 -> 51572 bytes
-rw-r--r--files/demo/title/titledemo/narc_0018.NSBTA (renamed from files/demo/title/titledemo/narc_0018.bin)bin472 -> 472 bytes
-rw-r--r--files/demo/title/titledemo/narc_0019.NSBTA (renamed from files/demo/title/titledemo/narc_0019.bin)bin472 -> 472 bytes
-rw-r--r--files/poketool/icongra/poke_icon/.gitignore1
-rw-r--r--files/poketool/icongra/poke_icon/.knarcignore1
-rw-r--r--files/poketool/icongra/poke_icon/narc_0002.NCERbin142 -> 0 bytes
-rw-r--r--files/poketool/icongra/poke_icon/narc_0002.json67
-rw-r--r--filesystem.mk6
-rw-r--r--graphics_rules.mk18
-rw-r--r--tools/nitrogfx/Makefile2
-rw-r--r--tools/nitrogfx/cJSON.c3110
-rw-r--r--tools/nitrogfx/cJSON.h293
-rw-r--r--tools/nitrogfx/gfx.c204
-rw-r--r--tools/nitrogfx/gfx.h3
-rw-r--r--tools/nitrogfx/json.c212
-rw-r--r--tools/nitrogfx/json.h13
-rw-r--r--tools/nitrogfx/main.c52
-rw-r--r--tools/nitrogfx/options.h53
159 files changed, 4355 insertions, 6 deletions
diff --git a/Makefile b/Makefile
index 4467d8ac..19d85350 100644
--- a/Makefile
+++ b/Makefile
@@ -162,7 +162,7 @@ clean: mostlyclean clean-fs clean-tools
clean-fs:
$(RM) $(filter %.narc %.arc,$(HOSTFS_FILES))
- $(RM) $(NCGR_CLEAN_LIST) $(NCLR_CLEAN_LIST)
+ $(RM) $(NCGR_CLEAN_LIST) $(NCLR_CLEAN_LIST) $(NCER_CLEAN_LIST) $(NSCR_CLEAN_LIST)
find . \( -iname '*.1bpp' -o -iname '*.4bpp' -o -iname '*.8bpp' -o -iname '*.gbapal' -o -iname '*.lz' \) -exec $(RM) {} +
$(RM) files/msgdata/msg/narc_*.bin
@@ -259,6 +259,7 @@ $(SCANNED_NCGR_FILES): GFX_FLAGS = -scanned
$(IR_NCLR_FILES): GFX_FLAGS = -ir
$(4BPP_NCLR_FILES): GFX_FLAGS = -bitdepth 4
+$(8BPP_NSCR_FILES): GFX_FLAGS = -bitdepth 8
$(8BPP_COMP10_NOPAD_NCLR_PNG_FILES): GFX_FLAGS = -bitdepth 8 -nopad -comp 10
$(8BPP_COMP10_NOPAD_NCLR_PAL_FILES): GFX_FLAGS = -bitdepth 8 -nopad -comp 10
@@ -271,8 +272,15 @@ $(8BPP_COMP10_NOPAD_NCLR_PAL_FILES): GFX_FLAGS = -bitdepth 8 -nopad -comp 10
%.NCLR: %.pal
$(GFX) $< $@ $(GFX_FLAGS)
+%.NCER: %.json
+ $(GFX) $< $@
+
+%.NSCR: %_map.json
+ $(GFX) $< $@ $(GFX_FLAGS)
+
%.png: ;
%.pal: ;
+%.json: ;
######################## Misc #######################
diff --git a/files/application/wifi_earth/wifi_earth/.gitignore b/files/application/wifi_earth/wifi_earth/.gitignore
new file mode 100644
index 00000000..2bac294d
--- /dev/null
+++ b/files/application/wifi_earth/wifi_earth/.gitignore
@@ -0,0 +1,2 @@
+narc_0005.NCGR
+narc_0006.NCLR
diff --git a/files/application/wifi_earth/wifi_earth/narc_0000.bin b/files/application/wifi_earth/wifi_earth/0000_earth.NSBMD
index 14df1e08..14df1e08 100644
--- a/files/application/wifi_earth/wifi_earth/narc_0000.bin
+++ b/files/application/wifi_earth/wifi_earth/0000_earth.NSBMD
Binary files differ
diff --git a/files/application/wifi_earth/wifi_earth/narc_0001.bin b/files/application/wifi_earth/wifi_earth/narc_0001.NSBMD
index fa6bc078..fa6bc078 100644
--- a/files/application/wifi_earth/wifi_earth/narc_0001.bin
+++ b/files/application/wifi_earth/wifi_earth/narc_0001.NSBMD
Binary files differ
diff --git a/files/application/wifi_earth/wifi_earth/narc_0002.bin b/files/application/wifi_earth/wifi_earth/narc_0002.NSBMD
index e121614f..e121614f 100644
--- a/files/application/wifi_earth/wifi_earth/narc_0002.bin
+++ b/files/application/wifi_earth/wifi_earth/narc_0002.NSBMD
Binary files differ
diff --git a/files/application/wifi_earth/wifi_earth/narc_0003.bin b/files/application/wifi_earth/wifi_earth/narc_0003.NSBMD
index e555f6b5..e555f6b5 100644
--- a/files/application/wifi_earth/wifi_earth/narc_0003.bin
+++ b/files/application/wifi_earth/wifi_earth/narc_0003.NSBMD
Binary files differ
diff --git a/files/application/wifi_earth/wifi_earth/narc_0004.bin b/files/application/wifi_earth/wifi_earth/narc_0004.NSBMD
index 1c0c0149..1c0c0149 100644
--- a/files/application/wifi_earth/wifi_earth/narc_0004.bin
+++ b/files/application/wifi_earth/wifi_earth/narc_0004.NSBMD
Binary files differ
diff --git a/files/application/wifi_earth/wifi_earth/narc_0005.NCGR b/files/application/wifi_earth/wifi_earth/narc_0005.NCGR
deleted file mode 100644
index 45fd8385..00000000
--- a/files/application/wifi_earth/wifi_earth/narc_0005.NCGR
+++ /dev/null
Binary files differ
diff --git a/files/application/wifi_earth/wifi_earth/narc_0005.png b/files/application/wifi_earth/wifi_earth/narc_0005.png
new file mode 100644
index 00000000..07667009
--- /dev/null
+++ b/files/application/wifi_earth/wifi_earth/narc_0005.png
Binary files differ
diff --git a/files/application/wifi_earth/wifi_earth/narc_0006.NCLR b/files/application/wifi_earth/wifi_earth/narc_0006.NCLR
deleted file mode 100644
index 50e2e255..00000000
--- a/files/application/wifi_earth/wifi_earth/narc_0006.NCLR
+++ /dev/null
Binary files differ
diff --git a/files/application/wifi_earth/wifi_earth/narc_0006.pal b/files/application/wifi_earth/wifi_earth/narc_0006.pal
new file mode 100644
index 00000000..c898c0ab
--- /dev/null
+++ b/files/application/wifi_earth/wifi_earth/narc_0006.pal
@@ -0,0 +1,259 @@
+JASC-PAL
+0100
+256
+0 0 0
+57 164 131
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+8 32 24
+57 164 131
+0 0 0
+41 131 106
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+8 32 24
+238 246 106
+0 0 0
+32 98 82
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+8 32 24
+255 98 255
+0 0 0
+16 65 49
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+8 32 24
+16 65 139
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+8 32 24
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
+0 0 0
diff --git a/files/arc/bm_anime/narc_0000.bin b/files/arc/bm_anime/narc_0000.NSBTA
index 239dc5c7..239dc5c7 100644
--- a/files/arc/bm_anime/narc_0000.bin
+++ b/files/arc/bm_anime/narc_0000.NSBTA
Binary files differ
diff --git a/files/arc/bm_anime/narc_0001.bin b/files/arc/bm_anime/narc_0001.NSBCA
index 1ddce3aa..1ddce3aa 100644
--- a/files/arc/bm_anime/narc_0001.bin
+++ b/files/arc/bm_anime/narc_0001.NSBCA
Binary files differ
diff --git a/files/arc/bm_anime/narc_0002.bin b/files/arc/bm_anime/narc_0002.NSBCA
index 56a6b316..56a6b316 100644
--- a/files/arc/bm_anime/narc_0002.bin
+++ b/files/arc/bm_anime/narc_0002.NSBCA
Binary files differ
diff --git a/files/arc/bm_anime/narc_0003.bin b/files/arc/bm_anime/narc_0003.NSBCA
index 9f2685fd..9f2685fd 100644
--- a/files/arc/bm_anime/narc_0003.bin
+++ b/files/arc/bm_anime/narc_0003.NSBCA
Binary files differ
diff --git a/files/arc/bm_anime/narc_0004.bin b/files/arc/bm_anime/narc_0004.NSBTA
index 28d12bb0..28d12bb0 100644
--- a/files/arc/bm_anime/narc_0004.bin
+++ b/files/arc/bm_anime/narc_0004.NSBTA
Binary files differ
diff --git a/files/arc/bm_anime/narc_0005.bin b/files/arc/bm_anime/narc_0005.NSBCA
index 9c1b2729..9c1b2729 100644
--- a/files/arc/bm_anime/narc_0005.bin
+++ b/files/arc/bm_anime/narc_0005.NSBCA
Binary files differ
diff --git a/files/arc/bm_anime/narc_0006.bin b/files/arc/bm_anime/narc_0006.NSBCA
index 06964c87..06964c87 100644
--- a/files/arc/bm_anime/narc_0006.bin
+++ b/files/arc/bm_anime/narc_0006.NSBCA
Binary files differ
diff --git a/files/arc/bm_anime/narc_0007.bin b/files/arc/bm_anime/narc_0007.NSBCA
index 92153c3c..92153c3c 100644
--- a/files/arc/bm_anime/narc_0007.bin
+++ b/files/arc/bm_anime/narc_0007.NSBCA
Binary files differ
diff --git a/files/arc/bm_anime/narc_0008.bin b/files/arc/bm_anime/narc_0008.NSBCA
index 97e7532c..97e7532c 100644
--- a/files/arc/bm_anime/narc_0008.bin
+++ b/files/arc/bm_anime/narc_0008.NSBCA
Binary files differ
diff --git a/files/arc/bm_anime/narc_0009.bin b/files/arc/bm_anime/narc_0009.NSBCA
index 9879230f..9879230f 100644
--- a/files/arc/bm_anime/narc_0009.bin
+++ b/files/arc/bm_anime/narc_0009.NSBCA
Binary files differ
diff --git a/files/arc/bm_anime/narc_0010.bin b/files/arc/bm_anime/narc_0010.NSBCA
index 2aab22a2..2aab22a2 100644
--- a/files/arc/bm_anime/narc_0010.bin
+++ b/files/arc/bm_anime/narc_0010.NSBCA
Binary files differ
diff --git a/files/arc/bm_anime/narc_0011.bin b/files/arc/bm_anime/narc_0011.NSBTP
index d1b76b15..d1b76b15 100644
--- a/files/arc/bm_anime/narc_0011.bin
+++ b/files/arc/bm_anime/narc_0011.NSBTP
Binary files differ
diff --git a/files/arc/bm_anime/narc_0012.bin b/files/arc/bm_anime/narc_0012.NSBTP
index 8ce1b536..8ce1b536 100644
--- a/files/arc/bm_anime/narc_0012.bin
+++ b/files/arc/bm_anime/narc_0012.NSBTP
Binary files differ
diff --git a/files/arc/bm_anime/narc_0013.bin b/files/arc/bm_anime/narc_0013.NSBTP
index e33c59dc..e33c59dc 100644
--- a/files/arc/bm_anime/narc_0013.bin
+++ b/files/arc/bm_anime/narc_0013.NSBTP
Binary files differ
diff --git a/files/arc/bm_anime/narc_0014.bin b/files/arc/bm_anime/narc_0014.NSBTA
index 4464402d..4464402d 100644
--- a/files/arc/bm_anime/narc_0014.bin
+++ b/files/arc/bm_anime/narc_0014.NSBTA
Binary files differ
diff --git a/files/arc/bm_anime/narc_0015.bin b/files/arc/bm_anime/narc_0015.NSBTP
index 54a4ceba..54a4ceba 100644
--- a/files/arc/bm_anime/narc_0015.bin
+++ b/files/arc/bm_anime/narc_0015.NSBTP
Binary files differ
diff --git a/files/arc/bm_anime/narc_0016.bin b/files/arc/bm_anime/narc_0016.NSBTP
index d99e5a29..d99e5a29 100644
--- a/files/arc/bm_anime/narc_0016.bin
+++ b/files/arc/bm_anime/narc_0016.NSBTP
Binary files differ
diff --git a/files/arc/bm_anime/narc_0017.bin b/files/arc/bm_anime/narc_0017.NSBTP
index 012f6fab..012f6fab 100644
--- a/files/arc/bm_anime/narc_0017.bin
+++ b/files/arc/bm_anime/narc_0017.NSBTP
Binary files differ
diff --git a/files/arc/bm_anime/narc_0018.bin b/files/arc/bm_anime/narc_0018.NSBTA
index ae194f1f..ae194f1f 100644
--- a/files/arc/bm_anime/narc_0018.bin
+++ b/files/arc/bm_anime/narc_0018.NSBTA
Binary files differ
diff --git a/files/arc/bm_anime/narc_0019.bin b/files/arc/bm_anime/narc_0019.NSBTA
index 4d9cb467..4d9cb467 100644
--- a/files/arc/bm_anime/narc_0019.bin
+++ b/files/arc/bm_anime/narc_0019.NSBTA
Binary files differ
diff --git a/files/arc/bm_anime/narc_0020.bin b/files/arc/bm_anime/narc_0020.NSBTA
index 8776a442..8776a442 100644
--- a/files/arc/bm_anime/narc_0020.bin
+++ b/files/arc/bm_anime/narc_0020.NSBTA
Binary files differ
diff --git a/files/arc/bm_anime/narc_0021.bin b/files/arc/bm_anime/narc_0021.NSBTA
index 6e6860b1..6e6860b1 100644
--- a/files/arc/bm_anime/narc_0021.bin
+++ b/files/arc/bm_anime/narc_0021.NSBTA
Binary files differ
diff --git a/files/arc/bm_anime/narc_0022.bin b/files/arc/bm_anime/narc_0022.NSBTA
index 1a9118ae..1a9118ae 100644
--- a/files/arc/bm_anime/narc_0022.bin
+++ b/files/arc/bm_anime/narc_0022.NSBTA
Binary files differ
diff --git a/files/arc/bm_anime/narc_0023.bin b/files/arc/bm_anime/narc_0023.NSBTP
index 76666fb2..76666fb2 100644
--- a/files/arc/bm_anime/narc_0023.bin
+++ b/files/arc/bm_anime/narc_0023.NSBTP
Binary files differ
diff --git a/files/arc/bm_anime/narc_0024.bin b/files/arc/bm_anime/narc_0024.NSBTP
index b7f0c14c..b7f0c14c 100644
--- a/files/arc/bm_anime/narc_0024.bin
+++ b/files/arc/bm_anime/narc_0024.NSBTP
Binary files differ
diff --git a/files/arc/bm_anime/narc_0025.bin b/files/arc/bm_anime/narc_0025.NSBCA
index 8ae20701..8ae20701 100644
--- a/files/arc/bm_anime/narc_0025.bin
+++ b/files/arc/bm_anime/narc_0025.NSBCA
Binary files differ
diff --git a/files/arc/bm_anime/narc_0026.bin b/files/arc/bm_anime/narc_0026.NSBCA
index e3b6ff54..e3b6ff54 100644
--- a/files/arc/bm_anime/narc_0026.bin
+++ b/files/arc/bm_anime/narc_0026.NSBCA
Binary files differ
diff --git a/files/arc/bm_anime/narc_0027.bin b/files/arc/bm_anime/narc_0027.NSBCA
index 513c28e7..513c28e7 100644
--- a/files/arc/bm_anime/narc_0027.bin
+++ b/files/arc/bm_anime/narc_0027.NSBCA
Binary files differ
diff --git a/files/arc/bm_anime/narc_0028.bin b/files/arc/bm_anime/narc_0028.NSBCA
index f5dcb4a5..f5dcb4a5 100644
--- a/files/arc/bm_anime/narc_0028.bin
+++ b/files/arc/bm_anime/narc_0028.NSBCA
Binary files differ
diff --git a/files/arc/bm_anime/narc_0029.bin b/files/arc/bm_anime/narc_0029.NSBCA
index f2036409..f2036409 100644
--- a/files/arc/bm_anime/narc_0029.bin
+++ b/files/arc/bm_anime/narc_0029.NSBCA
Binary files differ
diff --git a/files/arc/bm_anime/narc_0030.bin b/files/arc/bm_anime/narc_0030.NSBCA
index a9a4b647..a9a4b647 100644
--- a/files/arc/bm_anime/narc_0030.bin
+++ b/files/arc/bm_anime/narc_0030.NSBCA
Binary files differ
diff --git a/files/arc/bm_anime/narc_0031.bin b/files/arc/bm_anime/narc_0031.NSBTP
index 9ed8a506..9ed8a506 100644
--- a/files/arc/bm_anime/narc_0031.bin
+++ b/files/arc/bm_anime/narc_0031.NSBTP
Binary files differ
diff --git a/files/arc/bm_anime/narc_0032.bin b/files/arc/bm_anime/narc_0032.NSBTP
index 0b03cb5e..0b03cb5e 100644
--- a/files/arc/bm_anime/narc_0032.bin
+++ b/files/arc/bm_anime/narc_0032.NSBTP
Binary files differ
diff --git a/files/arc/bm_anime/narc_0033.bin b/files/arc/bm_anime/narc_0033.NSBCA
index 4239f546..4239f546 100644
--- a/files/arc/bm_anime/narc_0033.bin
+++ b/files/arc/bm_anime/narc_0033.NSBCA
Binary files differ
diff --git a/files/arc/bm_anime/narc_0034.bin b/files/arc/bm_anime/narc_0034.NSBCA
index f281c392..f281c392 100644
--- a/files/arc/bm_anime/narc_0034.bin
+++ b/files/arc/bm_anime/narc_0034.NSBCA
Binary files differ
diff --git a/files/arc/bm_anime/narc_0035.bin b/files/arc/bm_anime/narc_0035.NSBTA
index f9322ea1..f9322ea1 100644
--- a/files/arc/bm_anime/narc_0035.bin
+++ b/files/arc/bm_anime/narc_0035.NSBTA
Binary files differ
diff --git a/files/arc/bm_anime/narc_0036.bin b/files/arc/bm_anime/narc_0036.NSBTA
index 4c197f9c..4c197f9c 100644
--- a/files/arc/bm_anime/narc_0036.bin
+++ b/files/arc/bm_anime/narc_0036.NSBTA
Binary files differ
diff --git a/files/arc/bm_anime/narc_0037.bin b/files/arc/bm_anime/narc_0037.NSBTA
index d5e4c75f..d5e4c75f 100644
--- a/files/arc/bm_anime/narc_0037.bin
+++ b/files/arc/bm_anime/narc_0037.NSBTA
Binary files differ
diff --git a/files/arc/bm_anime/narc_0038.bin b/files/arc/bm_anime/narc_0038.NSBTA
index b2cdda44..b2cdda44 100644
--- a/files/arc/bm_anime/narc_0038.bin
+++ b/files/arc/bm_anime/narc_0038.NSBTA
Binary files differ
diff --git a/files/arc/bm_anime/narc_0039.bin b/files/arc/bm_anime/narc_0039.NSBCA
index af3b7b71..af3b7b71 100644
--- a/files/arc/bm_anime/narc_0039.bin
+++ b/files/arc/bm_anime/narc_0039.NSBCA
Binary files differ
diff --git a/files/arc/bm_anime/narc_0040.bin b/files/arc/bm_anime/narc_0040.NSBCA
index 806b2234..806b2234 100644
--- a/files/arc/bm_anime/narc_0040.bin
+++ b/files/arc/bm_anime/narc_0040.NSBCA
Binary files differ
diff --git a/files/arc/bm_anime/narc_0041.bin b/files/arc/bm_anime/narc_0041.NSBTP
index 1ee424e0..1ee424e0 100644
--- a/files/arc/bm_anime/narc_0041.bin
+++ b/files/arc/bm_anime/narc_0041.NSBTP
Binary files differ
diff --git a/files/arc/bm_anime/narc_0042.bin b/files/arc/bm_anime/narc_0042.NSBTP
index 3a0b0e7c..3a0b0e7c 100644
--- a/files/arc/bm_anime/narc_0042.bin
+++ b/files/arc/bm_anime/narc_0042.NSBTP
Binary files differ
diff --git a/files/arc/bm_anime/narc_0043.bin b/files/arc/bm_anime/narc_0043.NSBTA
index 849a1354..849a1354 100644
--- a/files/arc/bm_anime/narc_0043.bin
+++ b/files/arc/bm_anime/narc_0043.NSBTA
Binary files differ
diff --git a/files/arc/bm_anime/narc_0044.bin b/files/arc/bm_anime/narc_0044.NSBTA
index 5ac9cf20..5ac9cf20 100644
--- a/files/arc/bm_anime/narc_0044.bin
+++ b/files/arc/bm_anime/narc_0044.NSBTA
Binary files differ
diff --git a/files/arc/bm_anime/narc_0045.bin b/files/arc/bm_anime/narc_0045.NSBTA
index 4a922c68..4a922c68 100644
--- a/files/arc/bm_anime/narc_0045.bin
+++ b/files/arc/bm_anime/narc_0045.NSBTA
Binary files differ
diff --git a/files/arc/bm_anime/narc_0046.bin b/files/arc/bm_anime/narc_0046.NSBTA
index ab96d25e..ab96d25e 100644
--- a/files/arc/bm_anime/narc_0046.bin
+++ b/files/arc/bm_anime/narc_0046.NSBTA
Binary files differ
diff --git a/files/arc/bm_anime/narc_0047.bin b/files/arc/bm_anime/narc_0047.NSBTA
index e279f68f..e279f68f 100644
--- a/files/arc/bm_anime/narc_0047.bin
+++ b/files/arc/bm_anime/narc_0047.NSBTA
Binary files differ
diff --git a/files/arc/bm_anime/narc_0048.bin b/files/arc/bm_anime/narc_0048.NSBTA
index 02d90a8b..02d90a8b 100644
--- a/files/arc/bm_anime/narc_0048.bin
+++ b/files/arc/bm_anime/narc_0048.NSBTA
Binary files differ
diff --git a/files/arc/bm_anime/narc_0049.bin b/files/arc/bm_anime/narc_0049.NSBCA
index 3e2a1b15..3e2a1b15 100644
--- a/files/arc/bm_anime/narc_0049.bin
+++ b/files/arc/bm_anime/narc_0049.NSBCA
Binary files differ
diff --git a/files/arc/bm_anime/narc_0050.bin b/files/arc/bm_anime/narc_0050.NSBTP
index 67044c11..67044c11 100644
--- a/files/arc/bm_anime/narc_0050.bin
+++ b/files/arc/bm_anime/narc_0050.NSBTP
Binary files differ
diff --git a/files/arc/bm_anime/narc_0051.bin b/files/arc/bm_anime/narc_0051.NSBTP
index 99d52dd3..99d52dd3 100644
--- a/files/arc/bm_anime/narc_0051.bin
+++ b/files/arc/bm_anime/narc_0051.NSBTP
Binary files differ
diff --git a/files/arc/bm_anime/narc_0052.bin b/files/arc/bm_anime/narc_0052.NSBTP
index c84aebbd..c84aebbd 100644
--- a/files/arc/bm_anime/narc_0052.bin
+++ b/files/arc/bm_anime/narc_0052.NSBTP
Binary files differ
diff --git a/files/arc/bm_anime/narc_0053.bin b/files/arc/bm_anime/narc_0053.NSBTA
index f71fc8dc..f71fc8dc 100644
--- a/files/arc/bm_anime/narc_0053.bin
+++ b/files/arc/bm_anime/narc_0053.NSBTA
Binary files differ
diff --git a/files/arc/bm_anime/narc_0054.bin b/files/arc/bm_anime/narc_0054.NSBCA
index e150c3c9..e150c3c9 100644
--- a/files/arc/bm_anime/narc_0054.bin
+++ b/files/arc/bm_anime/narc_0054.NSBCA
Binary files differ
diff --git a/files/arc/bm_anime/narc_0055.bin b/files/arc/bm_anime/narc_0055.NSBTA
index 5210870f..5210870f 100644
--- a/files/arc/bm_anime/narc_0055.bin
+++ b/files/arc/bm_anime/narc_0055.NSBTA
Binary files differ
diff --git a/files/arc/bm_anime/narc_0056.bin b/files/arc/bm_anime/narc_0056.NSBTA
index d658427e..d658427e 100644
--- a/files/arc/bm_anime/narc_0056.bin
+++ b/files/arc/bm_anime/narc_0056.NSBTA
Binary files differ
diff --git a/files/arc/bm_anime/narc_0057.bin b/files/arc/bm_anime/narc_0057.NSBTA
index 0d0a990c..0d0a990c 100644
--- a/files/arc/bm_anime/narc_0057.bin
+++ b/files/arc/bm_anime/narc_0057.NSBTA
Binary files differ
diff --git a/files/arc/bm_anime/narc_0058.bin b/files/arc/bm_anime/narc_0058.NSBTA
index 39636870..39636870 100644
--- a/files/arc/bm_anime/narc_0058.bin
+++ b/files/arc/bm_anime/narc_0058.NSBTA
Binary files differ
diff --git a/files/arc/bm_anime/narc_0059.bin b/files/arc/bm_anime/narc_0059.NSBTA
index bcb907f4..bcb907f4 100644
--- a/files/arc/bm_anime/narc_0059.bin
+++ b/files/arc/bm_anime/narc_0059.NSBTA
Binary files differ
diff --git a/files/arc/bm_anime/narc_0060.bin b/files/arc/bm_anime/narc_0060.NSBTA
index 43d1507a..43d1507a 100644
--- a/files/arc/bm_anime/narc_0060.bin
+++ b/files/arc/bm_anime/narc_0060.NSBTA
Binary files differ
diff --git a/files/arc/bm_anime/narc_0061.bin b/files/arc/bm_anime/narc_0061.NSBTA
index 434f78ca..434f78ca 100644
--- a/files/arc/bm_anime/narc_0061.bin
+++ b/files/arc/bm_anime/narc_0061.NSBTA
Binary files differ
diff --git a/files/arc/bm_anime/narc_0062.bin b/files/arc/bm_anime/narc_0062.NSBTA
index 1a9980bf..1a9980bf 100644
--- a/files/arc/bm_anime/narc_0062.bin
+++ b/files/arc/bm_anime/narc_0062.NSBTA
Binary files differ
diff --git a/files/arc/bm_anime/narc_0063.bin b/files/arc/bm_anime/narc_0063.NSBTA
index 5c6eb367..5c6eb367 100644
--- a/files/arc/bm_anime/narc_0063.bin
+++ b/files/arc/bm_anime/narc_0063.NSBTA
Binary files differ
diff --git a/files/arc/ship_demo/narc_0000.bin b/files/arc/ship_demo/narc_0000.NSBCA
index 9ed7795a..9ed7795a 100644
--- a/files/arc/ship_demo/narc_0000.bin
+++ b/files/arc/ship_demo/narc_0000.NSBCA
Binary files differ
diff --git a/files/arc/ship_demo/narc_0001.bin b/files/arc/ship_demo/narc_0001.NSBMA
index 7eba42fc..7eba42fc 100644
--- a/files/arc/ship_demo/narc_0001.bin
+++ b/files/arc/ship_demo/narc_0001.NSBMA
Binary files differ
diff --git a/files/arc/ship_demo/narc_0002.bin b/files/arc/ship_demo/narc_0002.NSBMD
index 89d31b2c..89d31b2c 100644
--- a/files/arc/ship_demo/narc_0002.bin
+++ b/files/arc/ship_demo/narc_0002.NSBMD
Binary files differ
diff --git a/files/arc/ship_demo/narc_0003.bin b/files/arc/ship_demo/narc_0003.NSBTA
index 87585307..87585307 100644
--- a/files/arc/ship_demo/narc_0003.bin
+++ b/files/arc/ship_demo/narc_0003.NSBTA
Binary files differ
diff --git a/files/arc/ship_demo/narc_0004.bin b/files/arc/ship_demo/narc_0004.NSBTP
index 957df40f..957df40f 100644
--- a/files/arc/ship_demo/narc_0004.bin
+++ b/files/arc/ship_demo/narc_0004.NSBTP
Binary files differ
diff --git a/files/arc/ship_demo/narc_0005.bin b/files/arc/ship_demo/narc_0005.NSBCA
index f88c4d5b..f88c4d5b 100644
--- a/files/arc/ship_demo/narc_0005.bin
+++ b/files/arc/ship_demo/narc_0005.NSBCA
Binary files differ
diff --git a/files/arc/ship_demo/narc_0006.bin b/files/arc/ship_demo/narc_0006.NSBMA
index 4978c309..4978c309 100644
--- a/files/arc/ship_demo/narc_0006.bin
+++ b/files/arc/ship_demo/narc_0006.NSBMA
Binary files differ
diff --git a/files/arc/ship_demo/narc_0007.bin b/files/arc/ship_demo/narc_0007.NSBMD
index 5835a54d..5835a54d 100644
--- a/files/arc/ship_demo/narc_0007.bin
+++ b/files/arc/ship_demo/narc_0007.NSBMD
Binary files differ
diff --git a/files/arc/ship_demo/narc_0008.bin b/files/arc/ship_demo/narc_0008.NSBTA
index 387fbadc..387fbadc 100644
--- a/files/arc/ship_demo/narc_0008.bin
+++ b/files/arc/ship_demo/narc_0008.NSBTA
Binary files differ
diff --git a/files/arc/ship_demo/narc_0009.bin b/files/arc/ship_demo/narc_0009.NSBTP
index 2fe9e3ac..2fe9e3ac 100644
--- a/files/arc/ship_demo/narc_0009.bin
+++ b/files/arc/ship_demo/narc_0009.NSBTP
Binary files differ
diff --git a/files/arc/ship_demo/narc_0010.bin b/files/arc/ship_demo/narc_0010.NSBCA
index 195b2452..195b2452 100644
--- a/files/arc/ship_demo/narc_0010.bin
+++ b/files/arc/ship_demo/narc_0010.NSBCA
Binary files differ
diff --git a/files/arc/ship_demo/narc_0011.bin b/files/arc/ship_demo/narc_0011.NSBMA
index a53ecbdc..a53ecbdc 100644
--- a/files/arc/ship_demo/narc_0011.bin
+++ b/files/arc/ship_demo/narc_0011.NSBMA
Binary files differ
diff --git a/files/arc/ship_demo/narc_0012.bin b/files/arc/ship_demo/narc_0012.NSBMD
index c6364e24..c6364e24 100644
--- a/files/arc/ship_demo/narc_0012.bin
+++ b/files/arc/ship_demo/narc_0012.NSBMD
Binary files differ
diff --git a/files/arc/ship_demo/narc_0013.bin b/files/arc/ship_demo/narc_0013.NSBTA
index 80431301..80431301 100644
--- a/files/arc/ship_demo/narc_0013.bin
+++ b/files/arc/ship_demo/narc_0013.NSBTA
Binary files differ
diff --git a/files/arc/ship_demo/narc_0014.bin b/files/arc/ship_demo/narc_0014.NSBTP
index 38a63dc5..38a63dc5 100644
--- a/files/arc/ship_demo/narc_0014.bin
+++ b/files/arc/ship_demo/narc_0014.NSBTP
Binary files differ
diff --git a/files/arc/ship_demo/narc_0015.bin b/files/arc/ship_demo/narc_0015.NSBCA
index 544df372..544df372 100644
--- a/files/arc/ship_demo/narc_0015.bin
+++ b/files/arc/ship_demo/narc_0015.NSBCA
Binary files differ
diff --git a/files/arc/ship_demo/narc_0016.bin b/files/arc/ship_demo/narc_0016.NSBMA
index c087f887..c087f887 100644
--- a/files/arc/ship_demo/narc_0016.bin
+++ b/files/arc/ship_demo/narc_0016.NSBMA
Binary files differ
diff --git a/files/arc/ship_demo/narc_0017.bin b/files/arc/ship_demo/narc_0017.NSBMD
index 5659886f..5659886f 100644
--- a/files/arc/ship_demo/narc_0017.bin
+++ b/files/arc/ship_demo/narc_0017.NSBMD
Binary files differ
diff --git a/files/arc/ship_demo/narc_0018.bin b/files/arc/ship_demo/narc_0018.NSBTA
index e894a586..e894a586 100644
--- a/files/arc/ship_demo/narc_0018.bin
+++ b/files/arc/ship_demo/narc_0018.NSBTA
Binary files differ
diff --git a/files/arc/ship_demo/narc_0019.bin b/files/arc/ship_demo/narc_0019.NSBTP
index 375a630d..375a630d 100644
--- a/files/arc/ship_demo/narc_0019.bin
+++ b/files/arc/ship_demo/narc_0019.NSBTP
Binary files differ
diff --git a/files/data/demo_climax/narc_0000.bin b/files/data/demo_climax/narc_0000.NSBMD
index 3655f44a..3655f44a 100644
--- a/files/data/demo_climax/narc_0000.bin
+++ b/files/data/demo_climax/narc_0000.NSBMD
Binary files differ
diff --git a/files/data/demo_climax/narc_0001.bin b/files/data/demo_climax/narc_0001.NSBTA
index 1f0dd4c8..1f0dd4c8 100644
--- a/files/data/demo_climax/narc_0001.bin
+++ b/files/data/demo_climax/narc_0001.NSBTA
Binary files differ
diff --git a/files/data/demo_climax/narc_0002.bin b/files/data/demo_climax/narc_0002.NSBCA
index 4308f848..4308f848 100644
--- a/files/data/demo_climax/narc_0002.bin
+++ b/files/data/demo_climax/narc_0002.NSBCA
Binary files differ
diff --git a/files/data/demo_climax/narc_0003.bin b/files/data/demo_climax/narc_0003.NSBMA
index 5dba435b..5dba435b 100644
--- a/files/data/demo_climax/narc_0003.bin
+++ b/files/data/demo_climax/narc_0003.NSBMA
Binary files differ
diff --git a/files/data/demo_climax/narc_0004.bin b/files/data/demo_climax/narc_0004.NSBMD
index 2b54ce9c..2b54ce9c 100644
--- a/files/data/demo_climax/narc_0004.bin
+++ b/files/data/demo_climax/narc_0004.NSBMD
Binary files differ
diff --git a/files/data/demo_climax/narc_0005.bin b/files/data/demo_climax/narc_0005.NSBMD
index 6581547b..6581547b 100644
--- a/files/data/demo_climax/narc_0005.bin
+++ b/files/data/demo_climax/narc_0005.NSBMD
Binary files differ
diff --git a/files/data/demo_climax/narc_0006.bin b/files/data/demo_climax/narc_0006.NSBMD
index fe35ec0d..fe35ec0d 100644
--- a/files/data/demo_climax/narc_0006.bin
+++ b/files/data/demo_climax/narc_0006.NSBMD
Binary files differ
diff --git a/files/data/demo_climax/narc_0007.bin b/files/data/demo_climax/narc_0007.NSBMD
index cbeacc23..cbeacc23 100644
--- a/files/data/demo_climax/narc_0007.bin
+++ b/files/data/demo_climax/narc_0007.NSBMD
Binary files differ
diff --git a/files/data/demo_climax/narc_0008.bin b/files/data/demo_climax/narc_0008.NSBCA
index 1c669b48..1c669b48 100644
--- a/files/data/demo_climax/narc_0008.bin
+++ b/files/data/demo_climax/narc_0008.NSBCA
Binary files differ
diff --git a/files/data/demo_climax/narc_0009.bin b/files/data/demo_climax/narc_0009.NSBMA
index e7e51b7f..e7e51b7f 100644
--- a/files/data/demo_climax/narc_0009.bin
+++ b/files/data/demo_climax/narc_0009.NSBMA
Binary files differ
diff --git a/files/data/demo_climax/narc_0010.bin b/files/data/demo_climax/narc_0010.NSBTA
index 35de5a2a..35de5a2a 100644
--- a/files/data/demo_climax/narc_0010.bin
+++ b/files/data/demo_climax/narc_0010.NSBTA
Binary files differ
diff --git a/files/data/demo_climax/narc_0011.bin b/files/data/demo_climax/narc_0011.NSBVA
index e4972dad..e4972dad 100644
--- a/files/data/demo_climax/narc_0011.bin
+++ b/files/data/demo_climax/narc_0011.NSBVA
Binary files differ
diff --git a/files/data/demo_climax/narc_0012.bin b/files/data/demo_climax/narc_0012.NSBMD
index 7f25d734..7f25d734 100644
--- a/files/data/demo_climax/narc_0012.bin
+++ b/files/data/demo_climax/narc_0012.NSBMD
Binary files differ
diff --git a/files/data/demo_climax/narc_0013.bin b/files/data/demo_climax/narc_0013.NSBCA
index ff7c5365..ff7c5365 100644
--- a/files/data/demo_climax/narc_0013.bin
+++ b/files/data/demo_climax/narc_0013.NSBCA
Binary files differ
diff --git a/files/data/demo_climax/narc_0014.bin b/files/data/demo_climax/narc_0014.NSBMA
index da0b1458..da0b1458 100644
--- a/files/data/demo_climax/narc_0014.bin
+++ b/files/data/demo_climax/narc_0014.NSBMA
Binary files differ
diff --git a/files/data/demo_climax/narc_0015.bin b/files/data/demo_climax/narc_0015.NSBMD
index 5cf9e514..5cf9e514 100644
--- a/files/data/demo_climax/narc_0015.bin
+++ b/files/data/demo_climax/narc_0015.NSBMD
Binary files differ
diff --git a/files/data/demo_climax/narc_0016.bin b/files/data/demo_climax/narc_0016.NSBCA
index 71288973..71288973 100644
--- a/files/data/demo_climax/narc_0016.bin
+++ b/files/data/demo_climax/narc_0016.NSBCA
Binary files differ
diff --git a/files/data/demo_climax/narc_0017.bin b/files/data/demo_climax/narc_0017.NSBMA
index 404c0486..404c0486 100644
--- a/files/data/demo_climax/narc_0017.bin
+++ b/files/data/demo_climax/narc_0017.NSBMA
Binary files differ
diff --git a/files/data/demo_climax/narc_0018.bin b/files/data/demo_climax/narc_0018.NSBTA
index 4b02b818..4b02b818 100644
--- a/files/data/demo_climax/narc_0018.bin
+++ b/files/data/demo_climax/narc_0018.NSBTA
Binary files differ
diff --git a/files/data/demo_climax/narc_0019.bin b/files/data/demo_climax/narc_0019.NSBVA
index 8bd02499..8bd02499 100644
--- a/files/data/demo_climax/narc_0019.bin
+++ b/files/data/demo_climax/narc_0019.NSBVA
Binary files differ
diff --git a/files/data/mmodel/fldeff/narc_0000.bin b/files/data/mmodel/fldeff/narc_0000.NSBTX
index 8e49608d..8e49608d 100644
--- a/files/data/mmodel/fldeff/narc_0000.bin
+++ b/files/data/mmodel/fldeff/narc_0000.NSBTX
Binary files differ
diff --git a/files/data/mmodel/fldeff/narc_0001.bin b/files/data/mmodel/fldeff/narc_0001.NSBTX
index ea216570..ea216570 100644
--- a/files/data/mmodel/fldeff/narc_0001.bin
+++ b/files/data/mmodel/fldeff/narc_0001.NSBTX
Binary files differ
diff --git a/files/data/mmodel/fldeff/narc_0002.bin b/files/data/mmodel/fldeff/narc_0002.NSBTX
index 815023c7..815023c7 100644
--- a/files/data/mmodel/fldeff/narc_0002.bin
+++ b/files/data/mmodel/fldeff/narc_0002.NSBTX
Binary files differ
diff --git a/files/data/mmodel/fldeff/narc_0003.bin b/files/data/mmodel/fldeff/narc_0003.NSBTX
index 50463612..50463612 100644
--- a/files/data/mmodel/fldeff/narc_0003.bin
+++ b/files/data/mmodel/fldeff/narc_0003.NSBTX
Binary files differ
diff --git a/files/data/mmodel/fldeff/narc_0004.bin b/files/data/mmodel/fldeff/narc_0004.NSBTX
index b03b2a6f..b03b2a6f 100644
--- a/files/data/mmodel/fldeff/narc_0004.bin
+++ b/files/data/mmodel/fldeff/narc_0004.NSBTX
Binary files differ
diff --git a/files/data/mmodel/fldeff/narc_0005.bin b/files/data/mmodel/fldeff/narc_0005.NSBTX
index e1864caf..e1864caf 100644
--- a/files/data/mmodel/fldeff/narc_0005.bin
+++ b/files/data/mmodel/fldeff/narc_0005.NSBTX
Binary files differ
diff --git a/files/data/mmodel/fldeff/narc_0006.bin b/files/data/mmodel/fldeff/narc_0006.NSBTX
index fde4948e..fde4948e 100644
--- a/files/data/mmodel/fldeff/narc_0006.bin
+++ b/files/data/mmodel/fldeff/narc_0006.NSBTX
Binary files differ
diff --git a/files/data/mmodel/fldeff/narc_0007.bin b/files/data/mmodel/fldeff/narc_0007.NSBTX
index 52a7ff44..52a7ff44 100644
--- a/files/data/mmodel/fldeff/narc_0007.bin
+++ b/files/data/mmodel/fldeff/narc_0007.NSBTX
Binary files differ
diff --git a/files/data/mmodel/fldeff/narc_0008.bin b/files/data/mmodel/fldeff/narc_0008.NSBTX
index 9bb218de..9bb218de 100644
--- a/files/data/mmodel/fldeff/narc_0008.bin
+++ b/files/data/mmodel/fldeff/narc_0008.NSBTX
Binary files differ
diff --git a/files/data/mmodel/fldeff/narc_0009.bin b/files/data/mmodel/fldeff/narc_0009.NSBTX
index 6489fa8d..6489fa8d 100644
--- a/files/data/mmodel/fldeff/narc_0009.bin
+++ b/files/data/mmodel/fldeff/narc_0009.NSBTX
Binary files differ
diff --git a/files/data/mmodel/fldeff/narc_0010.bin b/files/data/mmodel/fldeff/narc_0010.NSBTX
index 63191309..63191309 100644
--- a/files/data/mmodel/fldeff/narc_0010.bin
+++ b/files/data/mmodel/fldeff/narc_0010.NSBTX
Binary files differ
diff --git a/files/data/mmodel/fldeff/narc_0011.bin b/files/data/mmodel/fldeff/narc_0011.NSBTX
index 3962dd5e..3962dd5e 100644
--- a/files/data/mmodel/fldeff/narc_0011.bin
+++ b/files/data/mmodel/fldeff/narc_0011.NSBTX
Binary files differ
diff --git a/files/data/mmodel/mmodel/narc_0000.bin b/files/data/mmodel/mmodel/narc_0000.NSBTX
index daf7ba36..daf7ba36 100644
--- a/files/data/mmodel/mmodel/narc_0000.bin
+++ b/files/data/mmodel/mmodel/narc_0000.NSBTX
Binary files differ
diff --git a/files/demo/title/op_demo/narc_0064.bin b/files/demo/title/op_demo/narc_0064.NSBMD
index d80229d5..d80229d5 100644
--- a/files/demo/title/op_demo/narc_0064.bin
+++ b/files/demo/title/op_demo/narc_0064.NSBMD
Binary files differ
diff --git a/files/demo/title/op_demo/narc_0065.bin b/files/demo/title/op_demo/narc_0065.NSBMD
index 064213d1..064213d1 100644
--- a/files/demo/title/op_demo/narc_0065.bin
+++ b/files/demo/title/op_demo/narc_0065.NSBMD
Binary files differ
diff --git a/files/demo/title/op_demo/narc_0066.bin b/files/demo/title/op_demo/narc_0066.NSBMD
index 92696b07..92696b07 100644
--- a/files/demo/title/op_demo/narc_0066.bin
+++ b/files/demo/title/op_demo/narc_0066.NSBMD
Binary files differ
diff --git a/files/demo/title/op_demo/narc_0067.bin b/files/demo/title/op_demo/narc_0067.NSBMD
index fdfef1a6..fdfef1a6 100644
--- a/files/demo/title/op_demo/narc_0067.bin
+++ b/files/demo/title/op_demo/narc_0067.NSBMD
Binary files differ
diff --git a/files/demo/title/op_demo/narc_0068.bin b/files/demo/title/op_demo/narc_0068.NSBMD
index 946ad766..946ad766 100644
--- a/files/demo/title/op_demo/narc_0068.bin
+++ b/files/demo/title/op_demo/narc_0068.NSBMD
Binary files differ
diff --git a/files/demo/title/op_demo/narc_0069.bin b/files/demo/title/op_demo/narc_0069.NSBMD
index 141a7c02..141a7c02 100644
--- a/files/demo/title/op_demo/narc_0069.bin
+++ b/files/demo/title/op_demo/narc_0069.NSBMD
Binary files differ
diff --git a/files/demo/title/op_demo/narc_0070.bin b/files/demo/title/op_demo/narc_0070.NSBTX
index 785fec33..785fec33 100644
--- a/files/demo/title/op_demo/narc_0070.bin
+++ b/files/demo/title/op_demo/narc_0070.NSBTX
Binary files differ
diff --git a/files/demo/title/titledemo/.gitignore b/files/demo/title/titledemo/.gitignore
index e16f0811..6dee0d75 100644
--- a/files/demo/title/titledemo/.gitignore
+++ b/files/demo/title/titledemo/.gitignore
@@ -1,2 +1,3 @@
+narc_0000.NSCR
*.NCLR
*.NCGR
diff --git a/files/demo/title/titledemo/.knarcignore b/files/demo/title/titledemo/.knarcignore
index 2856080a..ebdff6e6 100644
--- a/files/demo/title/titledemo/.knarcignore
+++ b/files/demo/title/titledemo/.knarcignore
@@ -1,2 +1,3 @@
*.png
*.pal
+*.json
diff --git a/files/demo/title/titledemo/narc_0000.NSCR b/files/demo/title/titledemo/narc_0000.NSCR
deleted file mode 100644
index 5f25cc5e..00000000
--- a/files/demo/title/titledemo/narc_0000.NSCR
+++ /dev/null
Binary files differ
diff --git a/files/demo/title/titledemo/narc_0000_map.json b/files/demo/title/titledemo/narc_0000_map.json
new file mode 100644
index 00000000..1df9d38b
--- /dev/null
+++ b/files/demo/title/titledemo/narc_0000_map.json
@@ -0,0 +1,39 @@
+{ "compressionlevel":-1,
+ "editorsettings":
+ {
+ "export":
+ {
+ "target":"."
+ }
+ },
+ "height":32,
+ "infinite":false,
+ "layers":[
+ {
+ "data":[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
+ "height":32,
+ "id":1,
+ "name":"Tile Layer 1",
+ "opacity":1,
+ "type":"tilelayer",
+ "visible":true,
+ "width":32,
+ "x":0,
+ "y":0
+ }],
+ "nextlayerid":2,
+ "nextobjectid":1,
+ "orientation":"orthogonal",
+ "renderorder":"right-down",
+ "tiledversion":"1.4.3",
+ "tileheight":8,
+ "tilesets":[
+ {
+ "firstgid":1,
+ "source":"narc_0000_tileset.json"
+ }],
+ "tilewidth":8,
+ "type":"map",
+ "version":1.4,
+ "width":32
+} \ No newline at end of file
diff --git a/files/demo/title/titledemo/narc_0000_tileset.json b/files/demo/title/titledemo/narc_0000_tileset.json
new file mode 100644
index 00000000..d691e3e1
--- /dev/null
+++ b/files/demo/title/titledemo/narc_0000_tileset.json
@@ -0,0 +1,14 @@
+{ "columns":32,
+ "image":"narc_0001.png",
+ "imageheight":128,
+ "imagewidth":256,
+ "margin":0,
+ "name":"narc_0001",
+ "spacing":0,
+ "tilecount":512,
+ "tiledversion":"1.4.3",
+ "tileheight":8,
+ "tilewidth":8,
+ "type":"tileset",
+ "version":1.4
+} \ No newline at end of file
diff --git a/files/demo/title/titledemo/narc_0005.bin b/files/demo/title/titledemo/narc_0005.NSBMD
index c049665b..c049665b 100644
--- a/files/demo/title/titledemo/narc_0005.bin
+++ b/files/demo/title/titledemo/narc_0005.NSBMD
Binary files differ
diff --git a/files/demo/title/titledemo/narc_0006.bin b/files/demo/title/titledemo/narc_0006.NSBMD
index a784e9e1..a784e9e1 100644
--- a/files/demo/title/titledemo/narc_0006.bin
+++ b/files/demo/title/titledemo/narc_0006.NSBMD
Binary files differ
diff --git a/files/demo/title/titledemo/narc_0018.bin b/files/demo/title/titledemo/narc_0018.NSBTA
index f0e87456..f0e87456 100644
--- a/files/demo/title/titledemo/narc_0018.bin
+++ b/files/demo/title/titledemo/narc_0018.NSBTA
Binary files differ
diff --git a/files/demo/title/titledemo/narc_0019.bin b/files/demo/title/titledemo/narc_0019.NSBTA
index 2e47d118..2e47d118 100644
--- a/files/demo/title/titledemo/narc_0019.bin
+++ b/files/demo/title/titledemo/narc_0019.NSBTA
Binary files differ
diff --git a/files/poketool/icongra/poke_icon/.gitignore b/files/poketool/icongra/poke_icon/.gitignore
index ce012113..15216251 100644
--- a/files/poketool/icongra/poke_icon/.gitignore
+++ b/files/poketool/icongra/poke_icon/.gitignore
@@ -1,4 +1,5 @@
narc_0000.NCLR
+narc_0002.NCER
narc_0007.NCGR
narc_0008.NCGR
narc_0009.NCGR
diff --git a/files/poketool/icongra/poke_icon/.knarcignore b/files/poketool/icongra/poke_icon/.knarcignore
index 2856080a..ebdff6e6 100644
--- a/files/poketool/icongra/poke_icon/.knarcignore
+++ b/files/poketool/icongra/poke_icon/.knarcignore
@@ -1,2 +1,3 @@
*.png
*.pal
+*.json
diff --git a/files/poketool/icongra/poke_icon/narc_0002.NCER b/files/poketool/icongra/poke_icon/narc_0002.NCER
deleted file mode 100644
index 37af7d5b..00000000
--- a/files/poketool/icongra/poke_icon/narc_0002.NCER
+++ /dev/null
Binary files differ
diff --git a/files/poketool/icongra/poke_icon/narc_0002.json b/files/poketool/icongra/poke_icon/narc_0002.json
new file mode 100644
index 00000000..a0d15511
--- /dev/null
+++ b/files/poketool/icongra/poke_icon/narc_0002.json
@@ -0,0 +1,67 @@
+{
+ "label": true,
+ "extended": true,
+ "imageHeight": 32,
+ "imageWidth": 32,
+ "cellCount": 2,
+ "cells": [
+ {
+ "readOnly": 2054,
+ "maxX": 15,
+ "maxY": 15,
+ "minX": 65520,
+ "minY": 65520,
+ "OAM": {
+ "Attr0": {
+ "YCoordinate": 240,
+ "Rotation": false,
+ "SizeDisable": false,
+ "Mode": 0,
+ "Mosaic": false,
+ "Colours": 16,
+ "Shape": 0
+ },
+ "Attr1": {
+ "XCoordinate": 496,
+ "RotationScaling": 0,
+ "Size": 2
+ },
+ "Attr2": {
+ "CharName": 0,
+ "Priority": 0,
+ "Palette": 0
+ }
+ },
+ "label": "CellAnime0"
+ },
+ {
+ "readOnly": 2054,
+ "maxX": 15,
+ "maxY": 15,
+ "minX": 65520,
+ "minY": 65520,
+ "OAM": {
+ "Attr0": {
+ "YCoordinate": 240,
+ "Rotation": false,
+ "SizeDisable": false,
+ "Mode": 0,
+ "Mosaic": false,
+ "Colours": 16,
+ "Shape": 0
+ },
+ "Attr1": {
+ "XCoordinate": 496,
+ "RotationScaling": 0,
+ "Size": 2
+ },
+ "Attr2": {
+ "CharName": 16,
+ "Priority": 0,
+ "Palette": 0
+ }
+ },
+ "label": "CellAnime1"
+ }
+ ]
+}
diff --git a/filesystem.mk b/filesystem.mk
index 6f48d05b..8f78dee6 100644
--- a/filesystem.mk
+++ b/filesystem.mk
@@ -317,6 +317,10 @@ $(O2NARC_TARGETS): %.narc: %.json %.json.txt $$(dep)
$(O2NARC) $(O2NARCFLAGS) $*.o $@
@$(RM) $*.o $*.c
+files/application/wifi_earth/wifi_earth.narc: \
+ files/application/wifi_earth/wifi_earth/narc_0005.NCGR \
+ files/application/wifi_earth/wifi_earth/narc_0006.NCLR
+
files/battle/graphic/batt_bg.narc: \
files/battle/graphic/batt_bg/narc_0156.NSCR.lz \
files/battle/graphic/batt_bg/narc_0142.NSCR.lz \
@@ -2286,6 +2290,7 @@ files/data/namein.narc: \
files/data/namein/narc_0007.NSCR.lz
files/demo/title/titledemo.narc: \
+ files/demo/title/titledemo/narc_0000.NSCR \
files/demo/title/titledemo/narc_0001.NCGR \
files/demo/title/titledemo/narc_0001.NCLR \
files/demo/title/titledemo/narc_0003.NCGR \
@@ -2579,6 +2584,7 @@ files/poketool/pokegra/pokegra.narc: \
files/poketool/icongra/poke_icon.narc: \
files/poketool/icongra/poke_icon/narc_0000.NCLR \
+ files/poketool/icongra/poke_icon/narc_0002.NCER \
files/poketool/icongra/poke_icon/narc_0007.NCGR \
files/poketool/icongra/poke_icon/narc_0008.NCGR \
files/poketool/icongra/poke_icon/narc_0009.NCGR \
diff --git a/graphics_rules.mk b/graphics_rules.mk
index b0d05eb0..bd5c187d 100644
--- a/graphics_rules.mk
+++ b/graphics_rules.mk
@@ -88,9 +88,12 @@ CLOBBER_SIZE_VERSION101_NCGR_FILES := files/graphic/bag_gra/narc_0002.NCGR \
files/poketool/icongra/poke_icon/narc_0016.NCGR \
files/poketool/icongra/poke_icon/narc_0402.NCGR
-4BPP_NCLR_FILES := files/demo/title/titledemo/narc_0016.NCLR \
+4BPP_NCLR_FILES := files/application/wifi_earth/wifi_earth/narc_0006.NCLR \
+ files/demo/title/titledemo/narc_0016.NCLR \
files/poketool/icongra/poke_icon/narc_0000.NCLR
+8BPP_NSCR_FILES := files/demo/title/titledemo/narc_0000.NSCR
+
IR_NCLR_FILES := files/itemtool/itemdata/item_icon/narc_0028.NCLR \
files/itemtool/itemdata/item_icon/narc_0029.NCLR \
files/itemtool/itemdata/item_icon/narc_0032.NCLR \
@@ -125,7 +128,8 @@ IR_NCLR_FILES := files/itemtool/itemdata/item_icon/narc_0028.NCLR \
VERSION101_SOPC_8BPP_NCGR_FILES := files/demo/title/titledemo/narc_0001.NCGR \
files/demo/title/titledemo/narc_0003.NCGR
-VERSION101_SOPC_NCGR_FILES := files/demo/title/titledemo/narc_0007.NCGR \
+VERSION101_SOPC_NCGR_FILES := files/application/wifi_earth/wifi_earth/narc_0005.NCGR \
+ files/demo/title/titledemo/narc_0007.NCGR \
files/demo/title/titledemo/narc_0011.NCGR \
files/demo/title/titledemo/narc_0015.NCGR
@@ -404,7 +408,8 @@ SCANNED_NCGR_FILES := files/poketool/pokegra/pokegra/narc_0006.NCGR \
files/poketool/trgra/trfgra/narc_0192.NCGR \
files/poketool/trgra/trfgra/narc_0194.NCGR \
-NCGR_CLEAN_LIST := files/data/cell0.NCGR \
+NCGR_CLEAN_LIST := files/application/wifi_earth/wifi_earth/narc_0005.NCGR \
+ files/data/cell0.NCGR \
files/demo/title/titledemo/narc_0001.NCGR \
files/demo/title/titledemo/narc_0003.NCGR \
files/demo/title/titledemo/narc_0007.NCGR \
@@ -642,7 +647,8 @@ NCGR_CLEAN_LIST := files/data/cell0.NCGR \
files/poketool/trgra/trfgra/narc_0194.NCGR \
-NCLR_CLEAN_LIST := files/data/cell0.NCLR \
+NCLR_CLEAN_LIST := files/application/wifi_earth/wifi_earth/narc_0006.NCLR \
+ files/data/cell0.NCLR \
files/demo/title/titledemo/narc_0001.NCLR \
files/demo/title/titledemo/narc_0003.NCLR \
files/demo/title/titledemo/narc_0009.NCLR \
@@ -873,3 +879,7 @@ NCLR_CLEAN_LIST := files/data/cell0.NCLR \
files/poketool/trgra/trfgra/narc_0190.NCLR \
files/poketool/trgra/trfgra/narc_0192.NCLR \
files/poketool/trgra/trfgra/narc_0194.NCLR \
+
+NCER_CLEAN_LIST := files/poketool/icongra/poke_icon/narc_0002.NCER
+
+NSCR_CLEAN_LIST := files/demo/title/titledemo/narc_0000.NSCR
diff --git a/tools/nitrogfx/Makefile b/tools/nitrogfx/Makefile
index 5b75d652..eadf2be5 100644
--- a/tools/nitrogfx/Makefile
+++ b/tools/nitrogfx/Makefile
@@ -4,7 +4,7 @@ CFLAGS = -Wall -Wextra -Werror -Wno-sign-compare -std=c11 -O2 -DPNG_SKIP_SETJMP_
LIBS = -lpng -lz
-SRCS = main.c convert_png.c gfx.c jasc_pal.c lz.c rl.c util.c font.c huff.c
+SRCS = main.c convert_png.c gfx.c jasc_pal.c lz.c rl.c util.c font.c huff.c json.c cJSON.c
.PHONY: all clean
diff --git a/tools/nitrogfx/cJSON.c b/tools/nitrogfx/cJSON.c
new file mode 100644
index 00000000..b0c12115
--- /dev/null
+++ b/tools/nitrogfx/cJSON.c
@@ -0,0 +1,3110 @@
+/*
+ Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+/* cJSON */
+/* JSON parser in C. */
+
+/* disable warnings about old C89 functions in MSVC */
+#if !defined(_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER)
+#define _CRT_SECURE_NO_DEPRECATE
+#endif
+
+#ifdef __GNUC__
+#pragma GCC visibility push(default)
+#endif
+#if defined(_MSC_VER)
+#pragma warning (push)
+/* disable warning about single line comments in system headers */
+#pragma warning (disable : 4001)
+#endif
+
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <ctype.h>
+#include <float.h>
+
+#ifdef ENABLE_LOCALES
+#include <locale.h>
+#endif
+
+#if defined(_MSC_VER)
+#pragma warning (pop)
+#endif
+#ifdef __GNUC__
+#pragma GCC visibility pop
+#endif
+
+#include "cJSON.h"
+
+/* define our own boolean type */
+#ifdef true
+#undef true
+#endif
+#define true ((cJSON_bool)1)
+
+#ifdef false
+#undef false
+#endif
+#define false ((cJSON_bool)0)
+
+/* define isnan and isinf for ANSI C, if in C99 or above, isnan and isinf has been defined in math.h */
+#ifndef isinf
+#define isinf(d) (isnan((d - d)) && !isnan(d))
+#endif
+#ifndef isnan
+#define isnan(d) (d != d)
+#endif
+
+#ifndef NAN
+#ifdef _WIN32
+#define NAN sqrt(-1.0)
+#else
+#define NAN 0.0/0.0
+#endif
+#endif
+
+typedef struct {
+ const unsigned char *json;
+ size_t position;
+} error;
+static error global_error = { NULL, 0 };
+
+CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void)
+{
+ return (const char*) (global_error.json + global_error.position);
+}
+
+CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item)
+{
+ if (!cJSON_IsString(item))
+ {
+ return NULL;
+ }
+
+ return item->valuestring;
+}
+
+CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item)
+{
+ if (!cJSON_IsNumber(item))
+ {
+ return (double) NAN;
+ }
+
+ return item->valuedouble;
+}
+
+/* This is a safeguard to prevent copy-pasters from using incompatible C and header files */
+#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 14)
+#error cJSON.h and cJSON.c have different versions. Make sure that both have the same.
+#endif
+
+CJSON_PUBLIC(const char*) cJSON_Version(void)
+{
+ static char version[15];
+ sprintf(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH);
+
+ return version;
+}
+
+/* Case insensitive string comparison, doesn't consider two NULL pointers equal though */
+static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2)
+{
+ if ((string1 == NULL) || (string2 == NULL))
+ {
+ return 1;
+ }
+
+ if (string1 == string2)
+ {
+ return 0;
+ }
+
+ for(; tolower(*string1) == tolower(*string2); (void)string1++, string2++)
+ {
+ if (*string1 == '\0')
+ {
+ return 0;
+ }
+ }
+
+ return tolower(*string1) - tolower(*string2);
+}
+
+typedef struct internal_hooks
+{
+ void *(CJSON_CDECL *allocate)(size_t size);
+ void (CJSON_CDECL *deallocate)(void *pointer);
+ void *(CJSON_CDECL *reallocate)(void *pointer, size_t size);
+} internal_hooks;
+
+#if defined(_MSC_VER)
+/* work around MSVC error C2322: '...' address of dllimport '...' is not static */
+static void * CJSON_CDECL internal_malloc(size_t size)
+{
+ return malloc(size);
+}
+static void CJSON_CDECL internal_free(void *pointer)
+{
+ free(pointer);
+}
+static void * CJSON_CDECL internal_realloc(void *pointer, size_t size)
+{
+ return realloc(pointer, size);
+}
+#else
+#define internal_malloc malloc
+#define internal_free free
+#define internal_realloc realloc
+#endif
+
+/* strlen of character literals resolved at compile time */
+#define static_strlen(string_literal) (sizeof(string_literal) - sizeof(""))
+
+static internal_hooks global_hooks = { internal_malloc, internal_free, internal_realloc };
+
+static unsigned char* cJSON_strdup(const unsigned char* string, const internal_hooks * const hooks)
+{
+ size_t length = 0;
+ unsigned char *copy = NULL;
+
+ if (string == NULL)
+ {
+ return NULL;
+ }
+
+ length = strlen((const char*)string) + sizeof("");
+ copy = (unsigned char*)hooks->allocate(length);
+ if (copy == NULL)
+ {
+ return NULL;
+ }
+ memcpy(copy, string, length);
+
+ return copy;
+}
+
+CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks)
+{
+ if (hooks == NULL)
+ {
+ /* Reset hooks */
+ global_hooks.allocate = malloc;
+ global_hooks.deallocate = free;
+ global_hooks.reallocate = realloc;
+ return;
+ }
+
+ global_hooks.allocate = malloc;
+ if (hooks->malloc_fn != NULL)
+ {
+ global_hooks.allocate = hooks->malloc_fn;
+ }
+
+ global_hooks.deallocate = free;
+ if (hooks->free_fn != NULL)
+ {
+ global_hooks.deallocate = hooks->free_fn;
+ }
+
+ /* use realloc only if both free and malloc are used */
+ global_hooks.reallocate = NULL;
+ if ((global_hooks.allocate == malloc) && (global_hooks.deallocate == free))
+ {
+ global_hooks.reallocate = realloc;
+ }
+}
+
+/* Internal constructor. */
+static cJSON *cJSON_New_Item(const internal_hooks * const hooks)
+{
+ cJSON* node = (cJSON*)hooks->allocate(sizeof(cJSON));
+ if (node)
+ {
+ memset(node, '\0', sizeof(cJSON));
+ }
+
+ return node;
+}
+
+/* Delete a cJSON structure. */
+CJSON_PUBLIC(void) cJSON_Delete(cJSON *item)
+{
+ cJSON *next = NULL;
+ while (item != NULL)
+ {
+ next = item->next;
+ if (!(item->type & cJSON_IsReference) && (item->child != NULL))
+ {
+ cJSON_Delete(item->child);
+ }
+ if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL))
+ {
+ global_hooks.deallocate(item->valuestring);
+ }
+ if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))
+ {
+ global_hooks.deallocate(item->string);
+ }
+ global_hooks.deallocate(item);
+ item = next;
+ }
+}
+
+/* get the decimal point character of the current locale */
+static unsigned char get_decimal_point(void)
+{
+#ifdef ENABLE_LOCALES
+ struct lconv *lconv = localeconv();
+ return (unsigned char) lconv->decimal_point[0];
+#else
+ return '.';
+#endif
+}
+
+typedef struct
+{
+ const unsigned char *content;
+ size_t length;
+ size_t offset;
+ size_t depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */
+ internal_hooks hooks;
+} parse_buffer;
+
+/* check if the given size is left to read in a given parse buffer (starting with 1) */
+#define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length))
+/* check if the buffer can be accessed at the given index (starting with 0) */
+#define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length))
+#define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index))
+/* get a pointer to the buffer at the position */
+#define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset)
+
+/* Parse the input text to generate a number, and populate the result into item. */
+static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_buffer)
+{
+ double number = 0;
+ unsigned char *after_end = NULL;
+ unsigned char number_c_string[64];
+ unsigned char decimal_point = get_decimal_point();
+ size_t i = 0;
+
+ if ((input_buffer == NULL) || (input_buffer->content == NULL))
+ {
+ return false;
+ }
+
+ /* copy the number into a temporary buffer and replace '.' with the decimal point
+ * of the current locale (for strtod)
+ * This also takes care of '\0' not necessarily being available for marking the end of the input */
+ for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++)
+ {
+ switch (buffer_at_offset(input_buffer)[i])
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '+':
+ case '-':
+ case 'e':
+ case 'E':
+ number_c_string[i] = buffer_at_offset(input_buffer)[i];
+ break;
+
+ case '.':
+ number_c_string[i] = decimal_point;
+ break;
+
+ default:
+ goto loop_end;
+ }
+ }
+ loop_end:
+ number_c_string[i] = '\0';
+
+ number = strtod((const char*)number_c_string, (char**)&after_end);
+ if (number_c_string == after_end)
+ {
+ return false; /* parse_error */
+ }
+
+ item->valuedouble = number;
+
+ /* use saturation in case of overflow */
+ if (number >= INT_MAX)
+ {
+ item->valueint = INT_MAX;
+ }
+ else if (number <= (double)INT_MIN)
+ {
+ item->valueint = INT_MIN;
+ }
+ else
+ {
+ item->valueint = (int)number;
+ }
+
+ item->type = cJSON_Number;
+
+ input_buffer->offset += (size_t)(after_end - number_c_string);
+ return true;
+}
+
+/* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */
+CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number)
+{
+ if (number >= INT_MAX)
+ {
+ object->valueint = INT_MAX;
+ }
+ else if (number <= (double)INT_MIN)
+ {
+ object->valueint = INT_MIN;
+ }
+ else
+ {
+ object->valueint = (int)number;
+ }
+
+ return object->valuedouble = number;
+}
+
+CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring)
+{
+ char *copy = NULL;
+ /* if object's type is not cJSON_String or is cJSON_IsReference, it should not set valuestring */
+ if (!(object->type & cJSON_String) || (object->type & cJSON_IsReference))
+ {
+ return NULL;
+ }
+ if (strlen(valuestring) <= strlen(object->valuestring))
+ {
+ strcpy(object->valuestring, valuestring);
+ return object->valuestring;
+ }
+ copy = (char*) cJSON_strdup((const unsigned char*)valuestring, &global_hooks);
+ if (copy == NULL)
+ {
+ return NULL;
+ }
+ if (object->valuestring != NULL)
+ {
+ cJSON_free(object->valuestring);
+ }
+ object->valuestring = copy;
+
+ return copy;
+}
+
+typedef struct
+{
+ unsigned char *buffer;
+ size_t length;
+ size_t offset;
+ size_t depth; /* current nesting depth (for formatted printing) */
+ cJSON_bool noalloc;
+ cJSON_bool format; /* is this print a formatted print */
+ internal_hooks hooks;
+} printbuffer;
+
+/* realloc printbuffer if necessary to have at least "needed" bytes more */
+static unsigned char* ensure(printbuffer * const p, size_t needed)
+{
+ unsigned char *newbuffer = NULL;
+ size_t newsize = 0;
+
+ if ((p == NULL) || (p->buffer == NULL))
+ {
+ return NULL;
+ }
+
+ if ((p->length > 0) && (p->offset >= p->length))
+ {
+ /* make sure that offset is valid */
+ return NULL;
+ }
+
+ if (needed > INT_MAX)
+ {
+ /* sizes bigger than INT_MAX are currently not supported */
+ return NULL;
+ }
+
+ needed += p->offset + 1;
+ if (needed <= p->length)
+ {
+ return p->buffer + p->offset;
+ }
+
+ if (p->noalloc) {
+ return NULL;
+ }
+
+ /* calculate new buffer size */
+ if (needed > (INT_MAX / 2))
+ {
+ /* overflow of int, use INT_MAX if possible */
+ if (needed <= INT_MAX)
+ {
+ newsize = INT_MAX;
+ }
+ else
+ {
+ return NULL;
+ }
+ }
+ else
+ {
+ newsize = needed * 2;
+ }
+
+ if (p->hooks.reallocate != NULL)
+ {
+ /* reallocate with realloc if available */
+ newbuffer = (unsigned char*)p->hooks.reallocate(p->buffer, newsize);
+ if (newbuffer == NULL)
+ {
+ p->hooks.deallocate(p->buffer);
+ p->length = 0;
+ p->buffer = NULL;
+
+ return NULL;
+ }
+ }
+ else
+ {
+ /* otherwise reallocate manually */
+ newbuffer = (unsigned char*)p->hooks.allocate(newsize);
+ if (!newbuffer)
+ {
+ p->hooks.deallocate(p->buffer);
+ p->length = 0;
+ p->buffer = NULL;
+
+ return NULL;
+ }
+
+ memcpy(newbuffer, p->buffer, p->offset + 1);
+ p->hooks.deallocate(p->buffer);
+ }
+ p->length = newsize;
+ p->buffer = newbuffer;
+
+ return newbuffer + p->offset;
+}
+
+/* calculate the new length of the string in a printbuffer and update the offset */
+static void update_offset(printbuffer * const buffer)
+{
+ const unsigned char *buffer_pointer = NULL;
+ if ((buffer == NULL) || (buffer->buffer == NULL))
+ {
+ return;
+ }
+ buffer_pointer = buffer->buffer + buffer->offset;
+
+ buffer->offset += strlen((const char*)buffer_pointer);
+}
+
+/* securely comparison of floating-point variables */
+static cJSON_bool compare_double(double a, double b)
+{
+ double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b);
+ return (fabs(a - b) <= maxVal * DBL_EPSILON);
+}
+
+/* Render the number nicely from the given item into a string. */
+static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer)
+{
+ unsigned char *output_pointer = NULL;
+ double d = item->valuedouble;
+ int length = 0;
+ size_t i = 0;
+ unsigned char number_buffer[26] = {0}; /* temporary buffer to print the number into */
+ unsigned char decimal_point = get_decimal_point();
+ double test = 0.0;
+
+ if (output_buffer == NULL)
+ {
+ return false;
+ }
+
+ /* This checks for NaN and Infinity */
+ if (isnan(d) || isinf(d))
+ {
+ length = sprintf((char*)number_buffer, "null");
+ }
+ else
+ {
+ /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */
+ length = sprintf((char*)number_buffer, "%1.15g", d);
+
+ /* Check whether the original double can be recovered */
+ if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || !compare_double((double)test, d))
+ {
+ /* If not, print with 17 decimal places of precision */
+ length = sprintf((char*)number_buffer, "%1.17g", d);
+ }
+ }
+
+ /* sprintf failed or buffer overrun occurred */
+ if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1)))
+ {
+ return false;
+ }
+
+ /* reserve appropriate space in the output */
+ output_pointer = ensure(output_buffer, (size_t)length + sizeof(""));
+ if (output_pointer == NULL)
+ {
+ return false;
+ }
+
+ /* copy the printed number to the output and replace locale
+ * dependent decimal point with '.' */
+ for (i = 0; i < ((size_t)length); i++)
+ {
+ if (number_buffer[i] == decimal_point)
+ {
+ output_pointer[i] = '.';
+ continue;
+ }
+
+ output_pointer[i] = number_buffer[i];
+ }
+ output_pointer[i] = '\0';
+
+ output_buffer->offset += (size_t)length;
+
+ return true;
+}
+
+/* parse 4 digit hexadecimal number */
+static unsigned parse_hex4(const unsigned char * const input)
+{
+ unsigned int h = 0;
+ size_t i = 0;
+
+ for (i = 0; i < 4; i++)
+ {
+ /* parse digit */
+ if ((input[i] >= '0') && (input[i] <= '9'))
+ {
+ h += (unsigned int) input[i] - '0';
+ }
+ else if ((input[i] >= 'A') && (input[i] <= 'F'))
+ {
+ h += (unsigned int) 10 + input[i] - 'A';
+ }
+ else if ((input[i] >= 'a') && (input[i] <= 'f'))
+ {
+ h += (unsigned int) 10 + input[i] - 'a';
+ }
+ else /* invalid */
+ {
+ return 0;
+ }
+
+ if (i < 3)
+ {
+ /* shift left to make place for the next nibble */
+ h = h << 4;
+ }
+ }
+
+ return h;
+}
+
+/* converts a UTF-16 literal to UTF-8
+ * A literal can be one or two sequences of the form \uXXXX */
+static unsigned char utf16_literal_to_utf8(const unsigned char * const input_pointer, const unsigned char * const input_end, unsigned char **output_pointer)
+{
+ long unsigned int codepoint = 0;
+ unsigned int first_code = 0;
+ const unsigned char *first_sequence = input_pointer;
+ unsigned char utf8_length = 0;
+ unsigned char utf8_position = 0;
+ unsigned char sequence_length = 0;
+ unsigned char first_byte_mark = 0;
+
+ if ((input_end - first_sequence) < 6)
+ {
+ /* input ends unexpectedly */
+ goto fail;
+ }
+
+ /* get the first utf16 sequence */
+ first_code = parse_hex4(first_sequence + 2);
+
+ /* check that the code is valid */
+ if (((first_code >= 0xDC00) && (first_code <= 0xDFFF)))
+ {
+ goto fail;
+ }
+
+ /* UTF16 surrogate pair */
+ if ((first_code >= 0xD800) && (first_code <= 0xDBFF))
+ {
+ const unsigned char *second_sequence = first_sequence + 6;
+ unsigned int second_code = 0;
+ sequence_length = 12; /* \uXXXX\uXXXX */
+
+ if ((input_end - second_sequence) < 6)
+ {
+ /* input ends unexpectedly */
+ goto fail;
+ }
+
+ if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u'))
+ {
+ /* missing second half of the surrogate pair */
+ goto fail;
+ }
+
+ /* get the second utf16 sequence */
+ second_code = parse_hex4(second_sequence + 2);
+ /* check that the code is valid */
+ if ((second_code < 0xDC00) || (second_code > 0xDFFF))
+ {
+ /* invalid second half of the surrogate pair */
+ goto fail;
+ }
+
+
+ /* calculate the unicode codepoint from the surrogate pair */
+ codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF));
+ }
+ else
+ {
+ sequence_length = 6; /* \uXXXX */
+ codepoint = first_code;
+ }
+
+ /* encode as UTF-8
+ * takes at maximum 4 bytes to encode:
+ * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
+ if (codepoint < 0x80)
+ {
+ /* normal ascii, encoding 0xxxxxxx */
+ utf8_length = 1;
+ }
+ else if (codepoint < 0x800)
+ {
+ /* two bytes, encoding 110xxxxx 10xxxxxx */
+ utf8_length = 2;
+ first_byte_mark = 0xC0; /* 11000000 */
+ }
+ else if (codepoint < 0x10000)
+ {
+ /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */
+ utf8_length = 3;
+ first_byte_mark = 0xE0; /* 11100000 */
+ }
+ else if (codepoint <= 0x10FFFF)
+ {
+ /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */
+ utf8_length = 4;
+ first_byte_mark = 0xF0; /* 11110000 */
+ }
+ else
+ {
+ /* invalid unicode codepoint */
+ goto fail;
+ }
+
+ /* encode as utf8 */
+ for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--)
+ {
+ /* 10xxxxxx */
+ (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF);
+ codepoint >>= 6;
+ }
+ /* encode first byte */
+ if (utf8_length > 1)
+ {
+ (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF);
+ }
+ else
+ {
+ (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F);
+ }
+
+ *output_pointer += utf8_length;
+
+ return sequence_length;
+
+ fail:
+ return 0;
+}
+
+/* Parse the input text into an unescaped cinput, and populate item. */
+static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_buffer)
+{
+ const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1;
+ const unsigned char *input_end = buffer_at_offset(input_buffer) + 1;
+ unsigned char *output_pointer = NULL;
+ unsigned char *output = NULL;
+
+ /* not a string */
+ if (buffer_at_offset(input_buffer)[0] != '\"')
+ {
+ goto fail;
+ }
+
+ {
+ /* calculate approximate size of the output (overestimate) */
+ size_t allocation_length = 0;
+ size_t skipped_bytes = 0;
+ while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"'))
+ {
+ /* is escape sequence */
+ if (input_end[0] == '\\')
+ {
+ if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length)
+ {
+ /* prevent buffer overflow when last input character is a backslash */
+ goto fail;
+ }
+ skipped_bytes++;
+ input_end++;
+ }
+ input_end++;
+ }
+ if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"'))
+ {
+ goto fail; /* string ended unexpectedly */
+ }
+
+ /* This is at most how much we need for the output */
+ allocation_length = (size_t) (input_end - buffer_at_offset(input_buffer)) - skipped_bytes;
+ output = (unsigned char*)input_buffer->hooks.allocate(allocation_length + sizeof(""));
+ if (output == NULL)
+ {
+ goto fail; /* allocation failure */
+ }
+ }
+
+ output_pointer = output;
+ /* loop through the string literal */
+ while (input_pointer < input_end)
+ {
+ if (*input_pointer != '\\')
+ {
+ *output_pointer++ = *input_pointer++;
+ }
+ /* escape sequence */
+ else
+ {
+ unsigned char sequence_length = 2;
+ if ((input_end - input_pointer) < 1)
+ {
+ goto fail;
+ }
+
+ switch (input_pointer[1])
+ {
+ case 'b':
+ *output_pointer++ = '\b';
+ break;
+ case 'f':
+ *output_pointer++ = '\f';
+ break;
+ case 'n':
+ *output_pointer++ = '\n';
+ break;
+ case 'r':
+ *output_pointer++ = '\r';
+ break;
+ case 't':
+ *output_pointer++ = '\t';
+ break;
+ case '\"':
+ case '\\':
+ case '/':
+ *output_pointer++ = input_pointer[1];
+ break;
+
+ /* UTF-16 literal */
+ case 'u':
+ sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer);
+ if (sequence_length == 0)
+ {
+ /* failed to convert UTF16-literal to UTF-8 */
+ goto fail;
+ }
+ break;
+
+ default:
+ goto fail;
+ }
+ input_pointer += sequence_length;
+ }
+ }
+
+ /* zero terminate the output */
+ *output_pointer = '\0';
+
+ item->type = cJSON_String;
+ item->valuestring = (char*)output;
+
+ input_buffer->offset = (size_t) (input_end - input_buffer->content);
+ input_buffer->offset++;
+
+ return true;
+
+ fail:
+ if (output != NULL)
+ {
+ input_buffer->hooks.deallocate(output);
+ }
+
+ if (input_pointer != NULL)
+ {
+ input_buffer->offset = (size_t)(input_pointer - input_buffer->content);
+ }
+
+ return false;
+}
+
+/* Render the cstring provided to an escaped version that can be printed. */
+static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer)
+{
+ const unsigned char *input_pointer = NULL;
+ unsigned char *output = NULL;
+ unsigned char *output_pointer = NULL;
+ size_t output_length = 0;
+ /* numbers of additional characters needed for escaping */
+ size_t escape_characters = 0;
+
+ if (output_buffer == NULL)
+ {
+ return false;
+ }
+
+ /* empty string */
+ if (input == NULL)
+ {
+ output = ensure(output_buffer, sizeof("\"\""));
+ if (output == NULL)
+ {
+ return false;
+ }
+ strcpy((char*)output, "\"\"");
+
+ return true;
+ }
+
+ /* set "flag" to 1 if something needs to be escaped */
+ for (input_pointer = input; *input_pointer; input_pointer++)
+ {
+ switch (*input_pointer)
+ {
+ case '\"':
+ case '\\':
+ case '\b':
+ case '\f':
+ case '\n':
+ case '\r':
+ case '\t':
+ /* one character escape sequence */
+ escape_characters++;
+ break;
+ default:
+ if (*input_pointer < 32)
+ {
+ /* UTF-16 escape sequence uXXXX */
+ escape_characters += 5;
+ }
+ break;
+ }
+ }
+ output_length = (size_t)(input_pointer - input) + escape_characters;
+
+ output = ensure(output_buffer, output_length + sizeof("\"\""));
+ if (output == NULL)
+ {
+ return false;
+ }
+
+ /* no characters have to be escaped */
+ if (escape_characters == 0)
+ {
+ output[0] = '\"';
+ memcpy(output + 1, input, output_length);
+ output[output_length + 1] = '\"';
+ output[output_length + 2] = '\0';
+
+ return true;
+ }
+
+ output[0] = '\"';
+ output_pointer = output + 1;
+ /* copy the string */
+ for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++)
+ {
+ if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\'))
+ {
+ /* normal character, copy */
+ *output_pointer = *input_pointer;
+ }
+ else
+ {
+ /* character needs to be escaped */
+ *output_pointer++ = '\\';
+ switch (*input_pointer)
+ {
+ case '\\':
+ *output_pointer = '\\';
+ break;
+ case '\"':
+ *output_pointer = '\"';
+ break;
+ case '\b':
+ *output_pointer = 'b';
+ break;
+ case '\f':
+ *output_pointer = 'f';
+ break;
+ case '\n':
+ *output_pointer = 'n';
+ break;
+ case '\r':
+ *output_pointer = 'r';
+ break;
+ case '\t':
+ *output_pointer = 't';
+ break;
+ default:
+ /* escape and print as unicode codepoint */
+ sprintf((char*)output_pointer, "u%04x", *input_pointer);
+ output_pointer += 4;
+ break;
+ }
+ }
+ }
+ output[output_length + 1] = '\"';
+ output[output_length + 2] = '\0';
+
+ return true;
+}
+
+/* Invoke print_string_ptr (which is useful) on an item. */
+static cJSON_bool print_string(const cJSON * const item, printbuffer * const p)
+{
+ return print_string_ptr((unsigned char*)item->valuestring, p);
+}
+
+/* Predeclare these prototypes. */
+static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer);
+static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer);
+static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer);
+static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer);
+static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer);
+static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer);
+
+/* Utility to jump whitespace and cr/lf */
+static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer)
+{
+ if ((buffer == NULL) || (buffer->content == NULL))
+ {
+ return NULL;
+ }
+
+ if (cannot_access_at_index(buffer, 0))
+ {
+ return buffer;
+ }
+
+ while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32))
+ {
+ buffer->offset++;
+ }
+
+ if (buffer->offset == buffer->length)
+ {
+ buffer->offset--;
+ }
+
+ return buffer;
+}
+
+/* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */
+static parse_buffer *skip_utf8_bom(parse_buffer * const buffer)
+{
+ if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0))
+ {
+ return NULL;
+ }
+
+ if (can_access_at_index(buffer, 4) && (strncmp((const char*)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0))
+ {
+ buffer->offset += 3;
+ }
+
+ return buffer;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated)
+{
+ size_t buffer_length;
+
+ if (NULL == value)
+ {
+ return NULL;
+ }
+
+ /* Adding null character size due to require_null_terminated. */
+ buffer_length = strlen(value) + sizeof("");
+
+ return cJSON_ParseWithLengthOpts(value, buffer_length, return_parse_end, require_null_terminated);
+}
+
+/* Parse an object - create a new root, and populate. */
+CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated)
+{
+ parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } };
+ cJSON *item = NULL;
+
+ /* reset error position */
+ global_error.json = NULL;
+ global_error.position = 0;
+
+ if (value == NULL || 0 == buffer_length)
+ {
+ goto fail;
+ }
+
+ buffer.content = (const unsigned char*)value;
+ buffer.length = buffer_length;
+ buffer.offset = 0;
+ buffer.hooks = global_hooks;
+
+ item = cJSON_New_Item(&global_hooks);
+ if (item == NULL) /* memory fail */
+ {
+ goto fail;
+ }
+
+ if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer))))
+ {
+ /* parse failure. ep is set. */
+ goto fail;
+ }
+
+ /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
+ if (require_null_terminated)
+ {
+ buffer_skip_whitespace(&buffer);
+ if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0')
+ {
+ goto fail;
+ }
+ }
+ if (return_parse_end)
+ {
+ *return_parse_end = (const char*)buffer_at_offset(&buffer);
+ }
+
+ return item;
+
+ fail:
+ if (item != NULL)
+ {
+ cJSON_Delete(item);
+ }
+
+ if (value != NULL)
+ {
+ error local_error;
+ local_error.json = (const unsigned char*)value;
+ local_error.position = 0;
+
+ if (buffer.offset < buffer.length)
+ {
+ local_error.position = buffer.offset;
+ }
+ else if (buffer.length > 0)
+ {
+ local_error.position = buffer.length - 1;
+ }
+
+ if (return_parse_end != NULL)
+ {
+ *return_parse_end = (const char*)local_error.json + local_error.position;
+ }
+
+ global_error = local_error;
+ }
+
+ return NULL;
+}
+
+/* Default options for cJSON_Parse */
+CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value)
+{
+ return cJSON_ParseWithOpts(value, 0, 0);
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length)
+{
+ return cJSON_ParseWithLengthOpts(value, buffer_length, 0, 0);
+}
+
+#define cjson_min(a, b) (((a) < (b)) ? (a) : (b))
+
+static unsigned char *print(const cJSON * const item, cJSON_bool format, const internal_hooks * const hooks)
+{
+ static const size_t default_buffer_size = 256;
+ printbuffer buffer[1];
+ unsigned char *printed = NULL;
+
+ memset(buffer, 0, sizeof(buffer));
+
+ /* create buffer */
+ buffer->buffer = (unsigned char*) hooks->allocate(default_buffer_size);
+ buffer->length = default_buffer_size;
+ buffer->format = format;
+ buffer->hooks = *hooks;
+ if (buffer->buffer == NULL)
+ {
+ goto fail;
+ }
+
+ /* print the value */
+ if (!print_value(item, buffer))
+ {
+ goto fail;
+ }
+ update_offset(buffer);
+
+ /* check if reallocate is available */
+ if (hooks->reallocate != NULL)
+ {
+ printed = (unsigned char*) hooks->reallocate(buffer->buffer, buffer->offset + 1);
+ if (printed == NULL) {
+ goto fail;
+ }
+ buffer->buffer = NULL;
+ }
+ else /* otherwise copy the JSON over to a new buffer */
+ {
+ printed = (unsigned char*) hooks->allocate(buffer->offset + 1);
+ if (printed == NULL)
+ {
+ goto fail;
+ }
+ memcpy(printed, buffer->buffer, cjson_min(buffer->length, buffer->offset + 1));
+ printed[buffer->offset] = '\0'; /* just to be sure */
+
+ /* free the buffer */
+ hooks->deallocate(buffer->buffer);
+ }
+
+ return printed;
+
+ fail:
+ if (buffer->buffer != NULL)
+ {
+ hooks->deallocate(buffer->buffer);
+ }
+
+ if (printed != NULL)
+ {
+ hooks->deallocate(printed);
+ }
+
+ return NULL;
+}
+
+/* Render a cJSON item/entity/structure to text. */
+CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item)
+{
+ return (char*)print(item, true, &global_hooks);
+}
+
+CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item)
+{
+ return (char*)print(item, false, &global_hooks);
+}
+
+CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt)
+{
+ printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };
+
+ if (prebuffer < 0)
+ {
+ return NULL;
+ }
+
+ p.buffer = (unsigned char*)global_hooks.allocate((size_t)prebuffer);
+ if (!p.buffer)
+ {
+ return NULL;
+ }
+
+ p.length = (size_t)prebuffer;
+ p.offset = 0;
+ p.noalloc = false;
+ p.format = fmt;
+ p.hooks = global_hooks;
+
+ if (!print_value(item, &p))
+ {
+ global_hooks.deallocate(p.buffer);
+ return NULL;
+ }
+
+ return (char*)p.buffer;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format)
+{
+ printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };
+
+ if ((length < 0) || (buffer == NULL))
+ {
+ return false;
+ }
+
+ p.buffer = (unsigned char*)buffer;
+ p.length = (size_t)length;
+ p.offset = 0;
+ p.noalloc = true;
+ p.format = format;
+ p.hooks = global_hooks;
+
+ return print_value(item, &p);
+}
+
+/* Parser core - when encountering text, process appropriately. */
+static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer)
+{
+ if ((input_buffer == NULL) || (input_buffer->content == NULL))
+ {
+ return false; /* no input */
+ }
+
+ /* parse the different types of values */
+ /* null */
+ if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "null", 4) == 0))
+ {
+ item->type = cJSON_NULL;
+ input_buffer->offset += 4;
+ return true;
+ }
+ /* false */
+ if (can_read(input_buffer, 5) && (strncmp((const char*)buffer_at_offset(input_buffer), "false", 5) == 0))
+ {
+ item->type = cJSON_False;
+ input_buffer->offset += 5;
+ return true;
+ }
+ /* true */
+ if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "true", 4) == 0))
+ {
+ item->type = cJSON_True;
+ item->valueint = 1;
+ input_buffer->offset += 4;
+ return true;
+ }
+ /* string */
+ if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"'))
+ {
+ return parse_string(item, input_buffer);
+ }
+ /* number */
+ if (can_access_at_index(input_buffer, 0) && ((buffer_at_offset(input_buffer)[0] == '-') || ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9'))))
+ {
+ return parse_number(item, input_buffer);
+ }
+ /* array */
+ if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '['))
+ {
+ return parse_array(item, input_buffer);
+ }
+ /* object */
+ if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{'))
+ {
+ return parse_object(item, input_buffer);
+ }
+
+ return false;
+}
+
+/* Render a value to text. */
+static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer)
+{
+ unsigned char *output = NULL;
+
+ if ((item == NULL) || (output_buffer == NULL))
+ {
+ return false;
+ }
+
+ switch ((item->type) & 0xFF)
+ {
+ case cJSON_NULL:
+ output = ensure(output_buffer, 5);
+ if (output == NULL)
+ {
+ return false;
+ }
+ strcpy((char*)output, "null");
+ return true;
+
+ case cJSON_False:
+ output = ensure(output_buffer, 6);
+ if (output == NULL)
+ {
+ return false;
+ }
+ strcpy((char*)output, "false");
+ return true;
+
+ case cJSON_True:
+ output = ensure(output_buffer, 5);
+ if (output == NULL)
+ {
+ return false;
+ }
+ strcpy((char*)output, "true");
+ return true;
+
+ case cJSON_Number:
+ return print_number(item, output_buffer);
+
+ case cJSON_Raw:
+ {
+ size_t raw_length = 0;
+ if (item->valuestring == NULL)
+ {
+ return false;
+ }
+
+ raw_length = strlen(item->valuestring) + sizeof("");
+ output = ensure(output_buffer, raw_length);
+ if (output == NULL)
+ {
+ return false;
+ }
+ memcpy(output, item->valuestring, raw_length);
+ return true;
+ }
+
+ case cJSON_String:
+ return print_string(item, output_buffer);
+
+ case cJSON_Array:
+ return print_array(item, output_buffer);
+
+ case cJSON_Object:
+ return print_object(item, output_buffer);
+
+ default:
+ return false;
+ }
+}
+
+/* Build an array from input text. */
+static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer)
+{
+ cJSON *head = NULL; /* head of the linked list */
+ cJSON *current_item = NULL;
+
+ if (input_buffer->depth >= CJSON_NESTING_LIMIT)
+ {
+ return false; /* to deeply nested */
+ }
+ input_buffer->depth++;
+
+ if (buffer_at_offset(input_buffer)[0] != '[')
+ {
+ /* not an array */
+ goto fail;
+ }
+
+ input_buffer->offset++;
+ buffer_skip_whitespace(input_buffer);
+ if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']'))
+ {
+ /* empty array */
+ goto success;
+ }
+
+ /* check if we skipped to the end of the buffer */
+ if (cannot_access_at_index(input_buffer, 0))
+ {
+ input_buffer->offset--;
+ goto fail;
+ }
+
+ /* step back to character in front of the first element */
+ input_buffer->offset--;
+ /* loop through the comma separated array elements */
+ do
+ {
+ /* allocate next item */
+ cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks));
+ if (new_item == NULL)
+ {
+ goto fail; /* allocation failure */
+ }
+
+ /* attach next item to list */
+ if (head == NULL)
+ {
+ /* start the linked list */
+ current_item = head = new_item;
+ }
+ else
+ {
+ /* add to the end and advance */
+ current_item->next = new_item;
+ new_item->prev = current_item;
+ current_item = new_item;
+ }
+
+ /* parse next value */
+ input_buffer->offset++;
+ buffer_skip_whitespace(input_buffer);
+ if (!parse_value(current_item, input_buffer))
+ {
+ goto fail; /* failed to parse value */
+ }
+ buffer_skip_whitespace(input_buffer);
+ }
+ while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
+
+ if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']')
+ {
+ goto fail; /* expected end of array */
+ }
+
+ success:
+ input_buffer->depth--;
+
+ if (head != NULL) {
+ head->prev = current_item;
+ }
+
+ item->type = cJSON_Array;
+ item->child = head;
+
+ input_buffer->offset++;
+
+ return true;
+
+ fail:
+ if (head != NULL)
+ {
+ cJSON_Delete(head);
+ }
+
+ return false;
+}
+
+/* Render an array to text */
+static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer)
+{
+ unsigned char *output_pointer = NULL;
+ size_t length = 0;
+ cJSON *current_element = item->child;
+
+ if (output_buffer == NULL)
+ {
+ return false;
+ }
+
+ /* Compose the output array. */
+ /* opening square bracket */
+ output_pointer = ensure(output_buffer, 1);
+ if (output_pointer == NULL)
+ {
+ return false;
+ }
+
+ *output_pointer = '[';
+ output_buffer->offset++;
+ output_buffer->depth++;
+
+ while (current_element != NULL)
+ {
+ if (!print_value(current_element, output_buffer))
+ {
+ return false;
+ }
+ update_offset(output_buffer);
+ if (current_element->next)
+ {
+ length = (size_t) (output_buffer->format ? 2 : 1);
+ output_pointer = ensure(output_buffer, length + 1);
+ if (output_pointer == NULL)
+ {
+ return false;
+ }
+ *output_pointer++ = ',';
+ if(output_buffer->format)
+ {
+ *output_pointer++ = ' ';
+ }
+ *output_pointer = '\0';
+ output_buffer->offset += length;
+ }
+ current_element = current_element->next;
+ }
+
+ output_pointer = ensure(output_buffer, 2);
+ if (output_pointer == NULL)
+ {
+ return false;
+ }
+ *output_pointer++ = ']';
+ *output_pointer = '\0';
+ output_buffer->depth--;
+
+ return true;
+}
+
+/* Build an object from the text. */
+static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer)
+{
+ cJSON *head = NULL; /* linked list head */
+ cJSON *current_item = NULL;
+
+ if (input_buffer->depth >= CJSON_NESTING_LIMIT)
+ {
+ return false; /* to deeply nested */
+ }
+ input_buffer->depth++;
+
+ if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{'))
+ {
+ goto fail; /* not an object */
+ }
+
+ input_buffer->offset++;
+ buffer_skip_whitespace(input_buffer);
+ if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}'))
+ {
+ goto success; /* empty object */
+ }
+
+ /* check if we skipped to the end of the buffer */
+ if (cannot_access_at_index(input_buffer, 0))
+ {
+ input_buffer->offset--;
+ goto fail;
+ }
+
+ /* step back to character in front of the first element */
+ input_buffer->offset--;
+ /* loop through the comma separated array elements */
+ do
+ {
+ /* allocate next item */
+ cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks));
+ if (new_item == NULL)
+ {
+ goto fail; /* allocation failure */
+ }
+
+ /* attach next item to list */
+ if (head == NULL)
+ {
+ /* start the linked list */
+ current_item = head = new_item;
+ }
+ else
+ {
+ /* add to the end and advance */
+ current_item->next = new_item;
+ new_item->prev = current_item;
+ current_item = new_item;
+ }
+
+ /* parse the name of the child */
+ input_buffer->offset++;
+ buffer_skip_whitespace(input_buffer);
+ if (!parse_string(current_item, input_buffer))
+ {
+ goto fail; /* failed to parse name */
+ }
+ buffer_skip_whitespace(input_buffer);
+
+ /* swap valuestring and string, because we parsed the name */
+ current_item->string = current_item->valuestring;
+ current_item->valuestring = NULL;
+
+ if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':'))
+ {
+ goto fail; /* invalid object */
+ }
+
+ /* parse the value */
+ input_buffer->offset++;
+ buffer_skip_whitespace(input_buffer);
+ if (!parse_value(current_item, input_buffer))
+ {
+ goto fail; /* failed to parse value */
+ }
+ buffer_skip_whitespace(input_buffer);
+ }
+ while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
+
+ if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}'))
+ {
+ goto fail; /* expected end of object */
+ }
+
+ success:
+ input_buffer->depth--;
+
+ if (head != NULL) {
+ head->prev = current_item;
+ }
+
+ item->type = cJSON_Object;
+ item->child = head;
+
+ input_buffer->offset++;
+ return true;
+
+ fail:
+ if (head != NULL)
+ {
+ cJSON_Delete(head);
+ }
+
+ return false;
+}
+
+/* Render an object to text. */
+static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer)
+{
+ unsigned char *output_pointer = NULL;
+ size_t length = 0;
+ cJSON *current_item = item->child;
+
+ if (output_buffer == NULL)
+ {
+ return false;
+ }
+
+ /* Compose the output: */
+ length = (size_t) (output_buffer->format ? 2 : 1); /* fmt: {\n */
+ output_pointer = ensure(output_buffer, length + 1);
+ if (output_pointer == NULL)
+ {
+ return false;
+ }
+
+ *output_pointer++ = '{';
+ output_buffer->depth++;
+ if (output_buffer->format)
+ {
+ *output_pointer++ = '\n';
+ }
+ output_buffer->offset += length;
+
+ while (current_item)
+ {
+ if (output_buffer->format)
+ {
+ size_t i;
+ output_pointer = ensure(output_buffer, output_buffer->depth);
+ if (output_pointer == NULL)
+ {
+ return false;
+ }
+ for (i = 0; i < output_buffer->depth; i++)
+ {
+ *output_pointer++ = '\t';
+ }
+ output_buffer->offset += output_buffer->depth;
+ }
+
+ /* print key */
+ if (!print_string_ptr((unsigned char*)current_item->string, output_buffer))
+ {
+ return false;
+ }
+ update_offset(output_buffer);
+
+ length = (size_t) (output_buffer->format ? 2 : 1);
+ output_pointer = ensure(output_buffer, length);
+ if (output_pointer == NULL)
+ {
+ return false;
+ }
+ *output_pointer++ = ':';
+ if (output_buffer->format)
+ {
+ *output_pointer++ = '\t';
+ }
+ output_buffer->offset += length;
+
+ /* print value */
+ if (!print_value(current_item, output_buffer))
+ {
+ return false;
+ }
+ update_offset(output_buffer);
+
+ /* print comma if not last */
+ length = ((size_t)(output_buffer->format ? 1 : 0) + (size_t)(current_item->next ? 1 : 0));
+ output_pointer = ensure(output_buffer, length + 1);
+ if (output_pointer == NULL)
+ {
+ return false;
+ }
+ if (current_item->next)
+ {
+ *output_pointer++ = ',';
+ }
+
+ if (output_buffer->format)
+ {
+ *output_pointer++ = '\n';
+ }
+ *output_pointer = '\0';
+ output_buffer->offset += length;
+
+ current_item = current_item->next;
+ }
+
+ output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2);
+ if (output_pointer == NULL)
+ {
+ return false;
+ }
+ if (output_buffer->format)
+ {
+ size_t i;
+ for (i = 0; i < (output_buffer->depth - 1); i++)
+ {
+ *output_pointer++ = '\t';
+ }
+ }
+ *output_pointer++ = '}';
+ *output_pointer = '\0';
+ output_buffer->depth--;
+
+ return true;
+}
+
+/* Get Array size/item / object item. */
+CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array)
+{
+ cJSON *child = NULL;
+ size_t size = 0;
+
+ if (array == NULL)
+ {
+ return 0;
+ }
+
+ child = array->child;
+
+ while(child != NULL)
+ {
+ size++;
+ child = child->next;
+ }
+
+ /* FIXME: Can overflow here. Cannot be fixed without breaking the API */
+
+ return (int)size;
+}
+
+static cJSON* get_array_item(const cJSON *array, size_t index)
+{
+ cJSON *current_child = NULL;
+
+ if (array == NULL)
+ {
+ return NULL;
+ }
+
+ current_child = array->child;
+ while ((current_child != NULL) && (index > 0))
+ {
+ index--;
+ current_child = current_child->next;
+ }
+
+ return current_child;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index)
+{
+ if (index < 0)
+ {
+ return NULL;
+ }
+
+ return get_array_item(array, (size_t)index);
+}
+
+static cJSON *get_object_item(const cJSON * const object, const char * const name, const cJSON_bool case_sensitive)
+{
+ cJSON *current_element = NULL;
+
+ if ((object == NULL) || (name == NULL))
+ {
+ return NULL;
+ }
+
+ current_element = object->child;
+ if (case_sensitive)
+ {
+ while ((current_element != NULL) && (current_element->string != NULL) && (strcmp(name, current_element->string) != 0))
+ {
+ current_element = current_element->next;
+ }
+ }
+ else
+ {
+ while ((current_element != NULL) && (case_insensitive_strcmp((const unsigned char*)name, (const unsigned char*)(current_element->string)) != 0))
+ {
+ current_element = current_element->next;
+ }
+ }
+
+ if ((current_element == NULL) || (current_element->string == NULL)) {
+ return NULL;
+ }
+
+ return current_element;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string)
+{
+ return get_object_item(object, string, false);
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string)
+{
+ return get_object_item(object, string, true);
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string)
+{
+ return cJSON_GetObjectItem(object, string) ? 1 : 0;
+}
+
+/* Utility for array list handling. */
+static void suffix_object(cJSON *prev, cJSON *item)
+{
+ prev->next = item;
+ item->prev = prev;
+}
+
+/* Utility for handling references. */
+static cJSON *create_reference(const cJSON *item, const internal_hooks * const hooks)
+{
+ cJSON *reference = NULL;
+ if (item == NULL)
+ {
+ return NULL;
+ }
+
+ reference = cJSON_New_Item(hooks);
+ if (reference == NULL)
+ {
+ return NULL;
+ }
+
+ memcpy(reference, item, sizeof(cJSON));
+ reference->string = NULL;
+ reference->type |= cJSON_IsReference;
+ reference->next = reference->prev = NULL;
+ return reference;
+}
+
+static cJSON_bool add_item_to_array(cJSON *array, cJSON *item)
+{
+ cJSON *child = NULL;
+
+ if ((item == NULL) || (array == NULL) || (array == item))
+ {
+ return false;
+ }
+
+ child = array->child;
+ /*
+ * To find the last item in array quickly, we use prev in array
+ */
+ if (child == NULL)
+ {
+ /* list is empty, start new one */
+ array->child = item;
+ item->prev = item;
+ item->next = NULL;
+ }
+ else
+ {
+ /* append to the end */
+ if (child->prev)
+ {
+ suffix_object(child->prev, item);
+ array->child->prev = item;
+ }
+ }
+
+ return true;
+}
+
+/* Add item to array/object. */
+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item)
+{
+ return add_item_to_array(array, item);
+}
+
+#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
+#pragma GCC diagnostic push
+#endif
+#ifdef __GNUC__
+#pragma GCC diagnostic ignored "-Wcast-qual"
+#endif
+/* helper function to cast away const */
+static void* cast_away_const(const void* string)
+{
+ return (void*)string;
+}
+#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
+#pragma GCC diagnostic pop
+#endif
+
+
+static cJSON_bool add_item_to_object(cJSON * const object, const char * const string, cJSON * const item, const internal_hooks * const hooks, const cJSON_bool constant_key)
+{
+ char *new_key = NULL;
+ int new_type = cJSON_Invalid;
+
+ if ((object == NULL) || (string == NULL) || (item == NULL) || (object == item))
+ {
+ return false;
+ }
+
+ if (constant_key)
+ {
+ new_key = (char*)cast_away_const(string);
+ new_type = item->type | cJSON_StringIsConst;
+ }
+ else
+ {
+ new_key = (char*)cJSON_strdup((const unsigned char*)string, hooks);
+ if (new_key == NULL)
+ {
+ return false;
+ }
+
+ new_type = item->type & ~cJSON_StringIsConst;
+ }
+
+ if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))
+ {
+ hooks->deallocate(item->string);
+ }
+
+ item->string = new_key;
+ item->type = new_type;
+
+ return add_item_to_array(object, item);
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item)
+{
+ return add_item_to_object(object, string, item, &global_hooks, false);
+}
+
+/* Add an item to an object with constant string as key */
+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item)
+{
+ return add_item_to_object(object, string, item, &global_hooks, true);
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item)
+{
+ if (array == NULL)
+ {
+ return false;
+ }
+
+ return add_item_to_array(array, create_reference(item, &global_hooks));
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item)
+{
+ if ((object == NULL) || (string == NULL))
+ {
+ return false;
+ }
+
+ return add_item_to_object(object, string, create_reference(item, &global_hooks), &global_hooks, false);
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name)
+{
+ cJSON *null = cJSON_CreateNull();
+ if (add_item_to_object(object, name, null, &global_hooks, false))
+ {
+ return null;
+ }
+
+ cJSON_Delete(null);
+ return NULL;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name)
+{
+ cJSON *true_item = cJSON_CreateTrue();
+ if (add_item_to_object(object, name, true_item, &global_hooks, false))
+ {
+ return true_item;
+ }
+
+ cJSON_Delete(true_item);
+ return NULL;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name)
+{
+ cJSON *false_item = cJSON_CreateFalse();
+ if (add_item_to_object(object, name, false_item, &global_hooks, false))
+ {
+ return false_item;
+ }
+
+ cJSON_Delete(false_item);
+ return NULL;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean)
+{
+ cJSON *bool_item = cJSON_CreateBool(boolean);
+ if (add_item_to_object(object, name, bool_item, &global_hooks, false))
+ {
+ return bool_item;
+ }
+
+ cJSON_Delete(bool_item);
+ return NULL;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number)
+{
+ cJSON *number_item = cJSON_CreateNumber(number);
+ if (add_item_to_object(object, name, number_item, &global_hooks, false))
+ {
+ return number_item;
+ }
+
+ cJSON_Delete(number_item);
+ return NULL;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string)
+{
+ cJSON *string_item = cJSON_CreateString(string);
+ if (add_item_to_object(object, name, string_item, &global_hooks, false))
+ {
+ return string_item;
+ }
+
+ cJSON_Delete(string_item);
+ return NULL;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw)
+{
+ cJSON *raw_item = cJSON_CreateRaw(raw);
+ if (add_item_to_object(object, name, raw_item, &global_hooks, false))
+ {
+ return raw_item;
+ }
+
+ cJSON_Delete(raw_item);
+ return NULL;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name)
+{
+ cJSON *object_item = cJSON_CreateObject();
+ if (add_item_to_object(object, name, object_item, &global_hooks, false))
+ {
+ return object_item;
+ }
+
+ cJSON_Delete(object_item);
+ return NULL;
+}
+
+CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name)
+{
+ cJSON *array = cJSON_CreateArray();
+ if (add_item_to_object(object, name, array, &global_hooks, false))
+ {
+ return array;
+ }
+
+ cJSON_Delete(array);
+ return NULL;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item)
+{
+ if ((parent == NULL) || (item == NULL))
+ {
+ return NULL;
+ }
+
+ if (item != parent->child)
+ {
+ /* not the first element */
+ item->prev->next = item->next;
+ }
+ if (item->next != NULL)
+ {
+ /* not the last element */
+ item->next->prev = item->prev;
+ }
+
+ if (item == parent->child)
+ {
+ /* first element */
+ parent->child = item->next;
+ }
+ else if (item->next == NULL)
+ {
+ /* last element */
+ parent->child->prev = item->prev;
+ }
+
+ /* make sure the detached item doesn't point anywhere anymore */
+ item->prev = NULL;
+ item->next = NULL;
+
+ return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which)
+{
+ if (which < 0)
+ {
+ return NULL;
+ }
+
+ return cJSON_DetachItemViaPointer(array, get_array_item(array, (size_t)which));
+}
+
+CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which)
+{
+ cJSON_Delete(cJSON_DetachItemFromArray(array, which));
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string)
+{
+ cJSON *to_detach = cJSON_GetObjectItem(object, string);
+
+ return cJSON_DetachItemViaPointer(object, to_detach);
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string)
+{
+ cJSON *to_detach = cJSON_GetObjectItemCaseSensitive(object, string);
+
+ return cJSON_DetachItemViaPointer(object, to_detach);
+}
+
+CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string)
+{
+ cJSON_Delete(cJSON_DetachItemFromObject(object, string));
+}
+
+CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string)
+{
+ cJSON_Delete(cJSON_DetachItemFromObjectCaseSensitive(object, string));
+}
+
+/* Replace array/object items with new ones. */
+CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem)
+{
+ cJSON *after_inserted = NULL;
+
+ if (which < 0)
+ {
+ return false;
+ }
+
+ after_inserted = get_array_item(array, (size_t)which);
+ if (after_inserted == NULL)
+ {
+ return add_item_to_array(array, newitem);
+ }
+
+ newitem->next = after_inserted;
+ newitem->prev = after_inserted->prev;
+ after_inserted->prev = newitem;
+ if (after_inserted == array->child)
+ {
+ array->child = newitem;
+ }
+ else
+ {
+ newitem->prev->next = newitem;
+ }
+ return true;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement)
+{
+ if ((parent == NULL) || (replacement == NULL) || (item == NULL))
+ {
+ return false;
+ }
+
+ if (replacement == item)
+ {
+ return true;
+ }
+
+ replacement->next = item->next;
+ replacement->prev = item->prev;
+
+ if (replacement->next != NULL)
+ {
+ replacement->next->prev = replacement;
+ }
+ if (parent->child == item)
+ {
+ if (parent->child->prev == parent->child)
+ {
+ replacement->prev = replacement;
+ }
+ parent->child = replacement;
+ }
+ else
+ { /*
+ * To find the last item in array quickly, we use prev in array.
+ * We can't modify the last item's next pointer where this item was the parent's child
+ */
+ if (replacement->prev != NULL)
+ {
+ replacement->prev->next = replacement;
+ }
+ if (replacement->next == NULL)
+ {
+ parent->child->prev = replacement;
+ }
+ }
+
+ item->next = NULL;
+ item->prev = NULL;
+ cJSON_Delete(item);
+
+ return true;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem)
+{
+ if (which < 0)
+ {
+ return false;
+ }
+
+ return cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem);
+}
+
+static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, cJSON_bool case_sensitive)
+{
+ if ((replacement == NULL) || (string == NULL))
+ {
+ return false;
+ }
+
+ /* replace the name in the replacement */
+ if (!(replacement->type & cJSON_StringIsConst) && (replacement->string != NULL))
+ {
+ cJSON_free(replacement->string);
+ }
+ replacement->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks);
+ replacement->type &= ~cJSON_StringIsConst;
+
+ return cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement);
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem)
+{
+ return replace_item_in_object(object, string, newitem, false);
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem)
+{
+ return replace_item_in_object(object, string, newitem, true);
+}
+
+/* Create basic types: */
+CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void)
+{
+ cJSON *item = cJSON_New_Item(&global_hooks);
+ if(item)
+ {
+ item->type = cJSON_NULL;
+ }
+
+ return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void)
+{
+ cJSON *item = cJSON_New_Item(&global_hooks);
+ if(item)
+ {
+ item->type = cJSON_True;
+ }
+
+ return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void)
+{
+ cJSON *item = cJSON_New_Item(&global_hooks);
+ if(item)
+ {
+ item->type = cJSON_False;
+ }
+
+ return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean)
+{
+ cJSON *item = cJSON_New_Item(&global_hooks);
+ if(item)
+ {
+ item->type = boolean ? cJSON_True : cJSON_False;
+ }
+
+ return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num)
+{
+ cJSON *item = cJSON_New_Item(&global_hooks);
+ if(item)
+ {
+ item->type = cJSON_Number;
+ item->valuedouble = num;
+
+ /* use saturation in case of overflow */
+ if (num >= INT_MAX)
+ {
+ item->valueint = INT_MAX;
+ }
+ else if (num <= (double)INT_MIN)
+ {
+ item->valueint = INT_MIN;
+ }
+ else
+ {
+ item->valueint = (int)num;
+ }
+ }
+
+ return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string)
+{
+ cJSON *item = cJSON_New_Item(&global_hooks);
+ if(item)
+ {
+ item->type = cJSON_String;
+ item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks);
+ if(!item->valuestring)
+ {
+ cJSON_Delete(item);
+ return NULL;
+ }
+ }
+
+ return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string)
+{
+ cJSON *item = cJSON_New_Item(&global_hooks);
+ if (item != NULL)
+ {
+ item->type = cJSON_String | cJSON_IsReference;
+ item->valuestring = (char*)cast_away_const(string);
+ }
+
+ return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child)
+{
+ cJSON *item = cJSON_New_Item(&global_hooks);
+ if (item != NULL) {
+ item->type = cJSON_Object | cJSON_IsReference;
+ item->child = (cJSON*)cast_away_const(child);
+ }
+
+ return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child) {
+ cJSON *item = cJSON_New_Item(&global_hooks);
+ if (item != NULL) {
+ item->type = cJSON_Array | cJSON_IsReference;
+ item->child = (cJSON*)cast_away_const(child);
+ }
+
+ return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw)
+{
+ cJSON *item = cJSON_New_Item(&global_hooks);
+ if(item)
+ {
+ item->type = cJSON_Raw;
+ item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw, &global_hooks);
+ if(!item->valuestring)
+ {
+ cJSON_Delete(item);
+ return NULL;
+ }
+ }
+
+ return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void)
+{
+ cJSON *item = cJSON_New_Item(&global_hooks);
+ if(item)
+ {
+ item->type=cJSON_Array;
+ }
+
+ return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void)
+{
+ cJSON *item = cJSON_New_Item(&global_hooks);
+ if (item)
+ {
+ item->type = cJSON_Object;
+ }
+
+ return item;
+}
+
+/* Create Arrays: */
+CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count)
+{
+ size_t i = 0;
+ cJSON *n = NULL;
+ cJSON *p = NULL;
+ cJSON *a = NULL;
+
+ if ((count < 0) || (numbers == NULL))
+ {
+ return NULL;
+ }
+
+ a = cJSON_CreateArray();
+
+ for(i = 0; a && (i < (size_t)count); i++)
+ {
+ n = cJSON_CreateNumber(numbers[i]);
+ if (!n)
+ {
+ cJSON_Delete(a);
+ return NULL;
+ }
+ if(!i)
+ {
+ a->child = n;
+ }
+ else
+ {
+ suffix_object(p, n);
+ }
+ p = n;
+ }
+
+ if (a && a->child) {
+ a->child->prev = n;
+ }
+
+ return a;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count)
+{
+ size_t i = 0;
+ cJSON *n = NULL;
+ cJSON *p = NULL;
+ cJSON *a = NULL;
+
+ if ((count < 0) || (numbers == NULL))
+ {
+ return NULL;
+ }
+
+ a = cJSON_CreateArray();
+
+ for(i = 0; a && (i < (size_t)count); i++)
+ {
+ n = cJSON_CreateNumber((double)numbers[i]);
+ if(!n)
+ {
+ cJSON_Delete(a);
+ return NULL;
+ }
+ if(!i)
+ {
+ a->child = n;
+ }
+ else
+ {
+ suffix_object(p, n);
+ }
+ p = n;
+ }
+
+ if (a && a->child) {
+ a->child->prev = n;
+ }
+
+ return a;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count)
+{
+ size_t i = 0;
+ cJSON *n = NULL;
+ cJSON *p = NULL;
+ cJSON *a = NULL;
+
+ if ((count < 0) || (numbers == NULL))
+ {
+ return NULL;
+ }
+
+ a = cJSON_CreateArray();
+
+ for(i = 0; a && (i < (size_t)count); i++)
+ {
+ n = cJSON_CreateNumber(numbers[i]);
+ if(!n)
+ {
+ cJSON_Delete(a);
+ return NULL;
+ }
+ if(!i)
+ {
+ a->child = n;
+ }
+ else
+ {
+ suffix_object(p, n);
+ }
+ p = n;
+ }
+
+ if (a && a->child) {
+ a->child->prev = n;
+ }
+
+ return a;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count)
+{
+ size_t i = 0;
+ cJSON *n = NULL;
+ cJSON *p = NULL;
+ cJSON *a = NULL;
+
+ if ((count < 0) || (strings == NULL))
+ {
+ return NULL;
+ }
+
+ a = cJSON_CreateArray();
+
+ for (i = 0; a && (i < (size_t)count); i++)
+ {
+ n = cJSON_CreateString(strings[i]);
+ if(!n)
+ {
+ cJSON_Delete(a);
+ return NULL;
+ }
+ if(!i)
+ {
+ a->child = n;
+ }
+ else
+ {
+ suffix_object(p,n);
+ }
+ p = n;
+ }
+
+ if (a && a->child) {
+ a->child->prev = n;
+ }
+
+ return a;
+}
+
+/* Duplication */
+CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse)
+{
+ cJSON *newitem = NULL;
+ cJSON *child = NULL;
+ cJSON *next = NULL;
+ cJSON *newchild = NULL;
+
+ /* Bail on bad ptr */
+ if (!item)
+ {
+ goto fail;
+ }
+ /* Create new item */
+ newitem = cJSON_New_Item(&global_hooks);
+ if (!newitem)
+ {
+ goto fail;
+ }
+ /* Copy over all vars */
+ newitem->type = item->type & (~cJSON_IsReference);
+ newitem->valueint = item->valueint;
+ newitem->valuedouble = item->valuedouble;
+ if (item->valuestring)
+ {
+ newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring, &global_hooks);
+ if (!newitem->valuestring)
+ {
+ goto fail;
+ }
+ }
+ if (item->string)
+ {
+ newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)cJSON_strdup((unsigned char*)item->string, &global_hooks);
+ if (!newitem->string)
+ {
+ goto fail;
+ }
+ }
+ /* If non-recursive, then we're done! */
+ if (!recurse)
+ {
+ return newitem;
+ }
+ /* Walk the ->next chain for the child. */
+ child = item->child;
+ while (child != NULL)
+ {
+ newchild = cJSON_Duplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */
+ if (!newchild)
+ {
+ goto fail;
+ }
+ if (next != NULL)
+ {
+ /* If newitem->child already set, then crosswire ->prev and ->next and move on */
+ next->next = newchild;
+ newchild->prev = next;
+ next = newchild;
+ }
+ else
+ {
+ /* Set newitem->child and move to it */
+ newitem->child = newchild;
+ next = newchild;
+ }
+ child = child->next;
+ }
+ if (newitem && newitem->child)
+ {
+ newitem->child->prev = newchild;
+ }
+
+ return newitem;
+
+ fail:
+ if (newitem != NULL)
+ {
+ cJSON_Delete(newitem);
+ }
+
+ return NULL;
+}
+
+static void skip_oneline_comment(char **input)
+{
+ *input += static_strlen("//");
+
+ for (; (*input)[0] != '\0'; ++(*input))
+ {
+ if ((*input)[0] == '\n') {
+ *input += static_strlen("\n");
+ return;
+ }
+ }
+}
+
+static void skip_multiline_comment(char **input)
+{
+ *input += static_strlen("/*");
+
+ for (; (*input)[0] != '\0'; ++(*input))
+ {
+ if (((*input)[0] == '*') && ((*input)[1] == '/'))
+ {
+ *input += static_strlen("*/");
+ return;
+ }
+ }
+}
+
+static void minify_string(char **input, char **output) {
+ (*output)[0] = (*input)[0];
+ *input += static_strlen("\"");
+ *output += static_strlen("\"");
+
+
+ for (; (*input)[0] != '\0'; (void)++(*input), ++(*output)) {
+ (*output)[0] = (*input)[0];
+
+ if ((*input)[0] == '\"') {
+ (*output)[0] = '\"';
+ *input += static_strlen("\"");
+ *output += static_strlen("\"");
+ return;
+ } else if (((*input)[0] == '\\') && ((*input)[1] == '\"')) {
+ (*output)[1] = (*input)[1];
+ *input += static_strlen("\"");
+ *output += static_strlen("\"");
+ }
+ }
+}
+
+CJSON_PUBLIC(void) cJSON_Minify(char *json)
+{
+ char *into = json;
+
+ if (json == NULL)
+ {
+ return;
+ }
+
+ while (json[0] != '\0')
+ {
+ switch (json[0])
+ {
+ case ' ':
+ case '\t':
+ case '\r':
+ case '\n':
+ json++;
+ break;
+
+ case '/':
+ if (json[1] == '/')
+ {
+ skip_oneline_comment(&json);
+ }
+ else if (json[1] == '*')
+ {
+ skip_multiline_comment(&json);
+ } else {
+ json++;
+ }
+ break;
+
+ case '\"':
+ minify_string(&json, (char**)&into);
+ break;
+
+ default:
+ into[0] = json[0];
+ json++;
+ into++;
+ }
+ }
+
+ /* and null-terminate. */
+ *into = '\0';
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item)
+{
+ if (item == NULL)
+ {
+ return false;
+ }
+
+ return (item->type & 0xFF) == cJSON_Invalid;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item)
+{
+ if (item == NULL)
+ {
+ return false;
+ }
+
+ return (item->type & 0xFF) == cJSON_False;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item)
+{
+ if (item == NULL)
+ {
+ return false;
+ }
+
+ return (item->type & 0xff) == cJSON_True;
+}
+
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item)
+{
+ if (item == NULL)
+ {
+ return false;
+ }
+
+ return (item->type & (cJSON_True | cJSON_False)) != 0;
+}
+CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item)
+{
+ if (item == NULL)
+ {
+ return false;
+ }
+
+ return (item->type & 0xFF) == cJSON_NULL;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item)
+{
+ if (item == NULL)
+ {
+ return false;
+ }
+
+ return (item->type & 0xFF) == cJSON_Number;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item)
+{
+ if (item == NULL)
+ {
+ return false;
+ }
+
+ return (item->type & 0xFF) == cJSON_String;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item)
+{
+ if (item == NULL)
+ {
+ return false;
+ }
+
+ return (item->type & 0xFF) == cJSON_Array;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item)
+{
+ if (item == NULL)
+ {
+ return false;
+ }
+
+ return (item->type & 0xFF) == cJSON_Object;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item)
+{
+ if (item == NULL)
+ {
+ return false;
+ }
+
+ return (item->type & 0xFF) == cJSON_Raw;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive)
+{
+ if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)) || cJSON_IsInvalid(a))
+ {
+ return false;
+ }
+
+ /* check if type is valid */
+ switch (a->type & 0xFF)
+ {
+ case cJSON_False:
+ case cJSON_True:
+ case cJSON_NULL:
+ case cJSON_Number:
+ case cJSON_String:
+ case cJSON_Raw:
+ case cJSON_Array:
+ case cJSON_Object:
+ break;
+
+ default:
+ return false;
+ }
+
+ /* identical objects are equal */
+ if (a == b)
+ {
+ return true;
+ }
+
+ switch (a->type & 0xFF)
+ {
+ /* in these cases and equal type is enough */
+ case cJSON_False:
+ case cJSON_True:
+ case cJSON_NULL:
+ return true;
+
+ case cJSON_Number:
+ if (compare_double(a->valuedouble, b->valuedouble))
+ {
+ return true;
+ }
+ return false;
+
+ case cJSON_String:
+ case cJSON_Raw:
+ if ((a->valuestring == NULL) || (b->valuestring == NULL))
+ {
+ return false;
+ }
+ if (strcmp(a->valuestring, b->valuestring) == 0)
+ {
+ return true;
+ }
+
+ return false;
+
+ case cJSON_Array:
+ {
+ cJSON *a_element = a->child;
+ cJSON *b_element = b->child;
+
+ for (; (a_element != NULL) && (b_element != NULL);)
+ {
+ if (!cJSON_Compare(a_element, b_element, case_sensitive))
+ {
+ return false;
+ }
+
+ a_element = a_element->next;
+ b_element = b_element->next;
+ }
+
+ /* one of the arrays is longer than the other */
+ if (a_element != b_element) {
+ return false;
+ }
+
+ return true;
+ }
+
+ case cJSON_Object:
+ {
+ cJSON *a_element = NULL;
+ cJSON *b_element = NULL;
+ cJSON_ArrayForEach(a_element, a)
+ {
+ /* TODO This has O(n^2) runtime, which is horrible! */
+ b_element = get_object_item(b, a_element->string, case_sensitive);
+ if (b_element == NULL)
+ {
+ return false;
+ }
+
+ if (!cJSON_Compare(a_element, b_element, case_sensitive))
+ {
+ return false;
+ }
+ }
+
+ /* doing this twice, once on a and b to prevent true comparison if a subset of b
+ * TODO: Do this the proper way, this is just a fix for now */
+ cJSON_ArrayForEach(b_element, b)
+ {
+ a_element = get_object_item(a, b_element->string, case_sensitive);
+ if (a_element == NULL)
+ {
+ return false;
+ }
+
+ if (!cJSON_Compare(b_element, a_element, case_sensitive))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ default:
+ return false;
+ }
+}
+
+CJSON_PUBLIC(void *) cJSON_malloc(size_t size)
+{
+ return global_hooks.allocate(size);
+}
+
+CJSON_PUBLIC(void) cJSON_free(void *object)
+{
+ global_hooks.deallocate(object);
+}
diff --git a/tools/nitrogfx/cJSON.h b/tools/nitrogfx/cJSON.h
new file mode 100644
index 00000000..94b2efe0
--- /dev/null
+++ b/tools/nitrogfx/cJSON.h
@@ -0,0 +1,293 @@
+/*
+ Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#ifndef cJSON__h
+#define cJSON__h
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32))
+#define __WINDOWS__
+#endif
+
+#ifdef __WINDOWS__
+
+/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 3 define options:
+
+CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols
+CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default)
+CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol
+
+For *nix builds that support visibility attribute, you can define similar behavior by
+
+setting default visibility to hidden by adding
+-fvisibility=hidden (for gcc)
+or
+-xldscope=hidden (for sun cc)
+to CFLAGS
+
+then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does
+
+*/
+
+#define CJSON_CDECL __cdecl
+#define CJSON_STDCALL __stdcall
+
+/* export symbols by default, this is necessary for copy pasting the C and header file */
+#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS)
+#define CJSON_EXPORT_SYMBOLS
+#endif
+
+#if defined(CJSON_HIDE_SYMBOLS)
+#define CJSON_PUBLIC(type) type CJSON_STDCALL
+#elif defined(CJSON_EXPORT_SYMBOLS)
+#define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL
+#elif defined(CJSON_IMPORT_SYMBOLS)
+#define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL
+#endif
+#else /* !__WINDOWS__ */
+#define CJSON_CDECL
+#define CJSON_STDCALL
+
+#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY)
+#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type
+#else
+#define CJSON_PUBLIC(type) type
+#endif
+#endif
+
+/* project version */
+#define CJSON_VERSION_MAJOR 1
+#define CJSON_VERSION_MINOR 7
+#define CJSON_VERSION_PATCH 14
+
+#include <stddef.h>
+
+/* cJSON Types: */
+#define cJSON_Invalid (0)
+#define cJSON_False (1 << 0)
+#define cJSON_True (1 << 1)
+#define cJSON_NULL (1 << 2)
+#define cJSON_Number (1 << 3)
+#define cJSON_String (1 << 4)
+#define cJSON_Array (1 << 5)
+#define cJSON_Object (1 << 6)
+#define cJSON_Raw (1 << 7) /* raw json */
+
+#define cJSON_IsReference 256
+#define cJSON_StringIsConst 512
+
+/* The cJSON structure: */
+typedef struct cJSON
+{
+ /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
+ struct cJSON *next;
+ struct cJSON *prev;
+ /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
+ struct cJSON *child;
+
+ /* The type of the item, as above. */
+ int type;
+
+ /* The item's string, if type==cJSON_String and type == cJSON_Raw */
+ char *valuestring;
+ /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
+ int valueint;
+ /* The item's number, if type==cJSON_Number */
+ double valuedouble;
+
+ /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
+ char *string;
+} cJSON;
+
+typedef struct cJSON_Hooks
+{
+ /* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */
+ void *(CJSON_CDECL *malloc_fn)(size_t sz);
+ void (CJSON_CDECL *free_fn)(void *ptr);
+} cJSON_Hooks;
+
+typedef int cJSON_bool;
+
+/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them.
+ * This is to prevent stack overflows. */
+#ifndef CJSON_NESTING_LIMIT
+#define CJSON_NESTING_LIMIT 1000
+#endif
+
+/* returns the version of cJSON as a string */
+CJSON_PUBLIC(const char*) cJSON_Version(void);
+
+/* Supply malloc, realloc and free functions to cJSON */
+CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks);
+
+/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */
+/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */
+CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
+CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length);
+/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
+/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */
+CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated);
+CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated);
+
+/* Render a cJSON entity to text for transfer/storage. */
+CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
+/* Render a cJSON entity to text for transfer/storage without any formatting. */
+CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item);
+/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
+CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt);
+/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */
+/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */
+CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format);
+/* Delete a cJSON entity and all subentities. */
+CJSON_PUBLIC(void) cJSON_Delete(cJSON *item);
+
+/* Returns the number of items in an array (or object). */
+CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);
+/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */
+CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);
+/* Get item "string" from object. Case insensitive. */
+CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);
+CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string);
+CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string);
+/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
+CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void);
+
+/* Check item type and return its value */
+CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item);
+CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item);
+
+/* These functions check the type of an item */
+CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item);
+CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item);
+CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item);
+CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item);
+CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item);
+CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item);
+CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item);
+CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item);
+CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item);
+CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item);
+
+/* These calls create a cJSON item of the appropriate type. */
+CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void);
+CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void);
+CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
+CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean);
+CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);
+CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);
+/* raw json */
+CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
+CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
+CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);
+
+/* Create a string where valuestring references a string so
+ * it will not be freed by cJSON_Delete */
+CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string);
+/* Create an object/array that only references it's elements so
+ * they will not be freed by cJSON_Delete */
+CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child);
+CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child);
+
+/* These utilities create an Array of count items.
+ * The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/
+CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count);
+CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count);
+CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count);
+CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count);
+
+/* Append item to the specified array/object. */
+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item);
+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
+/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object.
+ * WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before
+ * writing to `item->string` */
+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item);
+/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
+CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
+
+/* Remove/Detach items from Arrays/Objects. */
+CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item);
+CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which);
+CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which);
+CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string);
+CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string);
+CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string);
+CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string);
+
+/* Update array items. */
+CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */
+CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement);
+CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
+CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
+CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem);
+
+/* Duplicate a cJSON item */
+CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse);
+/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
+ * need to be released. With recurse!=0, it will duplicate any children connected to the item.
+ * The item->next and ->prev pointers are always zero on return from Duplicate. */
+/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal.
+ * case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */
+CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive);
+
+/* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings.
+ * The input pointer json cannot point to a read-only address area, such as a string constant,
+ * but should point to a readable and writable adress area. */
+CJSON_PUBLIC(void) cJSON_Minify(char *json);
+
+/* Helper functions for creating and adding items to an object at the same time.
+ * They return the added item or NULL on failure. */
+CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name);
+CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name);
+CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name);
+CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean);
+CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);
+CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);
+CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw);
+CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name);
+CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name);
+
+/* When assigning an integer value, it needs to be propagated to valuedouble too. */
+#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number))
+/* helper for the cJSON_SetNumberValue macro */
+CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number);
+#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number))
+/* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */
+CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring);
+
+/* Macro for iterating over an array or object */
+#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next)
+
+/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */
+CJSON_PUBLIC(void *) cJSON_malloc(size_t size);
+CJSON_PUBLIC(void) cJSON_free(void *object);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/tools/nitrogfx/gfx.c b/tools/nitrogfx/gfx.c
index 1f414ad7..be01a456 100644
--- a/tools/nitrogfx/gfx.c
+++ b/tools/nitrogfx/gfx.c
@@ -736,3 +736,207 @@ void WriteNtrPalette(char *path, struct Palette *palette, bool ncpr, bool ir, in
fclose(fp);
}
+
+void WriteNtrCell(char *path, struct JsonToCellOptions *options)
+{
+ FILE *fp = fopen(path, "wb");
+
+ if (fp == NULL)
+ FATAL_ERROR("Failed to open \"%s\" for writing.\n", path);
+
+ unsigned int totalSize = (options->label > 0 ? 0x34 : 0x20) + options->cellCount * (options->extended ? 0x16 : 0xe);
+
+ if (options->label)
+ {
+ for (int i = 0; i < options->cellCount; i++) {
+ totalSize += strlen(options->cells[i]->label) + 5; //strlen + terminator + pointer
+ }
+ }
+
+ WriteGenericNtrHeader(fp, "RECN", totalSize, true, false, options->label ? 3 : 1);
+
+ unsigned char KBECHeader[0x20] =
+ {
+ 0x4B, 0x42, 0x45, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+
+ KBECHeader[8] = options->cellCount; //cell count
+
+ if (options->extended)
+ {
+ KBECHeader[10] = 1; //extended
+ }
+
+ unsigned int size = options->cellCount * (options->extended ? 0x16 : 0xe);
+
+ KBECHeader[4] = (size + 0x20) & 0xFF; //size
+ KBECHeader[5] = (size + 0x20) >> 8; //unlikely to be more than 16 bits, but there are 32 allocated, change if necessary
+
+ fwrite(KBECHeader, 1, 0x20, fp);
+
+
+ unsigned char *KBECContents = malloc(size);
+
+ memset(KBECContents, 0, size);
+
+ if (!options->extended)
+ {
+ FATAL_ERROR("Don't know how to deal with not extended yet, bug red031000.\n");
+ }
+
+ int i;
+ for (i = 0; i < options->cellCount * 0x10; i += 0x10)
+ {
+ KBECContents[i] = 0x01; //number of images
+ KBECContents[i + 2] = options->cells[i / 0x10]->readOnly & 0xff; //unknown
+ KBECContents[i + 3] = options->cells[i / 0x10]->readOnly >> 8;
+ KBECContents[i + 4] = (i / 0x10 * 6) & 0xff; //pointer to OAM data
+ KBECContents[i + 5] = (i / 0x10 * 6) >> 8; //unlikely to be more than 16 bits, but there are 32 allocated, change if necessary
+ KBECContents[i + 8] = options->cells[i / 0x10]->maxX & 0xff; //maxX
+ KBECContents[i + 9] = options->cells[i / 0x10]->maxX >> 8;
+ KBECContents[i + 10] = options->cells[i / 0x10]->maxY & 0xff; //maxY
+ KBECContents[i + 11] = options->cells[i / 0x10]->maxY >> 8;
+ KBECContents[i + 12] = options->cells[i / 0x10]->minX & 0xff; //minX
+ KBECContents[i + 13] = options->cells[i / 0x10]->minX >> 8;
+ KBECContents[i + 14] = options->cells[i / 0x10]->minY & 0xff; //minY
+ KBECContents[i + 15] = options->cells[i / 0x10]->minY >> 8;
+ }
+
+ //OAM data
+ for (int j = i; j < options->cellCount * 6 + i; j += 6)
+ {
+ //Attr0
+
+ //bits 0-7 Y coordinate
+ KBECContents[j] = options->cells[(j - i) / 6]->oam.attr0.YCoordinate & 0xff;
+
+ //bit 8 rotation
+ KBECContents[j + 1] = options->cells[(j - i) / 6]->oam.attr0.Rotation;
+
+ //bit 9 Obj Size (if rotation) or Obj Disable (if not rotation)
+ KBECContents[j + 1] |= options->cells[(j - i) / 6]->oam.attr0.SizeDisable << 1;
+
+ //bits 10-11 Obj Mode
+ KBECContents[j + 1] |= options->cells[(j - i) / 6]->oam.attr0.Mode << 2;
+
+ //bit 12 Obj Mosaic
+ KBECContents[j + 1] |= options->cells[(j - i) / 6]->oam.attr0.Mosaic << 4;
+
+ //bit 13 Colours
+ KBECContents[j + 1] |= (options->cells[(j - i) / 6]->oam.attr0.Colours == 16 ? 0 : 1) << 5;
+
+ //bits 14-15 Obj Shape
+ KBECContents[j + 1] |= options->cells[(j - i) / 6]->oam.attr0.Shape << 6;
+
+ //Attr1
+
+ //bits 0-8 X coordinate
+ KBECContents[j + 2] = options->cells[(j - i) / 6]->oam.attr1.XCoordinate & 0xff;
+ KBECContents[j + 3] = options->cells[(j - i) / 6]->oam.attr1.XCoordinate >> 8;
+
+ //bits 9-13 Rotation and scaling (if rotation) bit 12 Horizontal flip, bit 13 Vertical flip (if not rotation)
+ KBECContents[j + 3] |= options->cells[(j - i) / 6]->oam.attr1.RotationScaling << 1;
+
+ //bits 14-15 Obj Size
+ KBECContents[j + 3] |= options->cells[(j - i) / 6]->oam.attr1.Size << 6;
+
+ //Attr2
+
+ //bits 0-9 Character Name?
+ KBECContents[j + 4] = options->cells[(j - i) / 6]->oam.attr2.CharName & 0xff;
+ KBECContents[j + 5] = options->cells[(j - i) / 6]->oam.attr2.CharName >> 8;
+
+ //bits 10-11 Priority
+ KBECContents[j + 5] |= options->cells[(j - i) / 6]->oam.attr2.Priority << 2;
+
+ //bits 12-15 Palette Number
+ KBECContents[j + 5] |= options->cells[(j - i) / 6]->oam.attr2.Palette << 4;
+ }
+
+ fwrite(KBECContents, 1, size, fp);
+
+ free(KBECContents);
+
+ if (options->label)
+ {
+ unsigned int lablSize = 8 + options->cellCount * 4;
+ for (i = 0; i < options->cellCount; i++)
+ {
+ lablSize += strlen(options->cells[i]->label) + 1;
+ }
+
+ unsigned char *labl = malloc(lablSize);
+
+ memset(labl, 0, lablSize);
+
+ strcpy((char *) labl, "LBAL");
+ labl[4] = lablSize & 0xff;
+ labl[5] = lablSize >> 8;
+
+ unsigned int position = 0;
+
+ for (i = 0; i < options->cellCount * 4; i += 4)
+ {
+ labl[i + 8] = position & 0xff;
+ labl[i + 9] = position >> 8;
+
+ position += strlen(options->cells[i / 4]->label) + 1;
+ }
+
+ for (int j = 0; j < options->cellCount; j++)
+ {
+ strcpy((char *) (labl + (i + 8)), options->cells[j]->label);
+ i += strlen(options->cells[j]->label) + 1;
+ }
+
+ fwrite(labl, 1, lablSize, fp);
+
+ free(labl);
+
+ unsigned char texu[0xc] = {0x54, 0x58, 0x45, 0x55, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+ fwrite(texu, 1, 0xc, fp);
+ }
+
+ fclose(fp);
+}
+
+void WriteNtrScreen(char *outputPath, struct JsonToScreenOptions *options)
+{
+ FILE *fp = fopen(outputPath, "wb");
+
+ if (fp == NULL)
+ FATAL_ERROR("Failed to open \"%s\" for writing.\n", outputPath);
+
+ int totalSize = options->width * options->height * 2 + 0x14;
+
+ WriteGenericNtrHeader(fp, "RCSN", totalSize, true, false, 1);
+
+ unsigned char NSCRHeader[0x14] = { 0x4E, 0x52, 0x43, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00 };
+
+ NSCRHeader[0x4] = totalSize & 0xff;
+ NSCRHeader[0x5] = (totalSize >> 8) & 0xff;
+ NSCRHeader[0x6] = (totalSize >> 16) & 0xff;
+ NSCRHeader[0x7] = totalSize >> 24;
+
+ NSCRHeader[0x8] = (options->width * 8) & 0xff;
+ NSCRHeader[0x9] = (options->width * 8) >> 8;
+
+ NSCRHeader[0xA] = (options->height * 8) & 0xff;
+ NSCRHeader[0xB] = (options->height * 8) >> 8;
+
+ NSCRHeader[0xC] = options->bitdepth == 4 ? 0 : 1;
+
+ NSCRHeader[0x10] = (totalSize - 0x14) & 0xff;
+ NSCRHeader[0x11] = ((totalSize - 0x14) >> 8) & 0xff;
+ NSCRHeader[0x12] = ((totalSize - 0x14) >> 16) & 0xff;
+ NSCRHeader[0x13] = (totalSize - 0x14) >> 24;
+
+ fwrite(NSCRHeader, 1, 0x14, fp);
+
+ fwrite(options->data, 1, totalSize - 0x14, fp);
+
+ fclose(fp);
+}
diff --git a/tools/nitrogfx/gfx.h b/tools/nitrogfx/gfx.h
index e04a781a..d0e6521a 100644
--- a/tools/nitrogfx/gfx.h
+++ b/tools/nitrogfx/gfx.h
@@ -5,6 +5,7 @@
#include <stdint.h>
#include <stdbool.h>
+#include "options.h"
struct Color {
unsigned char red;
@@ -37,5 +38,7 @@ void ReadGbaPalette(char *path, struct Palette *palette);
void ReadNtrPalette(char *path, struct Palette *palette, int bitdepth, int palIndex);
void WriteGbaPalette(char *path, struct Palette *palette);
void WriteNtrPalette(char *path, struct Palette *palette, bool ncpr, bool ir, int bitdepth, bool pad, int compNum);
+void WriteNtrCell(char *path, struct JsonToCellOptions *options);
+void WriteNtrScreen(char *outputPath, struct JsonToScreenOptions *options);
#endif // GFX_H
diff --git a/tools/nitrogfx/json.c b/tools/nitrogfx/json.c
new file mode 100644
index 00000000..fa9f9e5e
--- /dev/null
+++ b/tools/nitrogfx/json.c
@@ -0,0 +1,212 @@
+// Copyright (c) 2021 red031000
+
+#include "global.h"
+#include "cJSON.h"
+#include "json.h"
+#include "util.h"
+#include <string.h>
+#include <stdlib.h>
+
+static inline bool GetBool(cJSON * in)
+{
+ if (!cJSON_IsBool(in))
+ return false;
+
+ return cJSON_IsTrue(in);
+}
+
+static inline int GetInt(cJSON * in)
+{
+ if (!cJSON_IsNumber(in))
+ return 0;
+
+ return in->valueint;
+}
+
+static inline char *GetString(cJSON * in)
+{
+ if (!cJSON_IsString(in))
+ return NULL;
+
+ return in->valuestring;
+}
+
+struct JsonToCellOptions *ParseNCERJson(char *path)
+{
+ int fileLength;
+ unsigned char *jsonString = ReadWholeFile(path, &fileLength);
+
+ cJSON *json = cJSON_Parse((const char *)jsonString);
+
+ struct JsonToCellOptions *options = malloc(sizeof(struct JsonToCellOptions));
+
+ if (json == NULL)
+ {
+ const char *errorPtr = cJSON_GetErrorPtr();
+ FATAL_ERROR("Error in line \"%s\"\n", errorPtr);
+ }
+
+ cJSON *labelBool = cJSON_GetObjectItemCaseSensitive(json, "label");
+ cJSON *extended = cJSON_GetObjectItemCaseSensitive(json, "extended");
+ cJSON *imageHeight = cJSON_GetObjectItemCaseSensitive(json, "imageHeight");
+ cJSON *imageWidth = cJSON_GetObjectItemCaseSensitive(json, "imageWidth");
+ cJSON *cellCount = cJSON_GetObjectItemCaseSensitive(json, "cellCount");
+
+ options->label = GetBool(labelBool);
+ options->extended = GetBool(extended);
+ options->imageHeight = GetInt(imageHeight);
+ options->imageWidth = GetInt(imageWidth);
+ options->cellCount = GetInt(cellCount);
+
+ options->cells = malloc(sizeof(struct Cell *) * options->cellCount);
+
+ for (int i = 0; i < options->cellCount; i++)
+ {
+ options->cells[i] = malloc(sizeof(struct Cell));
+ }
+
+ int i = 0;
+ cJSON *cells = cJSON_GetObjectItemCaseSensitive(json, "cells");
+ cJSON *cell = NULL;
+
+ cJSON_ArrayForEach(cell, cells)
+ {
+ if (i > options->cellCount - 1)
+ FATAL_ERROR("Cell count is incorrect.\n");
+
+ cJSON *readOnly = cJSON_GetObjectItemCaseSensitive(cell, "readOnly");
+
+ options->cells[i]->readOnly = (short)GetInt(readOnly);
+ if (options->extended)
+ {
+ cJSON *maxX = cJSON_GetObjectItemCaseSensitive(cell, "maxX");
+ cJSON *maxY = cJSON_GetObjectItemCaseSensitive(cell, "maxY");
+ cJSON *minX = cJSON_GetObjectItemCaseSensitive(cell, "minX");
+ cJSON *minY = cJSON_GetObjectItemCaseSensitive(cell, "minY");
+
+ options->cells[i]->maxX = (short)GetInt(maxX);
+ options->cells[i]->maxY = (short)GetInt(maxY);
+ options->cells[i]->minX = (short)GetInt(minX);
+ options->cells[i]->minY = (short)GetInt(minY);
+ }
+
+ if (options->label)
+ {
+ cJSON *label = cJSON_GetObjectItemCaseSensitive(cell, "label");
+ char *labelString = GetString(label);
+ options->cells[i]->label = malloc(strlen(labelString) + 1);
+ strcpy(options->cells[i]->label, labelString);
+ }
+ //OAM data
+ cJSON *OAM = cJSON_GetObjectItemCaseSensitive(cell, "OAM");
+
+ //Attr0
+ cJSON *Attr0 = cJSON_GetObjectItemCaseSensitive(OAM, "Attr0");
+
+ cJSON *YCoordinate = cJSON_GetObjectItemCaseSensitive(Attr0, "YCoordinate");
+ cJSON *Rotation = cJSON_GetObjectItemCaseSensitive(Attr0, "Rotation");
+ cJSON *SizeDisable = cJSON_GetObjectItemCaseSensitive(Attr0, "SizeDisable");
+ cJSON *Mode = cJSON_GetObjectItemCaseSensitive(Attr0, "Mode");
+ cJSON *Mosaic = cJSON_GetObjectItemCaseSensitive(Attr0, "Mosaic");
+ cJSON *Colours = cJSON_GetObjectItemCaseSensitive(Attr0, "Colours");
+ cJSON *Shape = cJSON_GetObjectItemCaseSensitive(Attr0, "Shape");
+
+ options->cells[i]->oam.attr0.YCoordinate = GetInt(YCoordinate);
+ options->cells[i]->oam.attr0.Rotation = GetBool(Rotation);
+ options->cells[i]->oam.attr0.SizeDisable = GetBool(SizeDisable);
+ options->cells[i]->oam.attr0.Mode = GetInt(Mode);
+ options->cells[i]->oam.attr0.Mosaic = GetBool(Mosaic);
+ options->cells[i]->oam.attr0.Colours = GetInt(Colours);
+ options->cells[i]->oam.attr0.Shape = GetInt(Shape);
+
+ //Attr1
+ cJSON *Attr1 = cJSON_GetObjectItemCaseSensitive(OAM, "Attr1");
+
+ cJSON *XCoordinate = cJSON_GetObjectItemCaseSensitive(Attr1, "XCoordinate");
+ cJSON *RotationScaling = cJSON_GetObjectItemCaseSensitive(Attr1, "RotationScaling");
+ cJSON *Size = cJSON_GetObjectItemCaseSensitive(Attr1, "Size");
+
+ options->cells[i]->oam.attr1.XCoordinate = GetInt(XCoordinate);
+ options->cells[i]->oam.attr1.RotationScaling = GetInt(RotationScaling);
+ options->cells[i]->oam.attr1.Size = GetInt(Size);
+
+ //Attr2
+ cJSON *Attr2 = cJSON_GetObjectItemCaseSensitive(OAM, "Attr2");
+
+ cJSON *CharName = cJSON_GetObjectItemCaseSensitive(Attr2, "CharName");
+ cJSON *Priority = cJSON_GetObjectItemCaseSensitive(Attr2, "Priority");
+ cJSON *Palette = cJSON_GetObjectItemCaseSensitive(Attr2, "Palette");
+
+ options->cells[i]->oam.attr2.CharName = GetInt(CharName);
+ options->cells[i]->oam.attr2.Priority = GetInt(Priority);
+ options->cells[i]->oam.attr2.Palette = GetInt(Palette);
+
+ i++;
+ }
+
+ cJSON_Delete(json);
+ free(jsonString);
+ return options;
+}
+
+struct JsonToScreenOptions *ParseNSCRJson(char *path)
+{
+ int fileLength;
+ unsigned char *jsonString = ReadWholeFile(path, &fileLength);
+
+ cJSON *json = cJSON_Parse((const char *)jsonString);
+
+ struct JsonToScreenOptions *options = malloc(sizeof(struct JsonToScreenOptions));
+
+ if (json == NULL)
+ {
+ const char *errorPtr = cJSON_GetErrorPtr();
+ FATAL_ERROR("Error in line \"%s\"\n", errorPtr);
+ }
+
+ cJSON *Height = cJSON_GetObjectItemCaseSensitive(json, "height");
+ cJSON *Width = cJSON_GetObjectItemCaseSensitive(json, "width");
+
+ options->height = GetInt(Height);
+ options->width = GetInt(Width);
+
+ options->data = malloc(sizeof(unsigned short) * options->height * options->width);
+
+ cJSON *layer = NULL;
+ cJSON *layers = cJSON_GetObjectItemCaseSensitive(json, "layers");
+ cJSON_ArrayForEach(layer, layers)
+ {
+ cJSON *tile = NULL;
+ cJSON *data = cJSON_GetObjectItemCaseSensitive(layer, "data");
+ int i = 0;
+ cJSON_ArrayForEach(tile, data)
+ {
+ options->data[i] = (short)(GetInt(tile) - 1); //TODO horizontal and vertical flips
+ i++;
+ }
+ }
+
+ cJSON_Delete(json);
+ free(jsonString);
+ return options;
+}
+
+void FreeNCERCell(struct JsonToCellOptions *options)
+{
+ for (int i = 0; i < options->cellCount; i++)
+ {
+ if (options->label)
+ {
+ free(options->cells[i]->label);
+ }
+ free(options->cells[i]);
+ }
+ free(options);
+}
+
+void FreeNSCRScreen(struct JsonToScreenOptions *options)
+{
+ free(options->data);
+ free(options);
+}
+
diff --git a/tools/nitrogfx/json.h b/tools/nitrogfx/json.h
new file mode 100644
index 00000000..f297cf08
--- /dev/null
+++ b/tools/nitrogfx/json.h
@@ -0,0 +1,13 @@
+// Copyright (c) 2021 red031000
+
+#ifndef JSON_H
+#define JSON_H
+
+#include "options.h"
+
+struct JsonToCellOptions *ParseNCERJson(char *path);
+struct JsonToScreenOptions *ParseNSCRJson(char *path);
+void FreeNCERCell(struct JsonToCellOptions *options);
+void FreeNSCRScreen(struct JsonToScreenOptions *options);
+
+#endif //JSON_H
diff --git a/tools/nitrogfx/main.c b/tools/nitrogfx/main.c
index 35f59d0b..171cb5f3 100644
--- a/tools/nitrogfx/main.c
+++ b/tools/nitrogfx/main.c
@@ -13,6 +13,7 @@
#include "rl.h"
#include "font.h"
#include "huff.h"
+#include "json.h"
struct CommandHandler
{
@@ -674,6 +675,55 @@ void HandleJascToNtrPaletteCommand(char *inputPath, char *outputPath, int argc,
WriteNtrPalette(outputPath, &palette, ncpr, ir, bitdepth, !nopad, compNum);
}
+void HandleJsonToNtrCellCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED)
+{
+ struct JsonToCellOptions *options;
+
+ options = ParseNCERJson(inputPath);
+
+ WriteNtrCell(outputPath, options);
+
+ FreeNCERCell(options);
+}
+
+void HandleJsonToNtrScreenCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED)
+{
+ struct JsonToScreenOptions *options;
+
+ options = ParseNSCRJson(inputPath);
+
+ int bitdepth = 4;
+
+ for (int i = 3; i < argc; i++)
+ {
+ char *option = argv[i];
+
+ if (strcmp(option, "-bitdepth") == 0)
+ {
+ if (i + 1 >= argc)
+ FATAL_ERROR("No bitdepth following \"-bitdepth\".\n");
+
+ i++;
+
+ if (!ParseNumber(argv[i], NULL, 10, &bitdepth))
+ FATAL_ERROR("Failed to parse bitdepth.\n");
+
+ if (bitdepth != 4 && bitdepth != 8)
+ FATAL_ERROR("Bitdepth must be 4 or 8.\n");
+ }
+ else
+ {
+ FATAL_ERROR("Unrecognized option \"%s\".\n", option);
+ }
+ }
+
+ options->bitdepth = bitdepth;
+
+ WriteNtrScreen(outputPath, options);
+
+ FreeNSCRScreen(options);
+}
+
void HandleLatinFontToPngCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED)
{
struct Image image;
@@ -932,6 +982,8 @@ int main(int argc, char **argv)
{ "png", "hwjpnfont", HandlePngToHalfwidthJapaneseFontCommand },
{ "fwjpnfont", "png", HandleFullwidthJapaneseFontToPngCommand },
{ "png", "fwjpnfont", HandlePngToFullwidthJapaneseFontCommand },
+ { "json", "NCER", HandleJsonToNtrCellCommand },
+ { "json", "NSCR", HandleJsonToNtrScreenCommand },
{ NULL, "huff", HandleHuffCompressCommand },
{ NULL, "lz", HandleLZCompressCommand },
{ "huff", NULL, HandleHuffDecompressCommand },
diff --git a/tools/nitrogfx/options.h b/tools/nitrogfx/options.h
index 8c1e7a0e..f4626df9 100644
--- a/tools/nitrogfx/options.h
+++ b/tools/nitrogfx/options.h
@@ -34,5 +34,58 @@ struct PngToNtrOptions {
bool scanned;
};
+struct Attr0 {
+ int YCoordinate;
+ bool Rotation;
+ bool SizeDisable;
+ int Mode;
+ bool Mosaic;
+ int Colours;
+ int Shape;
+};
+
+struct Attr1 {
+ int XCoordinate;
+ int RotationScaling;
+ int Size;
+};
+
+struct Attr2 {
+ int CharName;
+ int Priority;
+ int Palette;
+};
+
+struct OAM {
+ struct Attr0 attr0;
+ struct Attr1 attr1;
+ struct Attr2 attr2;
+};
+
+struct Cell {
+ short readOnly;
+ short maxX;
+ short maxY;
+ short minX;
+ short minY;
+ struct OAM oam;
+ char *label;
+};
+
+struct JsonToCellOptions {
+ bool label;
+ bool extended;
+ int imageHeight;
+ int imageWidth;
+ int cellCount;
+ struct Cell **cells;
+};
+
+struct JsonToScreenOptions {
+ int height;
+ int width;
+ unsigned short *data;
+ int bitdepth;
+};
#endif // OPTIONS_H