on master help sign in
Initial commit
commitf9804b53a18a421c0b3873b797700496fce00747 authorNicolas Seriot <nicolas@seriot.ch> dateSun 23 Oct 2016, 21:17 (10 years ago) parent7b21557
831 files changed+42969−1
README.md+49−1 parsers/test-AppleJSONSerialization/bin/test-AppleJSONSerialization parsers/test-AppleJSONSerialization/test-AppleJSONSerialization.xcodeproj/project.pbxproj+260 parsers/test-AppleJSONSerialization/test-AppleJSONSerialization.xcodeproj/project.xcworkspace/contents.xcworkspacedata+7 parsers/test-AppleJSONSerialization/test-AppleJSONSerialization.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstate parsers/test-AppleJSONSerialization/test-AppleJSONSerialization.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test-AppleJSONSerialization.xcscheme+91 parsers/test-AppleJSONSerialization/test-AppleJSONSerialization.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plist+22 parsers/test-AppleJSONSerialization/test-AppleJSONSerialization/main.swift+34 parsers/test_Bash_JSON/JSON.sh+208 parsers/test_Freddy_20160830/bin/test_Freddy parsers/test_Freddy_20160830/test_Freddy.xcodeproj/project.pbxproj+300 parsers/test_Freddy_20160830/test_Freddy.xcodeproj/project.xcworkspace/contents.xcworkspacedata+7 parsers/test_Freddy_20160830/test_Freddy.xcodeproj/project.xcworkspace/xcshareddata/test_Freddy.xcscmblueprint+30 parsers/test_Freddy_20160830/test_Freddy.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstate parsers/test_Freddy_20160830/test_Freddy.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test_Freddy.xcscheme+91 parsers/test_Freddy_20160830/test_Freddy.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plist+22 parsers/test_Freddy_20160830/test_Freddy/JSON.swift+95 parsers/test_Freddy_20160830/test_Freddy/JSONDecodable.swift+177 parsers/test_Freddy_20160830/test_Freddy/JSONEncodable.swift+83 parsers/test_Freddy_20160830/test_Freddy/JSONEncodingDetector.swift+110 parsers/test_Freddy_20160830/test_Freddy/JSONLiteralConvertible.swift+130 parsers/test_Freddy_20160830/test_Freddy/JSONParser.swift+907 parsers/test_Freddy_20160830/test_Freddy/JSONParsing.swift+126 parsers/test_Freddy_20160830/test_Freddy/JSONSerializing.swift+43 parsers/test_Freddy_20160830/test_Freddy/JSONSubscripting.swift+705 parsers/test_Freddy_20160830/test_Freddy/main.swift+37 parsers/test_Freddy_20161018/bin/test_Freddy parsers/test_Freddy_20161018/test_Freddy.xcodeproj/project.pbxproj+300 parsers/test_Freddy_20161018/test_Freddy.xcodeproj/project.xcworkspace/contents.xcworkspacedata+7 parsers/test_Freddy_20161018/test_Freddy.xcodeproj/project.xcworkspace/xcshareddata/test_Freddy.xcscmblueprint+30 parsers/test_Freddy_20161018/test_Freddy.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstate parsers/test_Freddy_20161018/test_Freddy.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test_Freddy.xcscheme+91 parsers/test_Freddy_20161018/test_Freddy.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plist+22 parsers/test_Freddy_20161018/test_Freddy/JSON.swift+98 parsers/test_Freddy_20161018/test_Freddy/JSONDecodable.swift+186 parsers/test_Freddy_20161018/test_Freddy/JSONEncodable.swift+83 parsers/test_Freddy_20161018/test_Freddy/JSONEncodingDetector.swift+110 parsers/test_Freddy_20161018/test_Freddy/JSONLiteralConvertible.swift+134 parsers/test_Freddy_20161018/test_Freddy/JSONParser.swift+918 parsers/test_Freddy_20161018/test_Freddy/JSONParsing.swift+126 parsers/test_Freddy_20161018/test_Freddy/JSONSerializing.swift+54 parsers/test_Freddy_20161018/test_Freddy/JSONSubscripting.swift+613 parsers/test_Freddy_20161018/test_Freddy/main.swift+40 parsers/test_Freddy_2_1_0/bin/test_Freddy_2_1_0 parsers/test_Freddy_2_1_0/test_Freddy.xcodeproj/project.pbxproj+300 parsers/test_Freddy_2_1_0/test_Freddy.xcodeproj/project.xcworkspace/contents.xcworkspacedata+7 parsers/test_Freddy_2_1_0/test_Freddy.xcodeproj/project.xcworkspace/xcshareddata/test_Freddy.xcscmblueprint+30 parsers/test_Freddy_2_1_0/test_Freddy.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstate parsers/test_Freddy_2_1_0/test_Freddy.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test_Freddy.xcscheme+91 parsers/test_Freddy_2_1_0/test_Freddy.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plist+22 parsers/test_Freddy_2_1_0/test_Freddy/JSON.swift+95 parsers/test_Freddy_2_1_0/test_Freddy/JSONDecodable.swift+151 parsers/test_Freddy_2_1_0/test_Freddy/JSONEncodable.swift+83 parsers/test_Freddy_2_1_0/test_Freddy/JSONEncodingDetector.swift+110 parsers/test_Freddy_2_1_0/test_Freddy/JSONLiteralConvertible.swift+130 parsers/test_Freddy_2_1_0/test_Freddy/JSONParser.swift+903 parsers/test_Freddy_2_1_0/test_Freddy/JSONParsing.swift+126 parsers/test_Freddy_2_1_0/test_Freddy/JSONSerializing.swift+43 parsers/test_Freddy_2_1_0/test_Freddy/JSONSubscripting.swift+643 parsers/test_Freddy_2_1_0/test_Freddy/main.swift+37 parsers/test_JSONKit/JSONKit.h+251 parsers/test_JSONKit/JSONKit.m+3065 parsers/test_JSONKit/bin/test-JSONKit parsers/test_JSONKit/test-JSONKit.xcodeproj/project.pbxproj+252 parsers/test_JSONKit/test-JSONKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata+7 parsers/test_JSONKit/test-JSONKit.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstate parsers/test_JSONKit/test-JSONKit.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test-JSONKit.xcscheme+91 parsers/test_JSONKit/test-JSONKit.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plist+22 parsers/test_JSONKit/test-JSONKit/main.m+73 parsers/test_Lua_JSON/JSON.lua+1451 parsers/test_Lua_JSON/test_JSON.lua+22 parsers/test_ObjCNSJSONSerializer/bin/test_ObjCNSJSONSerializer parsers/test_ObjCNSJSONSerializer/test_ObjCNSJSONSerializer.xcodeproj/project.pbxproj+246 parsers/test_ObjCNSJSONSerializer/test_ObjCNSJSONSerializer.xcodeproj/project.xcworkspace/contents.xcworkspacedata+7 parsers/test_ObjCNSJSONSerializer/test_ObjCNSJSONSerializer.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstate parsers/test_ObjCNSJSONSerializer/test_ObjCNSJSONSerializer.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test_ObjCNSJSONSerializer.xcscheme+97 parsers/test_ObjCNSJSONSerializer/test_ObjCNSJSONSerializer.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plist+22 parsers/test_ObjCNSJSONSerializer/test_ObjCNSJSONSerializer/a.out parsers/test_ObjCNSJSONSerializer/test_ObjCNSJSONSerializer/a.out.dSYM/Contents/Info.plist+20 parsers/test_ObjCNSJSONSerializer/test_ObjCNSJSONSerializer/a.out.dSYM/Contents/Resources/DWARF/a.out parsers/test_ObjCNSJSONSerializer/test_ObjCNSJSONSerializer/findings_dir/plot_data+1 parsers/test_ObjCNSJSONSerializer/test_ObjCNSJSONSerializer/main.m+32 parsers/test_SBJSON/SBJson4.h+35 parsers/test_SBJSON/SBJson4Parser.h+248 parsers/test_SBJSON/SBJson4Parser.m+287 parsers/test_SBJSON/SBJson4StreamParser.h+131 parsers/test_SBJSON/SBJson4StreamParser.m+317 parsers/test_SBJSON/SBJson4StreamParserState.h+82 parsers/test_SBJSON/SBJson4StreamParserState.m+355 parsers/test_SBJSON/SBJson4StreamTokeniser.h+40 parsers/test_SBJSON/SBJson4StreamTokeniser.m+395 parsers/test_SBJSON/SBJson4StreamWriter.h+210 parsers/test_SBJSON/SBJson4StreamWriter.m+358 parsers/test_SBJSON/SBJson4StreamWriterState.h+69 parsers/test_SBJSON/SBJson4StreamWriterState.m+147 parsers/test_SBJSON/SBJson4Writer.h+103 parsers/test_SBJSON/SBJson4Writer.m+102 parsers/test_SBJSON/bin/test_SBJSON parsers/test_SBJSON/test_SBJSON.xcodeproj/project.pbxproj+290 parsers/test_SBJSON/test_SBJSON.xcodeproj/project.xcworkspace/contents.xcworkspacedata+7 parsers/test_SBJSON/test_SBJSON.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstate parsers/test_SBJSON/test_SBJSON.xcodeproj/xcuserdata/nst.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist+5 parsers/test_SBJSON/test_SBJSON.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test_SBJSON.xcscheme+91 parsers/test_SBJSON/test_SBJSON.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plist+22 parsers/test_SBJSON/test_SBJSON/main.m+38 parsers/test_STJSON/STJSON.xcodeproj/project.pbxproj+361 parsers/test_STJSON/STJSON.xcodeproj/project.xcworkspace/contents.xcworkspacedata+7 parsers/test_STJSON/STJSON.xcodeproj/project.xcworkspace/xcshareddata/STJSON.xcscmblueprint+30 parsers/test_STJSON/STJSON.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstate parsers/test_STJSON/STJSON.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/STJSON.xcscheme+91 parsers/test_STJSON/STJSON.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/STJSONTests.xcscheme+56 parsers/test_STJSON/STJSON.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plist+32 parsers/test_STJSON/STJSON/STJSONParser.swift+663 parsers/test_STJSON/STJSON/main.swift+47 parsers/test_STJSON/STJSONTests/Info.plist+22 parsers/test_STJSON/STJSONTests/STJSONTests.swift+92 parsers/test_STJSON/bin/STJSON parsers/test_TouchJSON/bin/test_TouchJSON parsers/test_TouchJSON/test_TouchJSON.xcodeproj/project.pbxproj+262 parsers/test_TouchJSON/test_TouchJSON.xcodeproj/project.xcworkspace/contents.xcworkspacedata+7 parsers/test_TouchJSON/test_TouchJSON.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstate parsers/test_TouchJSON/test_TouchJSON.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test_TouchJSON.xcscheme+97 parsers/test_TouchJSON/test_TouchJSON.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plist+22 parsers/test_TouchJSON/test_TouchJSON/CJSONDeserializer.h+96 parsers/test_TouchJSON/test_TouchJSON/CJSONDeserializer.m+1240 parsers/test_TouchJSON/test_TouchJSON/main.m+25 parsers/test_cJSON/bin/test-cJSON parsers/test_cJSON/cJSON.c+754 parsers/test_cJSON/cJSON.h+153 parsers/test_cJSON/test-cJSON.xcodeproj/project.pbxproj+257 parsers/test_cJSON/test-cJSON.xcodeproj/project.xcworkspace/contents.xcworkspacedata+7 parsers/test_cJSON/test-cJSON.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstate parsers/test_cJSON/test-cJSON.xcodeproj/xcuserdata/nst.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist+5 parsers/test_cJSON/test-cJSON.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test-cJSON.xcscheme+91 parsers/test_cJSON/test-cJSON.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plist+22 parsers/test_cJSON/test-cJSON/main.c+69 parsers/test_ccan_json/bin/test_ccan parsers/test_ccan_json/json/_test/common.h+18 parsers/test_ccan_json/json/_test/nst_files/n_10.json+1 parsers/test_ccan_json/json/_test/nst_files/n_101.json+1 parsers/test_ccan_json/json/_test/nst_files/n_11.json+1 parsers/test_ccan_json/json/_test/nst_files/n_12.json+1 parsers/test_ccan_json/json/_test/nst_files/n_125.json+1 parsers/test_ccan_json/json/_test/nst_files/n_127.json+1 parsers/test_ccan_json/json/_test/nst_files/n_13.json+1 parsers/test_ccan_json/json/_test/nst_files/n_136.json+1 parsers/test_ccan_json/json/_test/nst_files/n_137.json+1 parsers/test_ccan_json/json/_test/nst_files/n_139.json+1 parsers/test_ccan_json/json/_test/nst_files/n_14.json+1 parsers/test_ccan_json/json/_test/nst_files/n_140.json+1 parsers/test_ccan_json/json/_test/nst_files/n_145.json+1 parsers/test_ccan_json/json/_test/nst_files/n_147.json+1 parsers/test_ccan_json/json/_test/nst_files/n_149.json+1 parsers/test_ccan_json/json/_test/nst_files/n_15.json+1 parsers/test_ccan_json/json/_test/nst_files/n_150.json+1 parsers/test_ccan_json/json/_test/nst_files/n_151.json+1 parsers/test_ccan_json/json/_test/nst_files/n_153.json+1 parsers/test_ccan_json/json/_test/nst_files/n_154.json+1 parsers/test_ccan_json/json/_test/nst_files/n_155.json+1 parsers/test_ccan_json/json/_test/nst_files/n_156.json+1 parsers/test_ccan_json/json/_test/nst_files/n_157.json+1 parsers/test_ccan_json/json/_test/nst_files/n_158.json+1 parsers/test_ccan_json/json/_test/nst_files/n_159.json+1 parsers/test_ccan_json/json/_test/nst_files/n_16.json+1 parsers/test_ccan_json/json/_test/nst_files/n_160.json+1 parsers/test_ccan_json/json/_test/nst_files/n_161.json+1 parsers/test_ccan_json/json/_test/nst_files/n_162.json+1 parsers/test_ccan_json/json/_test/nst_files/n_163.json+1 parsers/test_ccan_json/json/_test/nst_files/n_164.json+1 parsers/test_ccan_json/json/_test/nst_files/n_165.json+1 parsers/test_ccan_json/json/_test/nst_files/n_169.json+1 parsers/test_ccan_json/json/_test/nst_files/n_17.json+1 parsers/test_ccan_json/json/_test/nst_files/n_171.json+1 parsers/test_ccan_json/json/_test/nst_files/n_172.json+1 parsers/test_ccan_json/json/_test/nst_files/n_173.json+1 parsers/test_ccan_json/json/_test/nst_files/n_175.json+1 parsers/test_ccan_json/json/_test/nst_files/n_176.json+1 parsers/test_ccan_json/json/_test/nst_files/n_177.json+1 parsers/test_ccan_json/json/_test/nst_files/n_178.json+1 parsers/test_ccan_json/json/_test/nst_files/n_179.json+1 parsers/test_ccan_json/json/_test/nst_files/n_18.json+1 parsers/test_ccan_json/json/_test/nst_files/n_180.json+1 parsers/test_ccan_json/json/_test/nst_files/n_181.json+1 parsers/test_ccan_json/json/_test/nst_files/n_183.json+1 parsers/test_ccan_json/json/_test/nst_files/n_184.json+1 parsers/test_ccan_json/json/_test/nst_files/n_185.json+1 parsers/test_ccan_json/json/_test/nst_files/n_186.json+1 parsers/test_ccan_json/json/_test/nst_files/n_187.json+1 parsers/test_ccan_json/json/_test/nst_files/n_188.json+1 parsers/test_ccan_json/json/_test/nst_files/n_189.json+1 parsers/test_ccan_json/json/_test/nst_files/n_19.json+1 parsers/test_ccan_json/json/_test/nst_files/n_190.json+1 parsers/test_ccan_json/json/_test/nst_files/n_191.json+1 parsers/test_ccan_json/json/_test/nst_files/n_192.json+1 parsers/test_ccan_json/json/_test/nst_files/n_193.json+1 parsers/test_ccan_json/json/_test/nst_files/n_194.json+1 parsers/test_ccan_json/json/_test/nst_files/n_195.json+1 parsers/test_ccan_json/json/_test/nst_files/n_197.json+1 parsers/test_ccan_json/json/_test/nst_files/n_198.json+1 parsers/test_ccan_json/json/_test/nst_files/n_199.json+1 parsers/test_ccan_json/json/_test/nst_files/n_2.json+1 parsers/test_ccan_json/json/_test/nst_files/n_20.json+1 parsers/test_ccan_json/json/_test/nst_files/n_200.json+1 parsers/test_ccan_json/json/_test/nst_files/n_201.json+1 parsers/test_ccan_json/json/_test/nst_files/n_202.json+1 parsers/test_ccan_json/json/_test/nst_files/n_203.json+1 parsers/test_ccan_json/json/_test/nst_files/n_204.json+1 parsers/test_ccan_json/json/_test/nst_files/n_205.json+1 parsers/test_ccan_json/json/_test/nst_files/n_206.json+1 parsers/test_ccan_json/json/_test/nst_files/n_207.json+1 parsers/test_ccan_json/json/_test/nst_files/n_208.json+1 parsers/test_ccan_json/json/_test/nst_files/n_209.json+1 parsers/test_ccan_json/json/_test/nst_files/n_21.json+1 parsers/test_ccan_json/json/_test/nst_files/n_210.json+1 parsers/test_ccan_json/json/_test/nst_files/n_211.json+1 parsers/test_ccan_json/json/_test/nst_files/n_212.json+1 parsers/test_ccan_json/json/_test/nst_files/n_213.json+1 parsers/test_ccan_json/json/_test/nst_files/n_214.json+1 parsers/test_ccan_json/json/_test/nst_files/n_216.json+1 parsers/test_ccan_json/json/_test/nst_files/n_217.json+1 parsers/test_ccan_json/json/_test/nst_files/n_218.json+1 parsers/test_ccan_json/json/_test/nst_files/n_219.json+1 parsers/test_ccan_json/json/_test/nst_files/n_22.json+1 parsers/test_ccan_json/json/_test/nst_files/n_220.json+1 parsers/test_ccan_json/json/_test/nst_files/n_221.json+1 parsers/test_ccan_json/json/_test/nst_files/n_222.json+1 parsers/test_ccan_json/json/_test/nst_files/n_223.json+1 parsers/test_ccan_json/json/_test/nst_files/n_23.json+1 parsers/test_ccan_json/json/_test/nst_files/n_24.json+1 parsers/test_ccan_json/json/_test/nst_files/n_25.json+1 parsers/test_ccan_json/json/_test/nst_files/n_26.json+1 parsers/test_ccan_json/json/_test/nst_files/n_27.json+1 parsers/test_ccan_json/json/_test/nst_files/n_28.json+1 parsers/test_ccan_json/json/_test/nst_files/n_29.json+1 parsers/test_ccan_json/json/_test/nst_files/n_3.json+1 parsers/test_ccan_json/json/_test/nst_files/n_30.json+1 parsers/test_ccan_json/json/_test/nst_files/n_31.json+1 parsers/test_ccan_json/json/_test/nst_files/n_32.json+1 parsers/test_ccan_json/json/_test/nst_files/n_33.json+1 parsers/test_ccan_json/json/_test/nst_files/n_34.json+1 parsers/test_ccan_json/json/_test/nst_files/n_35.json+1 parsers/test_ccan_json/json/_test/nst_files/n_36.json+1 parsers/test_ccan_json/json/_test/nst_files/n_37.json+1 parsers/test_ccan_json/json/_test/nst_files/n_4.json+1 parsers/test_ccan_json/json/_test/nst_files/n_40.json+1 parsers/test_ccan_json/json/_test/nst_files/n_44.json+1 parsers/test_ccan_json/json/_test/nst_files/n_46.json+1 parsers/test_ccan_json/json/_test/nst_files/n_5.json+1 parsers/test_ccan_json/json/_test/nst_files/n_54.json+1 parsers/test_ccan_json/json/_test/nst_files/n_55.json+1 parsers/test_ccan_json/json/_test/nst_files/n_59.json+1 parsers/test_ccan_json/json/_test/nst_files/n_6.json+1 parsers/test_ccan_json/json/_test/nst_files/n_63.json+1 parsers/test_ccan_json/json/_test/nst_files/n_64.json+1 parsers/test_ccan_json/json/_test/nst_files/n_66.json+1 parsers/test_ccan_json/json/_test/nst_files/n_69.json+1 parsers/test_ccan_json/json/_test/nst_files/n_7.json+1 parsers/test_ccan_json/json/_test/nst_files/n_77.json+1 parsers/test_ccan_json/json/_test/nst_files/n_78.json+1 parsers/test_ccan_json/json/_test/nst_files/n_79.json+1 parsers/test_ccan_json/json/_test/nst_files/n_8.json+1 parsers/test_ccan_json/json/_test/nst_files/n_80.json+1 parsers/test_ccan_json/json/_test/nst_files/n_81.json+1 parsers/test_ccan_json/json/_test/nst_files/n_82.json+1 parsers/test_ccan_json/json/_test/nst_files/n_83.json+1 parsers/test_ccan_json/json/_test/nst_files/n_85.json+1 parsers/test_ccan_json/json/_test/nst_files/n_86.json+1 parsers/test_ccan_json/json/_test/nst_files/n_87.json+1 parsers/test_ccan_json/json/_test/nst_files/n_9.json+1 parsers/test_ccan_json/json/_test/nst_files/n_91.json+1 parsers/test_ccan_json/json/_test/nst_files/y_100.json+1 parsers/test_ccan_json/json/_test/nst_files/y_102.json+1 parsers/test_ccan_json/json/_test/nst_files/y_103.json+1 parsers/test_ccan_json/json/_test/nst_files/y_104.json+1 parsers/test_ccan_json/json/_test/nst_files/y_105.json+1 parsers/test_ccan_json/json/_test/nst_files/y_106.json+1 parsers/test_ccan_json/json/_test/nst_files/y_107.json+1 parsers/test_ccan_json/json/_test/nst_files/y_108.json+1 parsers/test_ccan_json/json/_test/nst_files/y_109.json+1 parsers/test_ccan_json/json/_test/nst_files/y_110.json+1 parsers/test_ccan_json/json/_test/nst_files/y_111.json+1 parsers/test_ccan_json/json/_test/nst_files/y_112.json+1 parsers/test_ccan_json/json/_test/nst_files/y_113.json+1 parsers/test_ccan_json/json/_test/nst_files/y_114.json+1 parsers/test_ccan_json/json/_test/nst_files/y_115.json+1 parsers/test_ccan_json/json/_test/nst_files/y_116.json+1 parsers/test_ccan_json/json/_test/nst_files/y_117.json+1 parsers/test_ccan_json/json/_test/nst_files/y_118.json+1 parsers/test_ccan_json/json/_test/nst_files/y_119.json+1 parsers/test_ccan_json/json/_test/nst_files/y_120.json+1 parsers/test_ccan_json/json/_test/nst_files/y_121.json+1 parsers/test_ccan_json/json/_test/nst_files/y_122.json+1 parsers/test_ccan_json/json/_test/nst_files/y_123.json+1 parsers/test_ccan_json/json/_test/nst_files/y_124.json+1 parsers/test_ccan_json/json/_test/nst_files/y_126.json+1 parsers/test_ccan_json/json/_test/nst_files/y_128.json+1 parsers/test_ccan_json/json/_test/nst_files/y_129.json+1 parsers/test_ccan_json/json/_test/nst_files/y_130.json+1 parsers/test_ccan_json/json/_test/nst_files/y_131.json+1 parsers/test_ccan_json/json/_test/nst_files/y_132.json+1 parsers/test_ccan_json/json/_test/nst_files/y_133.json+1 parsers/test_ccan_json/json/_test/nst_files/y_134.json+1 parsers/test_ccan_json/json/_test/nst_files/y_135.json+1 parsers/test_ccan_json/json/_test/nst_files/y_138.json+1 parsers/test_ccan_json/json/_test/nst_files/y_141.json+1 parsers/test_ccan_json/json/_test/nst_files/y_142.json+1 parsers/test_ccan_json/json/_test/nst_files/y_143.json+1 parsers/test_ccan_json/json/_test/nst_files/y_144.json+1 parsers/test_ccan_json/json/_test/nst_files/y_146.json+1 parsers/test_ccan_json/json/_test/nst_files/y_148.json+1 parsers/test_ccan_json/json/_test/nst_files/y_152.json+1 parsers/test_ccan_json/json/_test/nst_files/y_166.json+1 parsers/test_ccan_json/json/_test/nst_files/y_167.json+1 parsers/test_ccan_json/json/_test/nst_files/y_168.json+1 parsers/test_ccan_json/json/_test/nst_files/y_170.json+1 parsers/test_ccan_json/json/_test/nst_files/y_174.json+1 parsers/test_ccan_json/json/_test/nst_files/y_182.json+1 parsers/test_ccan_json/json/_test/nst_files/y_196.json+1 parsers/test_ccan_json/json/_test/nst_files/y_215.json+1 parsers/test_ccan_json/json/_test/nst_files/y_38.json+1 parsers/test_ccan_json/json/_test/nst_files/y_39.json+1 parsers/test_ccan_json/json/_test/nst_files/y_41.json+1 parsers/test_ccan_json/json/_test/nst_files/y_42.json+1 parsers/test_ccan_json/json/_test/nst_files/y_43.json+1 parsers/test_ccan_json/json/_test/nst_files/y_45.json+1 parsers/test_ccan_json/json/_test/nst_files/y_47.json+1 parsers/test_ccan_json/json/_test/nst_files/y_48.json+1 parsers/test_ccan_json/json/_test/nst_files/y_49.json+1 parsers/test_ccan_json/json/_test/nst_files/y_50.json+1 parsers/test_ccan_json/json/_test/nst_files/y_51.json+1 parsers/test_ccan_json/json/_test/nst_files/y_52.json+1 parsers/test_ccan_json/json/_test/nst_files/y_53.json+1 parsers/test_ccan_json/json/_test/nst_files/y_56.json+1 parsers/test_ccan_json/json/_test/nst_files/y_57.json+1 parsers/test_ccan_json/json/_test/nst_files/y_58.json+1 parsers/test_ccan_json/json/_test/nst_files/y_60.json+1 parsers/test_ccan_json/json/_test/nst_files/y_61.json+1 parsers/test_ccan_json/json/_test/nst_files/y_62.json+1 parsers/test_ccan_json/json/_test/nst_files/y_65.json+1 parsers/test_ccan_json/json/_test/nst_files/y_67.json+1 parsers/test_ccan_json/json/_test/nst_files/y_68.json+1 parsers/test_ccan_json/json/_test/nst_files/y_70.json+1 parsers/test_ccan_json/json/_test/nst_files/y_71.json+1 parsers/test_ccan_json/json/_test/nst_files/y_72.json+1 parsers/test_ccan_json/json/_test/nst_files/y_73.json+1 parsers/test_ccan_json/json/_test/nst_files/y_74.json+1 parsers/test_ccan_json/json/_test/nst_files/y_75.json+1 parsers/test_ccan_json/json/_test/nst_files/y_76.json+1 parsers/test_ccan_json/json/_test/nst_files/y_84.json+1 parsers/test_ccan_json/json/_test/nst_files/y_88.json+1 parsers/test_ccan_json/json/_test/nst_files/y_89.json+1 parsers/test_ccan_json/json/_test/nst_files/y_90.json+1 parsers/test_ccan_json/json/_test/nst_files/y_92.json+1 parsers/test_ccan_json/json/_test/nst_files/y_93.json+1 parsers/test_ccan_json/json/_test/nst_files/y_94.json+1 parsers/test_ccan_json/json/_test/nst_files/y_95.json+1 parsers/test_ccan_json/json/_test/nst_files/y_96.json+1 parsers/test_ccan_json/json/_test/nst_files/y_97.json+1 parsers/test_ccan_json/json/_test/nst_files/y_98.json+1 parsers/test_ccan_json/json/_test/nst_files/y_99.json+1 parsers/test_ccan_json/json/_test/run-construction.c+191 parsers/test_ccan_json/json/_test/run-decode-encode.c+77 parsers/test_ccan_json/json/_test/run-stringify.c+108 parsers/test_ccan_json/json/_test/run-validate.c+49 parsers/test_ccan_json/json/_test/test-strings+224 parsers/test_ccan_json/json/_test/test-strings-reencoded+90 parsers/test_ccan_json/json/_test/x.py+21 parsers/test_ccan_json/json/json.c+1381 parsers/test_ccan_json/json/json.h+117 parsers/test_ccan_json/test_ccan/test_ccan.xcodeproj/project.pbxproj+262 parsers/test_ccan_json/test_ccan/test_ccan.xcodeproj/project.xcworkspace/contents.xcworkspacedata+7 parsers/test_ccan_json/test_ccan/test_ccan.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstate parsers/test_ccan_json/test_ccan/test_ccan.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test_ccan.xcscheme+91 parsers/test_ccan_json/test_ccan/test_ccan.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plist+22 parsers/test_ccan_json/test_ccan/test_ccan/main.c+44 parsers/test_dkjson.lua+25 parsers/test_go/test_json parsers/test_go/test_json.go+30 parsers/test_jansson/bin/test_jansson parsers/test_jansson/dump.c+467 parsers/test_jansson/error.c+63 parsers/test_jansson/hashtable.c+356 parsers/test_jansson/hashtable.h+184 parsers/test_jansson/hashtable_seed.c+277 parsers/test_jansson/jansson.h+298 parsers/test_jansson/jansson_config.h+43 parsers/test_jansson/jansson_private.h+109 parsers/test_jansson/load.c+1110 parsers/test_jansson/lookup3.h+381 parsers/test_jansson/memory.c+69 parsers/test_jansson/pack_unpack.c+871 parsers/test_jansson/strbuffer.c+111 parsers/test_jansson/strbuffer.h+34 parsers/test_jansson/strconv.c+145 parsers/test_jansson/test_jansson.xcodeproj/project.pbxproj+309 parsers/test_jansson/test_jansson.xcodeproj/project.xcworkspace/contents.xcworkspacedata+7 parsers/test_jansson/test_jansson.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstate parsers/test_jansson/test_jansson.xcodeproj/xcuserdata/nst.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist+5 parsers/test_jansson/test_jansson.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test_jansson.xcscheme+91 parsers/test_jansson/test_jansson.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plist+22 parsers/test_jansson/test_jansson/main.c+208 parsers/test_jansson/utf.c+187 parsers/test_jansson/utf.h+27 parsers/test_jansson/value.c+1048 parsers/test_jsmn/bin/test_jsmn parsers/test_jsmn/jsmn.c+311 parsers/test_jsmn/jsmn.h+76 parsers/test_jsmn/test_jsmn/test_jsmn.xcodeproj/project.pbxproj+253 parsers/test_jsmn/test_jsmn/test_jsmn.xcodeproj/project.xcworkspace/contents.xcworkspacedata+7 parsers/test_jsmn/test_jsmn/test_jsmn.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstate parsers/test_jsmn/test_jsmn/test_jsmn.xcodeproj/xcuserdata/nst.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist+23 parsers/test_jsmn/test_jsmn/test_jsmn.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test_jsmn.xcscheme+101 parsers/test_jsmn/test_jsmn/test_jsmn.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plist+22 parsers/test_jsmn/test_jsmn/test_jsmn/main.c+50 parsers/test_json-jq.py+34 parsers/test_json-parser/bin/test_json-parser parsers/test_json-parser/test_json-parser.xcodeproj/project.pbxproj+258 parsers/test_json-parser/test_json-parser.xcodeproj/project.xcworkspace/contents.xcworkspacedata+7 parsers/test_json-parser/test_json-parser.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstate parsers/test_json-parser/test_json-parser.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test_json-parser.xcscheme+91 parsers/test_json-parser/test_json-parser.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plist+22 parsers/test_json-parser/test_json-parser/json.c+1011 parsers/test_json-parser/test_json-parser/json.h+283 parsers/test_json-parser/test_json-parser/main.c+66 parsers/test_json-rust/Cargo.lock+14 parsers/test_json-rust/Cargo.toml+7 parsers/test_json-rust/README+2 parsers/test_json-rust/src/main.rs+42 parsers/test_json-rust/target/debug/.cargo-lock parsers/test_json-rust/target/debug/.fingerprint/json-74a82b4ec4439e90/dep-lib-json parsers/test_json-rust/target/debug/.fingerprint/json-74a82b4ec4439e90/lib-json+1 parsers/test_json-rust/target/debug/.fingerprint/json-74a82b4ec4439e90/lib-json.json+1 parsers/test_json-rust/target/debug/.fingerprint/tj-b5d63a9d8da2968e/bin-tj+1 parsers/test_json-rust/target/debug/.fingerprint/tj-b5d63a9d8da2968e/bin-tj.json+1 parsers/test_json-rust/target/debug/.fingerprint/tj-b5d63a9d8da2968e/dep-bin-tj parsers/test_json-rust/target/debug/.fingerprint/tj-bb890ae6f101bb25/bin-tj+1 parsers/test_json-rust/target/debug/.fingerprint/tj-bb890ae6f101bb25/bin-tj.json+1 parsers/test_json-rust/target/debug/.fingerprint/tj-bb890ae6f101bb25/dep-bin-tj parsers/test_json-rust/target/debug/.fingerprint/tj-bf24d0bdc8d0f4d6/bin-tj+1 parsers/test_json-rust/target/debug/.fingerprint/tj-bf24d0bdc8d0f4d6/bin-tj.json+1 parsers/test_json-rust/target/debug/.fingerprint/tj-bf24d0bdc8d0f4d6/dep-bin-tj parsers/test_json-rust/target/debug/deps/libjson-6bbf4c11dd6d7c25.rlib parsers/test_json-rust/target/debug/tj parsers/test_json-rust/target/debug/tj.dSYM/Contents/Info.plist+20 parsers/test_json-rust/target/debug/tj.dSYM/Contents/Resources/DWARF/tj parsers/test_json-rustc_serialize/rj/Cargo.lock+14 parsers/test_json-rustc_serialize/rj/Cargo.toml+7 parsers/test_json-rustc_serialize/rj/README+2 parsers/test_json-rustc_serialize/rj/src/main.rs+32 parsers/test_json-rustc_serialize/rj/target/debug/.cargo-lock parsers/test_json-rustc_serialize/rj/target/debug/.fingerprint/rj-8f8b750d20f3bf10/bin-rj+1 parsers/test_json-rustc_serialize/rj/target/debug/.fingerprint/rj-8f8b750d20f3bf10/bin-rj.json+1 parsers/test_json-rustc_serialize/rj/target/debug/.fingerprint/rj-8f8b750d20f3bf10/dep-bin-rj parsers/test_json-rustc_serialize/rj/target/debug/.fingerprint/rj-da0f8f63b87cf531/bin-rj+1 parsers/test_json-rustc_serialize/rj/target/debug/.fingerprint/rj-da0f8f63b87cf531/bin-rj.json+1 parsers/test_json-rustc_serialize/rj/target/debug/.fingerprint/rj-da0f8f63b87cf531/dep-bin-rj parsers/test_json-rustc_serialize/rj/target/debug/.fingerprint/rustc-serialize-80c565222c5ccdbb/dep-lib-rustc-serialize parsers/test_json-rustc_serialize/rj/target/debug/.fingerprint/rustc-serialize-80c565222c5ccdbb/lib-rustc-serialize+1 parsers/test_json-rustc_serialize/rj/target/debug/.fingerprint/rustc-serialize-80c565222c5ccdbb/lib-rustc-serialize.json+1 parsers/test_json-rustc_serialize/rj/target/debug/deps/librustc_serialize-3561541d79c18212.rlib parsers/test_json-rustc_serialize/rj/target/debug/rj parsers/test_json-rustc_serialize/rj/target/debug/rj.dSYM/Contents/Info.plist+20 parsers/test_json-rustc_serialize/rj/target/debug/rj.dSYM/Contents/Resources/DWARF/rj parsers/test_json.js+13 parsers/test_json.php+21 parsers/test_json.pl+32 parsers/test_json.py+39 parsers/test_json.rb+23 parsers/test_jsonChecker/bin/jsonChecker parsers/test_jsonChecker/jsonChecker/JSON_checker.c+400 parsers/test_jsonChecker/jsonChecker/JSON_checker.h+13 parsers/test_jsonChecker/jsonChecker/jsonChecker.xcodeproj/project.pbxproj+253 parsers/test_jsonChecker/jsonChecker/jsonChecker.xcodeproj/project.xcworkspace/contents.xcworkspacedata+7 parsers/test_jsonChecker/jsonChecker/jsonChecker.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstate parsers/test_jsonChecker/jsonChecker/jsonChecker.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/jsonChecker.xcscheme+91 parsers/test_jsonChecker/jsonChecker/jsonChecker.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plist+22 parsers/test_jsonChecker/jsonChecker/jsonChecker/main.c+53 parsers/test_jsonChecker2/FSM.rtf+57 parsers/test_jsonChecker2/bin/jsonChecker2 parsers/test_jsonChecker2/jsonChecker2/JSON_checker.c+402 parsers/test_jsonChecker2/jsonChecker2/JSON_checker.h+13 parsers/test_jsonChecker2/jsonChecker2/jsonChecker/main.c+53 parsers/test_jsonChecker2/jsonChecker2/jsonChecker2.xcodeproj/project.pbxproj+253 parsers/test_jsonChecker2/jsonChecker2/jsonChecker2.xcodeproj/project.xcworkspace/contents.xcworkspacedata+7 parsers/test_jsonChecker2/jsonChecker2/jsonChecker2.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstate parsers/test_jsonChecker2/jsonChecker2/jsonChecker2.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/jsonChecker.xcscheme+97 parsers/test_jsonChecker2/jsonChecker2/jsonChecker2.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plist+22 parsers/test_json_re.rb+33 parsers/test_json_xs.pl+28 parsers/test_jsonlite.r+7 parsers/test_rjson.r+7 results/logs.txt+1423 results/parsing.html+2149 results/parsing_pruned.html+146 results/pruned_results.png results/style.css+89 results/transform.html+1492 run_tests.py+583 test_parsing/i_number_neg_int_huge_exp.json+1 test_parsing/i_number_pos_double_huge_exp.json+1 test_parsing/i_object_key_lone_2nd_surrogate.json+1 test_parsing/i_string_1st_surrogate_but_2nd_missing.json+1 test_parsing/i_string_1st_valid_surrogate_2nd_invalid.json+1 test_parsing/i_string_UTF-16_invalid_lonely_surrogate.json+1 test_parsing/i_string_UTF-16_invalid_surrogate.json+1 test_parsing/i_string_UTF-8_invalid_sequence.json+1 test_parsing/i_string_incomplete_surrogate_and_escape_valid.json+1 test_parsing/i_string_incomplete_surrogate_pair.json+1 test_parsing/i_string_incomplete_surrogates_escape_valid.json+1 test_parsing/i_string_inverted_surrogates_U+1D11E.json+1 test_parsing/i_string_lone_second_surrogate.json+1 test_parsing/i_string_not_in_unicode_range.json+1 test_parsing/i_string_truncated-utf-8.json+1 test_parsing/i_string_unicode_U+10FFFE_nonchar.json+1 test_parsing/i_string_unicode_U+1FFFE_nonchar.json+1 test_parsing/i_string_unicode_U+FDD0_nonchar.json+1 test_parsing/i_string_unicode_U+FFFE_nonchar.json+1 test_parsing/i_structure_500_nested_arrays.json+1 test_parsing/i_structure_UTF-8_BOM_empty_object.json+1 test_parsing/n_array_1_true_without_comma.json+1 test_parsing/n_array_colon_instead_of_comma.json+1 test_parsing/n_array_comma_after_close.json+1 test_parsing/n_array_comma_and_number.json+1 test_parsing/n_array_double_comma.json+1 test_parsing/n_array_double_extra_comma.json+1 test_parsing/n_array_extra_close.json+1 test_parsing/n_array_extra_comma.json+1 test_parsing/n_array_incomplete.json+1 test_parsing/n_array_incomplete_invalid_value.json+1 test_parsing/n_array_inner_array_no_comma.json+1 test_parsing/n_array_invalid-utf-8-in-identifier.json+1 test_parsing/n_array_invalid_utf8.json+1 test_parsing/n_array_items_separated_by_semicolon.json+1 test_parsing/n_array_just_comma.json+1 test_parsing/n_array_just_minus.json+1 test_parsing/n_array_missing_value.json+1 test_parsing/n_array_newlines_unclosed.json+3 test_parsing/n_array_number_and_comma.json+1 test_parsing/n_array_number_and_several_commas.json+1 test_parsing/n_array_spaces_vertical_tab_formfeed.json+1 test_parsing/n_array_star_inside.json+1 test_parsing/n_array_unclosed.json+1 test_parsing/n_array_unclosed_trailing_comma.json+1 test_parsing/n_array_unclosed_with_new_lines.json+3 test_parsing/n_array_unclosed_with_object_inside.json+1 test_parsing/n_incomplete_false.json+1 test_parsing/n_incomplete_null.json+1 test_parsing/n_incomplete_true.json+1 test_parsing/n_number_++.json+1 test_parsing/n_number_+1.json+1 test_parsing/n_number_+Inf.json+1 test_parsing/n_number_-01.json+1 test_parsing/n_number_-1.0..json+1 test_parsing/n_number_-2..json+1 test_parsing/n_number_-NaN.json+1 test_parsing/n_number_.-1.json+1 test_parsing/n_number_.2e-3.json+1 test_parsing/n_number_0.1.2.json+1 test_parsing/n_number_0.3e+.json+1 test_parsing/n_number_0.3e.json+1 test_parsing/n_number_0.e1.json+1 test_parsing/n_number_0_capital_E+.json+1 test_parsing/n_number_0_capital_E.json+1 test_parsing/n_number_0e+.json+1 test_parsing/n_number_0e.json+1 test_parsing/n_number_1.0e+.json+1 test_parsing/n_number_1.0e-.json+1 test_parsing/n_number_1.0e.json+1 test_parsing/n_number_1_000.json+1 test_parsing/n_number_1eE2.json+1 test_parsing/n_number_2.e+3.json+1 test_parsing/n_number_2.e-3.json+1 test_parsing/n_number_2.e3.json+1 test_parsing/n_number_9.e+.json+1 test_parsing/n_number_Inf.json+1 test_parsing/n_number_NaN.json+1 test_parsing/n_number_U+FF11_fullwidth_digit_one.json+1 test_parsing/n_number_expression.json+1 test_parsing/n_number_hex_1_digit.json+1 test_parsing/n_number_hex_2_digits.json+1 test_parsing/n_number_infinity.json+1 test_parsing/n_number_invalid+-.json+1 test_parsing/n_number_invalid-negative-real.json+1 test_parsing/n_number_invalid-utf-8-in-bigger-int.json+1 test_parsing/n_number_invalid-utf-8-in-exponent.json+1 test_parsing/n_number_invalid-utf-8-in-int.json+1 test_parsing/n_number_minus_infinity.json+1 test_parsing/n_number_minus_sign_with_trailing_garbage.json+1 test_parsing/n_number_minus_space_1.json+1 test_parsing/n_number_neg_int_starting_with_zero.json+1 test_parsing/n_number_neg_real_without_int_part.json+1 test_parsing/n_number_neg_with_garbage_at_end.json+1 test_parsing/n_number_real_garbage_after_e.json+1 test_parsing/n_number_real_with_invalid_utf8_after_e.json+1 test_parsing/n_number_real_without_fractional_part.json+1 test_parsing/n_number_starting_with_dot.json+1 test_parsing/n_number_then_00.json test_parsing/n_number_with_alpha.json+1 test_parsing/n_number_with_alpha_char.json+1 test_parsing/n_number_with_leading_zero.json+1 test_parsing/n_object_bad_value.json+1 test_parsing/n_object_bracket_key.json+1 test_parsing/n_object_comma_instead_of_colon.json+1 test_parsing/n_object_double_colon.json+1 test_parsing/n_object_emoji.json+1 test_parsing/n_object_garbage_at_end.json+1 test_parsing/n_object_key_with_single_quotes.json+1 test_parsing/n_object_missing_colon.json+1 test_parsing/n_object_missing_key.json+1 test_parsing/n_object_missing_semicolon.json+1 test_parsing/n_object_missing_value.json+1 test_parsing/n_object_no-colon.json+1 test_parsing/n_object_non_string_key.json+1 test_parsing/n_object_non_string_key_but_huge_number_instead.json+1 test_parsing/n_object_pi_in_key_and_trailing_comma.json+1 test_parsing/n_object_repeated_null_null.json+1 test_parsing/n_object_several_trailing_commas.json+1 test_parsing/n_object_single_quote.json+1 test_parsing/n_object_trailing_comma.json+1 test_parsing/n_object_trailing_comment.json+1 test_parsing/n_object_trailing_comment_open.json+1 test_parsing/n_object_trailing_comment_slash_open.json+1 test_parsing/n_object_trailing_comment_slash_open_incomplete.json+1 test_parsing/n_object_two_commas_in_a_row.json+1 test_parsing/n_object_unquoted_key.json+1 test_parsing/n_object_unterminated-value.json+1 test_parsing/n_object_with_single_string.json+1 test_parsing/n_object_with_trailing_garbage.json+1 test_parsing/n_single_space.json+1 test_parsing/n_string_1_surrogate_then_escape u.json+1 test_parsing/n_string_1_surrogate_then_escape u1.json+1 test_parsing/n_string_1_surrogate_then_escape u1x.json+1 test_parsing/n_string_1_surrogate_then_escape.json+1 test_parsing/n_string_UTF-16_incomplete_surrogate.json+1 test_parsing/n_string_UTF8_surrogate_U+D800.json+1 test_parsing/n_string_accentuated_char_no_quotes.json+1 test_parsing/n_string_backslash_00.json test_parsing/n_string_escape_x.json+1 test_parsing/n_string_escaped_backslash_bad.json+1 test_parsing/n_string_escaped_ctrl_char_tab.json+1 test_parsing/n_string_escaped_emoji.json+1 test_parsing/n_string_incomplete_escape.json+1 test_parsing/n_string_incomplete_escaped_character.json+1 test_parsing/n_string_incomplete_surrogate_escape_invalid.json+1 test_parsing/n_string_invalid-utf-8-in-escape.json+1 test_parsing/n_string_invalid_backslash_esc.json+1 test_parsing/n_string_invalid_unicode_escape.json+1 test_parsing/n_string_invalid_utf-8.json+1 test_parsing/n_string_invalid_utf8_after_escape.json+1 test_parsing/n_string_iso_latin_1.json+1 test_parsing/n_string_leading_uescaped_thinspace.json+1 test_parsing/n_string_lone_utf8_continuation_byte.json+1 test_parsing/n_string_no_quotes_with_bad_escape.json+1 test_parsing/n_string_overlong_sequence_2_bytes.json+1 test_parsing/n_string_overlong_sequence_6_bytes.json+1 test_parsing/n_string_overlong_sequence_6_bytes_null.json+1 test_parsing/n_string_single_doublequote.json+1 test_parsing/n_string_single_quote.json+1 test_parsing/n_string_single_string_no_double_quotes.json+1 test_parsing/n_string_start_escape_unclosed.json+1 test_parsing/n_string_unescaped_crtl_char.json test_parsing/n_string_unescaped_newline.json+2 test_parsing/n_string_unescaped_tab.json+1 test_parsing/n_string_unicode_CapitalU.json+1 test_parsing/n_string_with_trailing_garbage.json+1 test_parsing/n_structure_100000_opening_arrays.json+1 test_parsing/n_structure_<.>.json+1 test_parsing/n_structure_<null>.json+1 test_parsing/n_structure_U+2060_word_joined.json+1 test_parsing/n_structure_UTF8_BOM_no_data.json+1 test_parsing/n_structure_array_trailing_garbage.json+1 test_parsing/n_structure_array_with_extra_array_close.json+1 test_parsing/n_structure_array_with_unclosed_string.json+1 test_parsing/n_structure_ascii-unicode-identifier.json+1 test_parsing/n_structure_capitalized_True.json+1 test_parsing/n_structure_close_unopened_array.json+1 test_parsing/n_structure_comma_instead_of_closing_brace.json+1 test_parsing/n_structure_double_array.json+1 test_parsing/n_structure_end_array.json+1 test_parsing/n_structure_incomplete_UTF8_BOM.json+1 test_parsing/n_structure_lone-invalid-utf-8.json+1 test_parsing/n_structure_lone-open-bracket.json+1 test_parsing/n_structure_no_data.json test_parsing/n_structure_null-byte-outside-string.json test_parsing/n_structure_number_with_trailing_garbage.json+1 test_parsing/n_structure_object_followed_by_closing_object.json+1 test_parsing/n_structure_object_unclosed_no_value.json+1 test_parsing/n_structure_object_with_comment.json+1 test_parsing/n_structure_object_with_trailing_garbage.json+1 test_parsing/n_structure_open_array_apostrophe.json+1 test_parsing/n_structure_open_array_comma.json+1 test_parsing/n_structure_open_array_object.json+1 test_parsing/n_structure_open_array_open_object.json+1 test_parsing/n_structure_open_array_open_string.json+1 test_parsing/n_structure_open_array_string.json+1 test_parsing/n_structure_open_object.json+1 test_parsing/n_structure_open_object_close_array.json+1 test_parsing/n_structure_open_object_comma.json+1 test_parsing/n_structure_open_object_open_array.json+1 test_parsing/n_structure_open_object_open_string.json+1 test_parsing/n_structure_open_object_string_with_apostrophes.json+1 test_parsing/n_structure_open_open.json+1 test_parsing/n_structure_single_point.json+1 test_parsing/n_structure_single_star.json+1 test_parsing/n_structure_trailing_#.json+1 test_parsing/n_structure_uescaped_LF_before_string.json+1 test_parsing/n_structure_unclosed_array.json+1 test_parsing/n_structure_unclosed_array_partial_null.json+1 test_parsing/n_structure_unclosed_array_unfinished_false.json+1 test_parsing/n_structure_unclosed_array_unfinished_true.json+1 test_parsing/n_structure_unclosed_object.json+1 test_parsing/n_structure_unicode-identifier.json+1 test_parsing/n_structure_whitespace_U+2060_word_joiner.json+1 test_parsing/n_structure_whitespace_formfeed.json+1 test_parsing/y_array_arraysWithSpaces.json+1 test_parsing/y_array_empty-string.json+1 test_parsing/y_array_empty.json+1 test_parsing/y_array_ending_with_newline.json+1 test_parsing/y_array_false.json+1 test_parsing/y_array_heterogeneous.json+1 test_parsing/y_array_null.json+1 test_parsing/y_array_with_1_and_newline.json+2 test_parsing/y_array_with_leading_space.json+1 test_parsing/y_array_with_several_null.json+1 test_parsing/y_array_with_trailing_space.json+1 test_parsing/y_number.json+1 test_parsing/y_number_0e+1.json+1 test_parsing/y_number_0e1.json+1 test_parsing/y_number_after_space.json+1 test_parsing/y_number_double_close_to_zero.json+1 test_parsing/y_number_double_huge_neg_exp.json+1 test_parsing/y_number_huge_exp.json+1 test_parsing/y_number_int_with_exp.json+1 test_parsing/y_number_minus_zero.json+1 test_parsing/y_number_negative_int.json+1 test_parsing/y_number_negative_one.json+1 test_parsing/y_number_negative_zero.json+1 test_parsing/y_number_real_capital_e.json+1 test_parsing/y_number_real_capital_e_neg_exp.json+1 test_parsing/y_number_real_capital_e_pos_exp.json+1 test_parsing/y_number_real_exponent.json+1 test_parsing/y_number_real_fraction_exponent.json+1 test_parsing/y_number_real_neg_exp.json+1 test_parsing/y_number_real_neg_overflow.json+1 test_parsing/y_number_real_pos_exponent.json+1 test_parsing/y_number_real_pos_overflow.json+1 test_parsing/y_number_real_underflow.json+1 test_parsing/y_number_simple_int.json+1 test_parsing/y_number_simple_real.json+1 test_parsing/y_number_too_big_neg_int.json+1 test_parsing/y_number_too_big_pos_int.json+1 test_parsing/y_number_very_big_negative_int.json+1 test_parsing/y_object.json+1 test_parsing/y_object_basic.json+1 test_parsing/y_object_duplicated_key.json+1 test_parsing/y_object_duplicated_key_and_value.json+1 test_parsing/y_object_empty.json+1 test_parsing/y_object_empty_key.json+1 test_parsing/y_object_escaped_null_in_key.json+1 test_parsing/y_object_extreme_numbers.json+1 test_parsing/y_object_long_strings.json+1 test_parsing/y_object_simple.json+1 test_parsing/y_object_string_unicode.json+1 test_parsing/y_object_with_newlines.json+3 test_parsing/y_string_1_2_3_bytes_UTF-8_sequences.json+1 test_parsing/y_string_UTF-16_Surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF.json+1 test_parsing/y_string_accepted_surrogate_pair.json+1 test_parsing/y_string_accepted_surrogate_pairs.json+1 test_parsing/y_string_allowed_escapes.json+1 test_parsing/y_string_backslash_and_u_escaped_zero.json+1 test_parsing/y_string_backslash_doublequotes.json+1 test_parsing/y_string_comments.json+1 test_parsing/y_string_double_escape_a.json+1 test_parsing/y_string_double_escape_n.json+1 test_parsing/y_string_escaped_control_character.json+1 test_parsing/y_string_escaped_noncharacter.json+1 test_parsing/y_string_in_array.json+1 test_parsing/y_string_in_array_with_leading_space.json+1 test_parsing/y_string_last_surrogates_1_and_2.json+1 test_parsing/y_string_newline_uescaped.json+1 test_parsing/y_string_nonCharacterInUTF-8_U+10FFFF.json+1 test_parsing/y_string_nonCharacterInUTF-8_U+1FFFF.json+1 test_parsing/y_string_nonCharacterInUTF-8_U+FFFF.json+1 test_parsing/y_string_null_escape.json+1 test_parsing/y_string_one-byte-utf-8.json+1 test_parsing/y_string_pi.json+1 test_parsing/y_string_simple_ascii.json+1 test_parsing/y_string_space.json+1 test_parsing/y_string_three-byte-utf-8.json+1 test_parsing/y_string_two-byte-utf-8.json+1 test_parsing/y_string_u+2028_line_sep.json+1 test_parsing/y_string_u+2029_par_sep.json+1 test_parsing/y_string_uEscape.json+1 test_parsing/y_string_unescaped_char_delete.json+1 test_parsing/y_string_unicode.json+1 test_parsing/y_string_unicodeEscapedBackslash.json+1 test_parsing/y_string_unicode_2.json+1 test_parsing/y_string_unicode_U+200B_ZERO_WIDTH_SPACE.json+1 test_parsing/y_string_unicode_U+2064_invisible_plus.json+1 test_parsing/y_string_unicode_escaped_double_quote.json+1 test_parsing/y_string_utf16.json test_parsing/y_string_utf8.json+1 test_parsing/y_string_with_del_character.json+1 test_parsing/y_structure_lonely_false.json+1 test_parsing/y_structure_lonely_int.json+1 test_parsing/y_structure_lonely_negative_real.json+1 test_parsing/y_structure_lonely_null.json+1 test_parsing/y_structure_lonely_string.json+1 test_parsing/y_structure_lonely_true.json+1 test_parsing/y_structure_string_empty.json+1 test_parsing/y_structure_trailing_newline.json+1 test_parsing/y_structure_true_in_array.json+1 test_parsing/y_structure_whitespace_array.json+1 test_transform/number_1.0.json+1 test_transform/number_1.000000000000000005.json+1 test_transform/number_1000000000000000.json+1 test_transform/number_10000000000000000999.json+1 test_transform/number_1e-999.json+1 test_transform/number_1e6.json+1 test_transform/object_key_nfc_nfd.json+1 test_transform/object_key_nfd_nfc.json+1 test_transform/object_same_key_different_values.json+1 test_transform/object_same_key_same_value.json+1 test_transform/object_same_key_unclear_values.json+1 test_transform/string_1_escaped_invalid_codepoint.json+1 test_transform/string_1_invalid_codepoint.json+1 test_transform/string_2_escaped_invalid_codepoints.json+1 test_transform/string_2_invalid_codepoints.json+1 test_transform/string_3_escaped_invalid_codepoints.json+1 test_transform/string_3_invalid_codepoints.json+1 test_transform/string_with_escaped_NULL.json+1
README.md+49−1
@@ -1,2 +1,50 @@
1−# JSONTestSuite
1+# JSON Parsing Test Suite
22A comprehensive test suite for RFC 7159 compliant JSON parsers
3+
4+This repository was created as an appendix to the article [Parsing JSON is a Minefield 💣](http://seriot.ch/parsing_json.php).
5+
6+**/parsers/**
7+
8+This directory contains several parsers and tiny wrappers to turn the parsers into JSON validators, by returning a specific value.
9+
10+- `0` the parser did accept the content
11+- `1` the parser did reject the content
12+- `>=1` the process did crash
13+- `timeout` happens after 5 seconds
14+
15+**/test\_parsing/**
16+
17+The name of these files tell if their contents should be accepted or rejected.
18+
19+- `y_` content must be accepted by parsers
20+- `n_` content must be rejected by parsers
21+- `i_` parsers are free to accept or reject content
22+
23+**/test\_transform/**
24+
25+These files contain weird structures and characters that parsers may understand differently, eg:
26+
27+- huge numbers
28+- dictionaries with similar keys
29+- NULL characters
30+- escaped invalid strings
31+
32+These files were used to produce `results/transform.html`.
33+
34+**/run_tests.py**
35+
36+Run all parsers with all files:
37+
38+ $ python3 run_tests.py
39+
40+Run all parsers with a specific file:
41+
42+ $ python3 run_tests.py file.json
43+
44+The script writes logs in `results/logs.txt`.
45+
46+The script then reads `logs.txt` and generates `results/parsing.html`.
47+
48+**/results/**
49+
50+<img src="results/pruned_results.png" alt="JSON Parsing Tests" />
parsers/test-AppleJSONSerialization/bin/test-AppleJSONSerializationnew file

Binary file not shown.

parsers/test-AppleJSONSerialization/test-AppleJSONSerialization.xcodeproj/project.pbxprojnew file+260
@@ -0,0 +1,260 @@
1+// !$*UTF8*$!
2+{
3+ archiveVersion = 1;
4+ classes = {
5+ };
6+ objectVersion = 46;
7+ objects = {
8+
9+/* Begin PBXBuildFile section */
10+ 03997F941D70CE0C0001C89F /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03997F931D70CE0C0001C89F /* main.swift */; };
11+/* End PBXBuildFile section */
12+
13+/* Begin PBXCopyFilesBuildPhase section */
14+ 03997F8E1D70CE0C0001C89F /* CopyFiles */ = {
15+ isa = PBXCopyFilesBuildPhase;
16+ buildActionMask = 2147483647;
17+ dstPath = /usr/share/man/man1/;
18+ dstSubfolderSpec = 0;
19+ files = (
20+ );
21+ runOnlyForDeploymentPostprocessing = 1;
22+ };
23+/* End PBXCopyFilesBuildPhase section */
24+
25+/* Begin PBXFileReference section */
26+ 03997F901D70CE0C0001C89F /* test-AppleJSONSerialization */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "test-AppleJSONSerialization"; sourceTree = BUILT_PRODUCTS_DIR; };
27+ 03997F931D70CE0C0001C89F /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
28+/* End PBXFileReference section */
29+
30+/* Begin PBXFrameworksBuildPhase section */
31+ 03997F8D1D70CE0C0001C89F /* Frameworks */ = {
32+ isa = PBXFrameworksBuildPhase;
33+ buildActionMask = 2147483647;
34+ files = (
35+ );
36+ runOnlyForDeploymentPostprocessing = 0;
37+ };
38+/* End PBXFrameworksBuildPhase section */
39+
40+/* Begin PBXGroup section */
41+ 03997F871D70CE0C0001C89F = {
42+ isa = PBXGroup;
43+ children = (
44+ 03997F921D70CE0C0001C89F /* test-AppleJSONSerialization */,
45+ 03997F911D70CE0C0001C89F /* Products */,
46+ );
47+ sourceTree = "<group>";
48+ };
49+ 03997F911D70CE0C0001C89F /* Products */ = {
50+ isa = PBXGroup;
51+ children = (
52+ 03997F901D70CE0C0001C89F /* test-AppleJSONSerialization */,
53+ );
54+ name = Products;
55+ sourceTree = "<group>";
56+ };
57+ 03997F921D70CE0C0001C89F /* test-AppleJSONSerialization */ = {
58+ isa = PBXGroup;
59+ children = (
60+ 03997F931D70CE0C0001C89F /* main.swift */,
61+ );
62+ path = "test-AppleJSONSerialization";
63+ sourceTree = "<group>";
64+ };
65+/* End PBXGroup section */
66+
67+/* Begin PBXNativeTarget section */
68+ 03997F8F1D70CE0C0001C89F /* test-AppleJSONSerialization */ = {
69+ isa = PBXNativeTarget;
70+ buildConfigurationList = 03997F971D70CE0C0001C89F /* Build configuration list for PBXNativeTarget "test-AppleJSONSerialization" */;
71+ buildPhases = (
72+ 03997F8C1D70CE0C0001C89F /* Sources */,
73+ 03997F8D1D70CE0C0001C89F /* Frameworks */,
74+ 03997F8E1D70CE0C0001C89F /* CopyFiles */,
75+ );
76+ buildRules = (
77+ );
78+ dependencies = (
79+ );
80+ name = "test-AppleJSONSerialization";
81+ productName = "test-AppleJSONSerialization";
82+ productReference = 03997F901D70CE0C0001C89F /* test-AppleJSONSerialization */;
83+ productType = "com.apple.product-type.tool";
84+ };
85+/* End PBXNativeTarget section */
86+
87+/* Begin PBXProject section */
88+ 03997F881D70CE0C0001C89F /* Project object */ = {
89+ isa = PBXProject;
90+ attributes = {
91+ LastSwiftUpdateCheck = 0800;
92+ LastUpgradeCheck = 0800;
93+ ORGANIZATIONNAME = "Nicolas Seriot";
94+ TargetAttributes = {
95+ 03997F8F1D70CE0C0001C89F = {
96+ CreatedOnToolsVersion = 8.0;
97+ DevelopmentTeam = VBYRKYS73S;
98+ ProvisioningStyle = Automatic;
99+ };
100+ };
101+ };
102+ buildConfigurationList = 03997F8B1D70CE0C0001C89F /* Build configuration list for PBXProject "test-AppleJSONSerialization" */;
103+ compatibilityVersion = "Xcode 3.2";
104+ developmentRegion = English;
105+ hasScannedForEncodings = 0;
106+ knownRegions = (
107+ en,
108+ );
109+ mainGroup = 03997F871D70CE0C0001C89F;
110+ productRefGroup = 03997F911D70CE0C0001C89F /* Products */;
111+ projectDirPath = "";
112+ projectRoot = "";
113+ targets = (
114+ 03997F8F1D70CE0C0001C89F /* test-AppleJSONSerialization */,
115+ );
116+ };
117+/* End PBXProject section */
118+
119+/* Begin PBXSourcesBuildPhase section */
120+ 03997F8C1D70CE0C0001C89F /* Sources */ = {
121+ isa = PBXSourcesBuildPhase;
122+ buildActionMask = 2147483647;
123+ files = (
124+ 03997F941D70CE0C0001C89F /* main.swift in Sources */,
125+ );
126+ runOnlyForDeploymentPostprocessing = 0;
127+ };
128+/* End PBXSourcesBuildPhase section */
129+
130+/* Begin XCBuildConfiguration section */
131+ 03997F951D70CE0C0001C89F /* Debug */ = {
132+ isa = XCBuildConfiguration;
133+ buildSettings = {
134+ ALWAYS_SEARCH_USER_PATHS = NO;
135+ CLANG_ANALYZER_NONNULL = YES;
136+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
137+ CLANG_CXX_LIBRARY = "libc++";
138+ CLANG_ENABLE_MODULES = YES;
139+ CLANG_ENABLE_OBJC_ARC = YES;
140+ CLANG_WARN_BOOL_CONVERSION = YES;
141+ CLANG_WARN_CONSTANT_CONVERSION = YES;
142+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
143+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
144+ CLANG_WARN_EMPTY_BODY = YES;
145+ CLANG_WARN_ENUM_CONVERSION = YES;
146+ CLANG_WARN_INFINITE_RECURSION = YES;
147+ CLANG_WARN_INT_CONVERSION = YES;
148+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
149+ CLANG_WARN_SUSPICIOUS_MOVES = YES;
150+ CLANG_WARN_UNREACHABLE_CODE = YES;
151+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
152+ CODE_SIGN_IDENTITY = "-";
153+ COPY_PHASE_STRIP = NO;
154+ DEBUG_INFORMATION_FORMAT = dwarf;
155+ ENABLE_STRICT_OBJC_MSGSEND = YES;
156+ ENABLE_TESTABILITY = YES;
157+ GCC_C_LANGUAGE_STANDARD = gnu99;
158+ GCC_DYNAMIC_NO_PIC = NO;
159+ GCC_NO_COMMON_BLOCKS = YES;
160+ GCC_OPTIMIZATION_LEVEL = 0;
161+ GCC_PREPROCESSOR_DEFINITIONS = (
162+ "DEBUG=1",
163+ "$(inherited)",
164+ );
165+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
166+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
167+ GCC_WARN_UNDECLARED_SELECTOR = YES;
168+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
169+ GCC_WARN_UNUSED_FUNCTION = YES;
170+ GCC_WARN_UNUSED_VARIABLE = YES;
171+ MACOSX_DEPLOYMENT_TARGET = 10.11;
172+ MTL_ENABLE_DEBUG_INFO = YES;
173+ ONLY_ACTIVE_ARCH = YES;
174+ SDKROOT = macosx;
175+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
176+ };
177+ name = Debug;
178+ };
179+ 03997F961D70CE0C0001C89F /* Release */ = {
180+ isa = XCBuildConfiguration;
181+ buildSettings = {
182+ ALWAYS_SEARCH_USER_PATHS = NO;
183+ CLANG_ANALYZER_NONNULL = YES;
184+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
185+ CLANG_CXX_LIBRARY = "libc++";
186+ CLANG_ENABLE_MODULES = YES;
187+ CLANG_ENABLE_OBJC_ARC = YES;
188+ CLANG_WARN_BOOL_CONVERSION = YES;
189+ CLANG_WARN_CONSTANT_CONVERSION = YES;
190+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
191+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
192+ CLANG_WARN_EMPTY_BODY = YES;
193+ CLANG_WARN_ENUM_CONVERSION = YES;
194+ CLANG_WARN_INFINITE_RECURSION = YES;
195+ CLANG_WARN_INT_CONVERSION = YES;
196+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
197+ CLANG_WARN_SUSPICIOUS_MOVES = YES;
198+ CLANG_WARN_UNREACHABLE_CODE = YES;
199+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
200+ CODE_SIGN_IDENTITY = "-";
201+ COPY_PHASE_STRIP = NO;
202+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
203+ ENABLE_NS_ASSERTIONS = NO;
204+ ENABLE_STRICT_OBJC_MSGSEND = YES;
205+ GCC_C_LANGUAGE_STANDARD = gnu99;
206+ GCC_NO_COMMON_BLOCKS = YES;
207+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
208+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
209+ GCC_WARN_UNDECLARED_SELECTOR = YES;
210+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
211+ GCC_WARN_UNUSED_FUNCTION = YES;
212+ GCC_WARN_UNUSED_VARIABLE = YES;
213+ MACOSX_DEPLOYMENT_TARGET = 10.11;
214+ MTL_ENABLE_DEBUG_INFO = NO;
215+ SDKROOT = macosx;
216+ };
217+ name = Release;
218+ };
219+ 03997F981D70CE0C0001C89F /* Debug */ = {
220+ isa = XCBuildConfiguration;
221+ buildSettings = {
222+ DEVELOPMENT_TEAM = VBYRKYS73S;
223+ PRODUCT_NAME = "$(TARGET_NAME)";
224+ SWIFT_VERSION = 3.0;
225+ };
226+ name = Debug;
227+ };
228+ 03997F991D70CE0C0001C89F /* Release */ = {
229+ isa = XCBuildConfiguration;
230+ buildSettings = {
231+ DEVELOPMENT_TEAM = VBYRKYS73S;
232+ PRODUCT_NAME = "$(TARGET_NAME)";
233+ SWIFT_VERSION = 3.0;
234+ };
235+ name = Release;
236+ };
237+/* End XCBuildConfiguration section */
238+
239+/* Begin XCConfigurationList section */
240+ 03997F8B1D70CE0C0001C89F /* Build configuration list for PBXProject "test-AppleJSONSerialization" */ = {
241+ isa = XCConfigurationList;
242+ buildConfigurations = (
243+ 03997F951D70CE0C0001C89F /* Debug */,
244+ 03997F961D70CE0C0001C89F /* Release */,
245+ );
246+ defaultConfigurationIsVisible = 0;
247+ defaultConfigurationName = Release;
248+ };
249+ 03997F971D70CE0C0001C89F /* Build configuration list for PBXNativeTarget "test-AppleJSONSerialization" */ = {
250+ isa = XCConfigurationList;
251+ buildConfigurations = (
252+ 03997F981D70CE0C0001C89F /* Debug */,
253+ 03997F991D70CE0C0001C89F /* Release */,
254+ );
255+ defaultConfigurationIsVisible = 0;
256+ };
257+/* End XCConfigurationList section */
258+ };
259+ rootObject = 03997F881D70CE0C0001C89F /* Project object */;
260+}
parsers/test-AppleJSONSerialization/test-AppleJSONSerialization.xcodeproj/project.xcworkspace/contents.xcworkspacedatanew file+7
@@ -0,0 +1,7 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<Workspace
3+ version = "1.0">
4+ <FileRef
5+ location = "self:test-AppleJSONSerialization.xcodeproj">
6+ </FileRef>
7+</Workspace>
parsers/test-AppleJSONSerialization/test-AppleJSONSerialization.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstatenew file

Binary file not shown.

parsers/test-AppleJSONSerialization/test-AppleJSONSerialization.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test-AppleJSONSerialization.xcschemenew file+91
@@ -0,0 +1,91 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<Scheme
3+ LastUpgradeVersion = "0800"
4+ version = "1.3">
5+ <BuildAction
6+ parallelizeBuildables = "YES"
7+ buildImplicitDependencies = "YES">
8+ <BuildActionEntries>
9+ <BuildActionEntry
10+ buildForTesting = "YES"
11+ buildForRunning = "YES"
12+ buildForProfiling = "YES"
13+ buildForArchiving = "YES"
14+ buildForAnalyzing = "YES">
15+ <BuildableReference
16+ BuildableIdentifier = "primary"
17+ BlueprintIdentifier = "03997F8F1D70CE0C0001C89F"
18+ BuildableName = "test-AppleJSONSerialization"
19+ BlueprintName = "test-AppleJSONSerialization"
20+ ReferencedContainer = "container:test-AppleJSONSerialization.xcodeproj">
21+ </BuildableReference>
22+ </BuildActionEntry>
23+ </BuildActionEntries>
24+ </BuildAction>
25+ <TestAction
26+ buildConfiguration = "Debug"
27+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
28+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
29+ shouldUseLaunchSchemeArgsEnv = "YES">
30+ <Testables>
31+ </Testables>
32+ <MacroExpansion>
33+ <BuildableReference
34+ BuildableIdentifier = "primary"
35+ BlueprintIdentifier = "03997F8F1D70CE0C0001C89F"
36+ BuildableName = "test-AppleJSONSerialization"
37+ BlueprintName = "test-AppleJSONSerialization"
38+ ReferencedContainer = "container:test-AppleJSONSerialization.xcodeproj">
39+ </BuildableReference>
40+ </MacroExpansion>
41+ <AdditionalOptions>
42+ </AdditionalOptions>
43+ </TestAction>
44+ <LaunchAction
45+ buildConfiguration = "Debug"
46+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
47+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
48+ launchStyle = "0"
49+ useCustomWorkingDirectory = "NO"
50+ ignoresPersistentStateOnLaunch = "NO"
51+ debugDocumentVersioning = "YES"
52+ debugServiceExtension = "internal"
53+ allowLocationSimulation = "YES">
54+ <BuildableProductRunnable
55+ runnableDebuggingMode = "0">
56+ <BuildableReference
57+ BuildableIdentifier = "primary"
58+ BlueprintIdentifier = "03997F8F1D70CE0C0001C89F"
59+ BuildableName = "test-AppleJSONSerialization"
60+ BlueprintName = "test-AppleJSONSerialization"
61+ ReferencedContainer = "container:test-AppleJSONSerialization.xcodeproj">
62+ </BuildableReference>
63+ </BuildableProductRunnable>
64+ <AdditionalOptions>
65+ </AdditionalOptions>
66+ </LaunchAction>
67+ <ProfileAction
68+ buildConfiguration = "Release"
69+ shouldUseLaunchSchemeArgsEnv = "YES"
70+ savedToolIdentifier = ""
71+ useCustomWorkingDirectory = "NO"
72+ debugDocumentVersioning = "YES">
73+ <BuildableProductRunnable
74+ runnableDebuggingMode = "0">
75+ <BuildableReference
76+ BuildableIdentifier = "primary"
77+ BlueprintIdentifier = "03997F8F1D70CE0C0001C89F"
78+ BuildableName = "test-AppleJSONSerialization"
79+ BlueprintName = "test-AppleJSONSerialization"
80+ ReferencedContainer = "container:test-AppleJSONSerialization.xcodeproj">
81+ </BuildableReference>
82+ </BuildableProductRunnable>
83+ </ProfileAction>
84+ <AnalyzeAction
85+ buildConfiguration = "Debug">
86+ </AnalyzeAction>
87+ <ArchiveAction
88+ buildConfiguration = "Release"
89+ revealArchiveInOrganizer = "YES">
90+ </ArchiveAction>
91+</Scheme>
parsers/test-AppleJSONSerialization/test-AppleJSONSerialization.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plistnew file+22
@@ -0,0 +1,22 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+<plist version="1.0">
4+<dict>
5+ <key>SchemeUserState</key>
6+ <dict>
7+ <key>test-AppleJSONSerialization.xcscheme</key>
8+ <dict>
9+ <key>orderHint</key>
10+ <integer>0</integer>
11+ </dict>
12+ </dict>
13+ <key>SuppressBuildableAutocreation</key>
14+ <dict>
15+ <key>03997F8F1D70CE0C0001C89F</key>
16+ <dict>
17+ <key>primary</key>
18+ <true/>
19+ </dict>
20+ </dict>
21+</dict>
22+</plist>
parsers/test-AppleJSONSerialization/test-AppleJSONSerialization/main.swiftnew file+34
@@ -0,0 +1,34 @@
1+//
2+// main.swift
3+// test-AppleJSONSerialization
4+//
5+// Created by nst on 26/08/16.
6+// Copyright © 2016 Nicolas Seriot. All rights reserved.
7+//
8+
9+import Foundation
10+
11+func main() {
12+
13+ guard ProcessInfo.processInfo.arguments.count == 2 else {
14+ let url = NSURL(fileURLWithPath: ProcessInfo.processInfo.arguments[0])
15+ guard let programName = url.lastPathComponent else { exit(1) }
16+ print("Usage: ./\(programName) file.json")
17+ exit(1)
18+ }
19+
20+ let path = ProcessInfo.processInfo.arguments[1]
21+ let url = NSURL.fileURL(withPath:path)
22+
23+ do {
24+ let data = try Data(contentsOf:url)
25+
26+ let _ = try JSONSerialization.jsonObject(with: data, options: [.allowFragments])
27+
28+ exit(0)
29+ } catch {
30+ exit(1)
31+ }
32+}
33+
34+main()
parsers/test_Bash_JSON/JSON.shnew file+208
@@ -0,0 +1,208 @@
1+#!/bin/sh
2+
3+throw() {
4+ echo "$*" >&2
5+ exit 1
6+}
7+
8+BRIEF=0
9+LEAFONLY=0
10+PRUNE=0
11+NO_HEAD=0
12+NORMALIZE_SOLIDUS=0
13+
14+usage() {
15+ echo
16+ echo "Usage: JSON.sh [-b] [-l] [-p] [-s] [-h]"
17+ echo
18+ echo "-p - Prune empty. Exclude fields with empty values."
19+ echo "-l - Leaf only. Only show leaf nodes, which stops data duplication."
20+ echo "-b - Brief. Combines 'Leaf only' and 'Prune empty' options."
21+ echo "-n - No-head. Do not show nodes that have no path (lines that start with [])."
22+ echo "-s - Remove escaping of the solidus symbol (straight slash)."
23+ echo "-h - This help text."
24+ echo
25+}
26+
27+parse_options() {
28+ set -- "$@"
29+ local ARGN=$#
30+ while [ "$ARGN" -ne 0 ]
31+ do
32+ case $1 in
33+ -h) usage
34+ exit 0
35+ ;;
36+ -b) BRIEF=1
37+ LEAFONLY=1
38+ PRUNE=1
39+ ;;
40+ -l) LEAFONLY=1
41+ ;;
42+ -p) PRUNE=1
43+ ;;
44+ -n) NO_HEAD=1
45+ ;;
46+ -s) NORMALIZE_SOLIDUS=1
47+ ;;
48+ ?*) echo "ERROR: Unknown option."
49+ usage
50+ exit 0
51+ ;;
52+ esac
53+ shift 1
54+ ARGN=$((ARGN-1))
55+ done
56+}
57+
58+awk_egrep () {
59+ local pattern_string=$1
60+
61+ gawk '{
62+ while ($0) {
63+ start=match($0, pattern);
64+ token=substr($0, start, RLENGTH);
65+ print token;
66+ $0=substr($0, start+RLENGTH);
67+ }
68+ }' pattern="$pattern_string"
69+}
70+
71+tokenize () {
72+ local GREP
73+ local ESCAPE
74+ local CHAR
75+
76+ if echo "test string" | egrep -ao --color=never "test" >/dev/null 2>&1
77+ then
78+ GREP='egrep -ao --color=never'
79+ else
80+ GREP='egrep -ao'
81+ fi
82+
83+ if echo "test string" | egrep -o "test" >/dev/null 2>&1
84+ then
85+ ESCAPE='(\\[^u[:cntrl:]]|\\u[0-9a-fA-F]{4})'
86+ CHAR='[^[:cntrl:]"\\]'
87+ else
88+ GREP=awk_egrep
89+ ESCAPE='(\\\\[^u[:cntrl:]]|\\u[0-9a-fA-F]{4})'
90+ CHAR='[^[:cntrl:]"\\\\]'
91+ fi
92+
93+ local STRING="\"$CHAR*($ESCAPE$CHAR*)*\""
94+ local NUMBER='-?(0|[1-9][0-9]*)([.][0-9]*)?([eE][+-]?[0-9]*)?'
95+ local KEYWORD='null|false|true'
96+ local SPACE='[[:space:]]+'
97+
98+ # Force zsh to expand $A into multiple words
99+ local is_wordsplit_disabled=$(unsetopt 2>/dev/null | grep -c '^shwordsplit$')
100+ if [ $is_wordsplit_disabled != 0 ]; then setopt shwordsplit; fi
101+ $GREP "$STRING|$NUMBER|$KEYWORD|$SPACE|." | egrep -v "^$SPACE$"
102+ if [ $is_wordsplit_disabled != 0 ]; then unsetopt shwordsplit; fi
103+}
104+
105+parse_array () {
106+ local index=0
107+ local ary=''
108+ read -r token
109+ case "$token" in
110+ ']') ;;
111+ *)
112+ while :
113+ do
114+ parse_value "$1" "$index"
115+ index=$((index+1))
116+ ary="$ary""$value"
117+ read -r token
118+ case "$token" in
119+ ']') break ;;
120+ ',') ary="$ary," ;;
121+ *) throw "EXPECTED , or ] GOT ${token:-EOF}" ;;
122+ esac
123+ read -r token
124+ done
125+ ;;
126+ esac
127+ [ "$BRIEF" -eq 0 ] && value=$(printf '[%s]' "$ary") || value=
128+ :
129+}
130+
131+parse_object () {
132+ local key
133+ local obj=''
134+ read -r token
135+ case "$token" in
136+ '}') ;;
137+ *)
138+ while :
139+ do
140+ case "$token" in
141+ '"'*'"') key=$token ;;
142+ *) throw "EXPECTED string GOT ${token:-EOF}" ;;
143+ esac
144+ read -r token
145+ case "$token" in
146+ ':') ;;
147+ *) throw "EXPECTED : GOT ${token:-EOF}" ;;
148+ esac
149+ read -r token
150+ parse_value "$1" "$key"
151+ obj="$obj$key:$value"
152+ read -r token
153+ case "$token" in
154+ '}') break ;;
155+ ',') obj="$obj," ;;
156+ *) throw "EXPECTED , or } GOT ${token:-EOF}" ;;
157+ esac
158+ read -r token
159+ done
160+ ;;
161+ esac
162+ [ "$BRIEF" -eq 0 ] && value=$(printf '{%s}' "$obj") || value=
163+ :
164+}
165+
166+parse_value () {
167+ local jpath="${1:+$1,}$2" isleaf=0 isempty=0 print=0
168+ case "$token" in
169+ '{') parse_object "$jpath" ;;
170+ '[') parse_array "$jpath" ;;
171+ # At this point, the only valid single-character tokens are digits.
172+ ''|[!0-9]) throw "EXPECTED value GOT ${token:-EOF}" ;;
173+ *) value=$token
174+ # if asked, replace solidus ("\/") in json strings with normalized value: "/"
175+ [ "$NORMALIZE_SOLIDUS" -eq 1 ] && value=$(echo "$value" | sed 's#\\/#/#g')
176+ isleaf=1
177+ [ "$value" = '""' ] && isempty=1
178+ ;;
179+ esac
180+ [ "$value" = '' ] && return
181+ [ "$NO_HEAD" -eq 1 ] && [ -z "$jpath" ] && return
182+
183+ [ "$LEAFONLY" -eq 0 ] && [ "$PRUNE" -eq 0 ] && print=1
184+ [ "$LEAFONLY" -eq 1 ] && [ "$isleaf" -eq 1 ] && [ $PRUNE -eq 0 ] && print=1
185+ [ "$LEAFONLY" -eq 0 ] && [ "$PRUNE" -eq 1 ] && [ "$isempty" -eq 0 ] && print=1
186+ [ "$LEAFONLY" -eq 1 ] && [ "$isleaf" -eq 1 ] && \
187+ [ $PRUNE -eq 1 ] && [ $isempty -eq 0 ] && print=1
188+ [ "$print" -eq 1 ] && printf "[%s]\t%s\n" "$jpath" "$value"
189+ :
190+}
191+
192+parse () {
193+ read -r token
194+ parse_value
195+ read -r token
196+ case "$token" in
197+ '') ;;
198+ *) throw "EXPECTED EOF GOT $token" ;;
199+ esac
200+}
201+
202+if ([ "$0" = "$BASH_SOURCE" ] || ! [ -n "$BASH_SOURCE" ]);
203+then
204+ parse_options "$@"
205+ tokenize | parse
206+fi
207+
208+# vi: expandtab sw=2 ts=2
parsers/test_Freddy_20160830/bin/test_Freddynew file

Binary file not shown.

parsers/test_Freddy_20160830/test_Freddy.xcodeproj/project.pbxprojnew file+300
@@ -0,0 +1,300 @@
1+// !$*UTF8*$!
2+{
3+ archiveVersion = 1;
4+ classes = {
5+ };
6+ objectVersion = 46;
7+ objects = {
8+
9+/* Begin PBXBuildFile section */
10+ 03D84ABB1D5B0A1000776402 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03D84ABA1D5B0A1000776402 /* main.swift */; };
11+ 03F8F7811D5B75600021630C /* JSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03F8F7781D5B75600021630C /* JSON.swift */; };
12+ 03F8F7821D5B75600021630C /* JSONDecodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03F8F7791D5B75600021630C /* JSONDecodable.swift */; };
13+ 03F8F7831D5B75600021630C /* JSONEncodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03F8F77A1D5B75600021630C /* JSONEncodable.swift */; };
14+ 03F8F7841D5B75600021630C /* JSONEncodingDetector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03F8F77B1D5B75600021630C /* JSONEncodingDetector.swift */; };
15+ 03F8F7851D5B75600021630C /* JSONLiteralConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03F8F77C1D5B75600021630C /* JSONLiteralConvertible.swift */; };
16+ 03F8F7861D5B75600021630C /* JSONParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03F8F77D1D5B75600021630C /* JSONParser.swift */; };
17+ 03F8F7871D5B75600021630C /* JSONParsing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03F8F77E1D5B75600021630C /* JSONParsing.swift */; };
18+ 03F8F7881D5B75600021630C /* JSONSerializing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03F8F77F1D5B75600021630C /* JSONSerializing.swift */; };
19+ 03F8F7891D5B75600021630C /* JSONSubscripting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03F8F7801D5B75600021630C /* JSONSubscripting.swift */; };
20+/* End PBXBuildFile section */
21+
22+/* Begin PBXCopyFilesBuildPhase section */
23+ 03D84AB51D5B0A1000776402 /* CopyFiles */ = {
24+ isa = PBXCopyFilesBuildPhase;
25+ buildActionMask = 2147483647;
26+ dstPath = /usr/share/man/man1;
27+ dstSubfolderSpec = 0;
28+ files = (
29+ );
30+ runOnlyForDeploymentPostprocessing = 1;
31+ };
32+/* End PBXCopyFilesBuildPhase section */
33+
34+/* Begin PBXFileReference section */
35+ 03D84AB71D5B0A1000776402 /* test_Freddy */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = test_Freddy; sourceTree = BUILT_PRODUCTS_DIR; };
36+ 03D84ABA1D5B0A1000776402 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
37+ 03F8F7781D5B75600021630C /* JSON.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = JSON.swift; path = test_Freddy/JSON.swift; sourceTree = "<group>"; };
38+ 03F8F7791D5B75600021630C /* JSONDecodable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = JSONDecodable.swift; path = test_Freddy/JSONDecodable.swift; sourceTree = "<group>"; };
39+ 03F8F77A1D5B75600021630C /* JSONEncodable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = JSONEncodable.swift; path = test_Freddy/JSONEncodable.swift; sourceTree = "<group>"; };
40+ 03F8F77B1D5B75600021630C /* JSONEncodingDetector.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = JSONEncodingDetector.swift; path = test_Freddy/JSONEncodingDetector.swift; sourceTree = "<group>"; };
41+ 03F8F77C1D5B75600021630C /* JSONLiteralConvertible.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = JSONLiteralConvertible.swift; path = test_Freddy/JSONLiteralConvertible.swift; sourceTree = "<group>"; };
42+ 03F8F77D1D5B75600021630C /* JSONParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = JSONParser.swift; path = test_Freddy/JSONParser.swift; sourceTree = "<group>"; };
43+ 03F8F77E1D5B75600021630C /* JSONParsing.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = JSONParsing.swift; path = test_Freddy/JSONParsing.swift; sourceTree = "<group>"; };
44+ 03F8F77F1D5B75600021630C /* JSONSerializing.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = JSONSerializing.swift; path = test_Freddy/JSONSerializing.swift; sourceTree = "<group>"; };
45+ 03F8F7801D5B75600021630C /* JSONSubscripting.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = JSONSubscripting.swift; path = test_Freddy/JSONSubscripting.swift; sourceTree = "<group>"; };
46+/* End PBXFileReference section */
47+
48+/* Begin PBXFrameworksBuildPhase section */
49+ 03D84AB41D5B0A1000776402 /* Frameworks */ = {
50+ isa = PBXFrameworksBuildPhase;
51+ buildActionMask = 2147483647;
52+ files = (
53+ );
54+ runOnlyForDeploymentPostprocessing = 0;
55+ };
56+/* End PBXFrameworksBuildPhase section */
57+
58+/* Begin PBXGroup section */
59+ 03D84AAE1D5B0A1000776402 = {
60+ isa = PBXGroup;
61+ children = (
62+ 03F8F7781D5B75600021630C /* JSON.swift */,
63+ 03F8F7791D5B75600021630C /* JSONDecodable.swift */,
64+ 03F8F77A1D5B75600021630C /* JSONEncodable.swift */,
65+ 03F8F77B1D5B75600021630C /* JSONEncodingDetector.swift */,
66+ 03F8F77C1D5B75600021630C /* JSONLiteralConvertible.swift */,
67+ 03F8F77D1D5B75600021630C /* JSONParser.swift */,
68+ 03F8F77E1D5B75600021630C /* JSONParsing.swift */,
69+ 03F8F77F1D5B75600021630C /* JSONSerializing.swift */,
70+ 03F8F7801D5B75600021630C /* JSONSubscripting.swift */,
71+ 03D84AB91D5B0A1000776402 /* test_Freddy */,
72+ 03D84AB81D5B0A1000776402 /* Products */,
73+ );
74+ sourceTree = "<group>";
75+ };
76+ 03D84AB81D5B0A1000776402 /* Products */ = {
77+ isa = PBXGroup;
78+ children = (
79+ 03D84AB71D5B0A1000776402 /* test_Freddy */,
80+ );
81+ name = Products;
82+ sourceTree = "<group>";
83+ };
84+ 03D84AB91D5B0A1000776402 /* test_Freddy */ = {
85+ isa = PBXGroup;
86+ children = (
87+ 03D84ABA1D5B0A1000776402 /* main.swift */,
88+ );
89+ path = test_Freddy;
90+ sourceTree = "<group>";
91+ };
92+/* End PBXGroup section */
93+
94+/* Begin PBXNativeTarget section */
95+ 03D84AB61D5B0A1000776402 /* test_Freddy */ = {
96+ isa = PBXNativeTarget;
97+ buildConfigurationList = 03D84ABE1D5B0A1000776402 /* Build configuration list for PBXNativeTarget "test_Freddy" */;
98+ buildPhases = (
99+ 03D84AB31D5B0A1000776402 /* Sources */,
100+ 03D84AB41D5B0A1000776402 /* Frameworks */,
101+ 03D84AB51D5B0A1000776402 /* CopyFiles */,
102+ );
103+ buildRules = (
104+ );
105+ dependencies = (
106+ );
107+ name = test_Freddy;
108+ productName = test_Freddy;
109+ productReference = 03D84AB71D5B0A1000776402 /* test_Freddy */;
110+ productType = "com.apple.product-type.tool";
111+ };
112+/* End PBXNativeTarget section */
113+
114+/* Begin PBXProject section */
115+ 03D84AAF1D5B0A1000776402 /* Project object */ = {
116+ isa = PBXProject;
117+ attributes = {
118+ LastSwiftUpdateCheck = 0800;
119+ LastUpgradeCheck = 0800;
120+ ORGANIZATIONNAME = "Nicolas Seriot";
121+ TargetAttributes = {
122+ 03D84AB61D5B0A1000776402 = {
123+ CreatedOnToolsVersion = 8.0;
124+ DevelopmentTeam = VBYRKYS73S;
125+ DevelopmentTeamName = "Nicolas Seriot";
126+ ProvisioningStyle = Automatic;
127+ };
128+ };
129+ };
130+ buildConfigurationList = 03D84AB21D5B0A1000776402 /* Build configuration list for PBXProject "test_Freddy" */;
131+ compatibilityVersion = "Xcode 3.2";
132+ developmentRegion = English;
133+ hasScannedForEncodings = 0;
134+ knownRegions = (
135+ en,
136+ );
137+ mainGroup = 03D84AAE1D5B0A1000776402;
138+ productRefGroup = 03D84AB81D5B0A1000776402 /* Products */;
139+ projectDirPath = "";
140+ projectRoot = "";
141+ targets = (
142+ 03D84AB61D5B0A1000776402 /* test_Freddy */,
143+ );
144+ };
145+/* End PBXProject section */
146+
147+/* Begin PBXSourcesBuildPhase section */
148+ 03D84AB31D5B0A1000776402 /* Sources */ = {
149+ isa = PBXSourcesBuildPhase;
150+ buildActionMask = 2147483647;
151+ files = (
152+ 03F8F7881D5B75600021630C /* JSONSerializing.swift in Sources */,
153+ 03F8F7821D5B75600021630C /* JSONDecodable.swift in Sources */,
154+ 03F8F7851D5B75600021630C /* JSONLiteralConvertible.swift in Sources */,
155+ 03F8F7871D5B75600021630C /* JSONParsing.swift in Sources */,
156+ 03F8F7861D5B75600021630C /* JSONParser.swift in Sources */,
157+ 03F8F7831D5B75600021630C /* JSONEncodable.swift in Sources */,
158+ 03D84ABB1D5B0A1000776402 /* main.swift in Sources */,
159+ 03F8F7811D5B75600021630C /* JSON.swift in Sources */,
160+ 03F8F7891D5B75600021630C /* JSONSubscripting.swift in Sources */,
161+ 03F8F7841D5B75600021630C /* JSONEncodingDetector.swift in Sources */,
162+ );
163+ runOnlyForDeploymentPostprocessing = 0;
164+ };
165+/* End PBXSourcesBuildPhase section */
166+
167+/* Begin XCBuildConfiguration section */
168+ 03D84ABC1D5B0A1000776402 /* Debug */ = {
169+ isa = XCBuildConfiguration;
170+ buildSettings = {
171+ ALWAYS_SEARCH_USER_PATHS = NO;
172+ CLANG_ANALYZER_NONNULL = YES;
173+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
174+ CLANG_CXX_LIBRARY = "libc++";
175+ CLANG_ENABLE_MODULES = YES;
176+ CLANG_ENABLE_OBJC_ARC = YES;
177+ CLANG_WARN_BOOL_CONVERSION = YES;
178+ CLANG_WARN_CONSTANT_CONVERSION = YES;
179+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
180+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
181+ CLANG_WARN_EMPTY_BODY = YES;
182+ CLANG_WARN_ENUM_CONVERSION = YES;
183+ CLANG_WARN_INT_CONVERSION = YES;
184+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
185+ CLANG_WARN_UNREACHABLE_CODE = YES;
186+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
187+ CODE_SIGN_IDENTITY = "-";
188+ COPY_PHASE_STRIP = NO;
189+ DEBUG_INFORMATION_FORMAT = dwarf;
190+ ENABLE_STRICT_OBJC_MSGSEND = YES;
191+ ENABLE_TESTABILITY = YES;
192+ GCC_C_LANGUAGE_STANDARD = gnu99;
193+ GCC_DYNAMIC_NO_PIC = NO;
194+ GCC_NO_COMMON_BLOCKS = YES;
195+ GCC_OPTIMIZATION_LEVEL = 0;
196+ GCC_PREPROCESSOR_DEFINITIONS = (
197+ "DEBUG=1",
198+ "$(inherited)",
199+ );
200+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
201+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
202+ GCC_WARN_UNDECLARED_SELECTOR = YES;
203+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
204+ GCC_WARN_UNUSED_FUNCTION = YES;
205+ GCC_WARN_UNUSED_VARIABLE = YES;
206+ MACOSX_DEPLOYMENT_TARGET = 10.11;
207+ MTL_ENABLE_DEBUG_INFO = YES;
208+ ONLY_ACTIVE_ARCH = YES;
209+ SDKROOT = macosx;
210+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
211+ };
212+ name = Debug;
213+ };
214+ 03D84ABD1D5B0A1000776402 /* Release */ = {
215+ isa = XCBuildConfiguration;
216+ buildSettings = {
217+ ALWAYS_SEARCH_USER_PATHS = NO;
218+ CLANG_ANALYZER_NONNULL = YES;
219+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
220+ CLANG_CXX_LIBRARY = "libc++";
221+ CLANG_ENABLE_MODULES = YES;
222+ CLANG_ENABLE_OBJC_ARC = YES;
223+ CLANG_WARN_BOOL_CONVERSION = YES;
224+ CLANG_WARN_CONSTANT_CONVERSION = YES;
225+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
226+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
227+ CLANG_WARN_EMPTY_BODY = YES;
228+ CLANG_WARN_ENUM_CONVERSION = YES;
229+ CLANG_WARN_INT_CONVERSION = YES;
230+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
231+ CLANG_WARN_UNREACHABLE_CODE = YES;
232+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
233+ CODE_SIGN_IDENTITY = "-";
234+ COPY_PHASE_STRIP = NO;
235+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
236+ ENABLE_NS_ASSERTIONS = NO;
237+ ENABLE_STRICT_OBJC_MSGSEND = YES;
238+ GCC_C_LANGUAGE_STANDARD = gnu99;
239+ GCC_NO_COMMON_BLOCKS = YES;
240+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
241+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
242+ GCC_WARN_UNDECLARED_SELECTOR = YES;
243+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
244+ GCC_WARN_UNUSED_FUNCTION = YES;
245+ GCC_WARN_UNUSED_VARIABLE = YES;
246+ MACOSX_DEPLOYMENT_TARGET = 10.11;
247+ MTL_ENABLE_DEBUG_INFO = NO;
248+ SDKROOT = macosx;
249+ };
250+ name = Release;
251+ };
252+ 03D84ABF1D5B0A1000776402 /* Debug */ = {
253+ isa = XCBuildConfiguration;
254+ buildSettings = {
255+ FRAMEWORK_SEARCH_PATHS = (
256+ "$(inherited)",
257+ "$(PROJECT_DIR)",
258+ );
259+ PRODUCT_NAME = "$(TARGET_NAME)";
260+ SWIFT_VERSION = 2.3;
261+ };
262+ name = Debug;
263+ };
264+ 03D84AC01D5B0A1000776402 /* Release */ = {
265+ isa = XCBuildConfiguration;
266+ buildSettings = {
267+ FRAMEWORK_SEARCH_PATHS = (
268+ "$(inherited)",
269+ "$(PROJECT_DIR)",
270+ );
271+ PRODUCT_NAME = "$(TARGET_NAME)";
272+ SWIFT_VERSION = 2.3;
273+ };
274+ name = Release;
275+ };
276+/* End XCBuildConfiguration section */
277+
278+/* Begin XCConfigurationList section */
279+ 03D84AB21D5B0A1000776402 /* Build configuration list for PBXProject "test_Freddy" */ = {
280+ isa = XCConfigurationList;
281+ buildConfigurations = (
282+ 03D84ABC1D5B0A1000776402 /* Debug */,
283+ 03D84ABD1D5B0A1000776402 /* Release */,
284+ );
285+ defaultConfigurationIsVisible = 0;
286+ defaultConfigurationName = Release;
287+ };
288+ 03D84ABE1D5B0A1000776402 /* Build configuration list for PBXNativeTarget "test_Freddy" */ = {
289+ isa = XCConfigurationList;
290+ buildConfigurations = (
291+ 03D84ABF1D5B0A1000776402 /* Debug */,
292+ 03D84AC01D5B0A1000776402 /* Release */,
293+ );
294+ defaultConfigurationIsVisible = 0;
295+ defaultConfigurationName = Release;
296+ };
297+/* End XCConfigurationList section */
298+ };
299+ rootObject = 03D84AAF1D5B0A1000776402 /* Project object */;
300+}
parsers/test_Freddy_20160830/test_Freddy.xcodeproj/project.xcworkspace/contents.xcworkspacedatanew file+7
@@ -0,0 +1,7 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<Workspace
3+ version = "1.0">
4+ <FileRef
5+ location = "self:test_Freddy.xcodeproj">
6+ </FileRef>
7+</Workspace>
parsers/test_Freddy_20160830/test_Freddy.xcodeproj/project.xcworkspace/xcshareddata/test_Freddy.xcscmblueprintnew file+30
@@ -0,0 +1,30 @@
1+{
2+ "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "ED13D74FC1ED9BC322EA1859E5AD7D001676FA6A",
3+ "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : {
4+
5+ },
6+ "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : {
7+ "6ADA245F937D8ED6D99F5A7865E19F5267A169E2" : 0,
8+ "ED13D74FC1ED9BC322EA1859E5AD7D001676FA6A" : 0
9+ },
10+ "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "7B3DFA55-F9BF-41D8-8FD5-204D3162EB03",
11+ "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : {
12+ "6ADA245F937D8ED6D99F5A7865E19F5267A169E2" : "dropbox\/JSON\/test_Freddy\/Vendor\/Freddy\/",
13+ "ED13D74FC1ED9BC322EA1859E5AD7D001676FA6A" : "dropbox\/"
14+ },
15+ "DVTSourceControlWorkspaceBlueprintNameKey" : "test_Freddy",
16+ "DVTSourceControlWorkspaceBlueprintVersion" : 204,
17+ "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "JSON\/test_Freddy\/test_Freddy.xcodeproj",
18+ "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [
19+ {
20+ "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/bignerdranch\/Freddy.git",
21+ "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
22+ "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "6ADA245F937D8ED6D99F5A7865E19F5267A169E2"
23+ },
24+ {
25+ "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "\/Users\/nst\/Dropbox\/dropbox.git",
26+ "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
27+ "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "ED13D74FC1ED9BC322EA1859E5AD7D001676FA6A"
28+ }
29+ ]
30+}
parsers/test_Freddy_20160830/test_Freddy.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstatenew file

Binary file not shown.

parsers/test_Freddy_20160830/test_Freddy.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test_Freddy.xcschemenew file+91
@@ -0,0 +1,91 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<Scheme
3+ LastUpgradeVersion = "0800"
4+ version = "1.3">
5+ <BuildAction
6+ parallelizeBuildables = "YES"
7+ buildImplicitDependencies = "YES">
8+ <BuildActionEntries>
9+ <BuildActionEntry
10+ buildForTesting = "YES"
11+ buildForRunning = "YES"
12+ buildForProfiling = "YES"
13+ buildForArchiving = "YES"
14+ buildForAnalyzing = "YES">
15+ <BuildableReference
16+ BuildableIdentifier = "primary"
17+ BlueprintIdentifier = "03D84AB61D5B0A1000776402"
18+ BuildableName = "test_Freddy"
19+ BlueprintName = "test_Freddy"
20+ ReferencedContainer = "container:test_Freddy.xcodeproj">
21+ </BuildableReference>
22+ </BuildActionEntry>
23+ </BuildActionEntries>
24+ </BuildAction>
25+ <TestAction
26+ buildConfiguration = "Debug"
27+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
28+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
29+ shouldUseLaunchSchemeArgsEnv = "YES">
30+ <Testables>
31+ </Testables>
32+ <MacroExpansion>
33+ <BuildableReference
34+ BuildableIdentifier = "primary"
35+ BlueprintIdentifier = "03D84AB61D5B0A1000776402"
36+ BuildableName = "test_Freddy"
37+ BlueprintName = "test_Freddy"
38+ ReferencedContainer = "container:test_Freddy.xcodeproj">
39+ </BuildableReference>
40+ </MacroExpansion>
41+ <AdditionalOptions>
42+ </AdditionalOptions>
43+ </TestAction>
44+ <LaunchAction
45+ buildConfiguration = "Debug"
46+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
47+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
48+ launchStyle = "0"
49+ useCustomWorkingDirectory = "NO"
50+ ignoresPersistentStateOnLaunch = "NO"
51+ debugDocumentVersioning = "YES"
52+ debugServiceExtension = "internal"
53+ allowLocationSimulation = "YES">
54+ <BuildableProductRunnable
55+ runnableDebuggingMode = "0">
56+ <BuildableReference
57+ BuildableIdentifier = "primary"
58+ BlueprintIdentifier = "03D84AB61D5B0A1000776402"
59+ BuildableName = "test_Freddy"
60+ BlueprintName = "test_Freddy"
61+ ReferencedContainer = "container:test_Freddy.xcodeproj">
62+ </BuildableReference>
63+ </BuildableProductRunnable>
64+ <AdditionalOptions>
65+ </AdditionalOptions>
66+ </LaunchAction>
67+ <ProfileAction
68+ buildConfiguration = "Release"
69+ shouldUseLaunchSchemeArgsEnv = "YES"
70+ savedToolIdentifier = ""
71+ useCustomWorkingDirectory = "NO"
72+ debugDocumentVersioning = "YES">
73+ <BuildableProductRunnable
74+ runnableDebuggingMode = "0">
75+ <BuildableReference
76+ BuildableIdentifier = "primary"
77+ BlueprintIdentifier = "03D84AB61D5B0A1000776402"
78+ BuildableName = "test_Freddy"
79+ BlueprintName = "test_Freddy"
80+ ReferencedContainer = "container:test_Freddy.xcodeproj">
81+ </BuildableReference>
82+ </BuildableProductRunnable>
83+ </ProfileAction>
84+ <AnalyzeAction
85+ buildConfiguration = "Debug">
86+ </AnalyzeAction>
87+ <ArchiveAction
88+ buildConfiguration = "Release"
89+ revealArchiveInOrganizer = "YES">
90+ </ArchiveAction>
91+</Scheme>
parsers/test_Freddy_20160830/test_Freddy.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plistnew file+22
@@ -0,0 +1,22 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+<plist version="1.0">
4+<dict>
5+ <key>SchemeUserState</key>
6+ <dict>
7+ <key>test_Freddy.xcscheme</key>
8+ <dict>
9+ <key>orderHint</key>
10+ <integer>0</integer>
11+ </dict>
12+ </dict>
13+ <key>SuppressBuildableAutocreation</key>
14+ <dict>
15+ <key>03D84AB61D5B0A1000776402</key>
16+ <dict>
17+ <key>primary</key>
18+ <true/>
19+ </dict>
20+ </dict>
21+</dict>
22+</plist>
parsers/test_Freddy_20160830/test_Freddy/JSON.swiftnew file+95
@@ -0,0 +1,95 @@
1+//
2+// JSON.swift
3+// Freddy
4+//
5+// Created by Matthew D. Mathias on 3/17/15.
6+// Copyright © 2015 Big Nerd Ranch. Licensed under MIT.
7+//
8+
9+/// An enum to describe the structure of JSON.
10+public enum JSON {
11+ /// A case for denoting an array with an associated value of `[JSON]`
12+ case Array([JSON])
13+ /// A case for denoting a dictionary with an associated value of `[Swift.String: JSON]`
14+ case Dictionary([Swift.String: JSON])
15+ /// A case for denoting a double with an associated value of `Swift.Double`.
16+ case Double(Swift.Double)
17+ /// A case for denoting an integer with an associated value of `Swift.Int`.
18+ case Int(Swift.Int)
19+ /// A case for denoting a string with an associated value of `Swift.String`.
20+ case String(Swift.String)
21+ /// A case for denoting a boolean with an associated value of `Swift.Bool`.
22+ case Bool(Swift.Bool)
23+ /// A case for denoting null.
24+ case Null
25+}
26+
27+// MARK: - Errors
28+
29+extension JSON {
30+
31+ /// An enum to encapsulate errors that may arise in working with `JSON`.
32+ public enum Error: ErrorType {
33+ /// The `index` is out of bounds for a JSON array
34+ case IndexOutOfBounds(index: Swift.Int)
35+
36+ /// The `key` was not found in the JSON dictionary
37+ case KeyNotFound(key: Swift.String)
38+
39+ /// The JSON is not subscriptable with `type`
40+ case UnexpectedSubscript(type: JSONPathType.Type)
41+
42+ /// Unexpected JSON `value` was found that is not convertible `to` type
43+ case ValueNotConvertible(value: JSON, to: Any.Type)
44+ }
45+
46+}
47+
48+// MARK: - Test Equality
49+
50+/// Return `true` if `lhs` is equal to `rhs`.
51+public func ==(lhs: JSON, rhs: JSON) -> Bool {
52+ switch (lhs, rhs) {
53+ case (.Array(let arrL), .Array(let arrR)):
54+ return arrL == arrR
55+ case (.Dictionary(let dictL), .Dictionary(let dictR)):
56+ return dictL == dictR
57+ case (.String(let strL), .String(let strR)):
58+ return strL == strR
59+ case (.Double(let dubL), .Double(let dubR)):
60+ return dubL == dubR
61+ case (.Double(let dubL), .Int(let intR)):
62+ return dubL == Double(intR)
63+ case (.Int(let intL), .Int(let intR)):
64+ return intL == intR
65+ case (.Int(let intL), .Double(let dubR)):
66+ return Double(intL) == dubR
67+ case (.Bool(let bL), .Bool(let bR)):
68+ return bL == bR
69+ case (.Null, .Null):
70+ return true
71+ default:
72+ return false
73+ }
74+}
75+
76+extension JSON: Equatable {}
77+
78+// MARK: - Printing
79+
80+extension JSON: CustomStringConvertible {
81+
82+ /// A textual representation of `self`.
83+ public var description: Swift.String {
84+ switch self {
85+ case .Array(let arr): return Swift.String(arr)
86+ case .Dictionary(let dict): return Swift.String(dict)
87+ case .String(let string): return string
88+ case .Double(let double): return Swift.String(double)
89+ case .Int(let int): return Swift.String(int)
90+ case .Bool(let bool): return Swift.String(bool)
91+ case .Null: return "null"
92+ }
93+ }
94+
95+}
parsers/test_Freddy_20160830/test_Freddy/JSONDecodable.swiftnew file+177
@@ -0,0 +1,177 @@
1+//
2+// JSONDecodable.swift
3+// Freddy
4+//
5+// Created by Matthew D. Mathias on 3/24/15.
6+// Copyright © 2015 Big Nerd Ranch. Licensed under MIT.
7+//
8+
9+/// A protocol to provide functionality for creating a model object with a `JSON`
10+/// value.
11+public protocol JSONDecodable {
12+
13+ /// Creates an instance of the model with a `JSON` instance.
14+ /// - parameter json: An instance of a `JSON` value from which to
15+ /// construct an instance of the implementing type.
16+ /// - throws: Any `JSON.Error` for errors derived from inspecting the
17+ /// `JSON` value, or any other error involved in decoding.
18+ init(json: JSON) throws
19+
20+}
21+
22+extension Double: JSONDecodable {
23+
24+ /// An initializer to create an instance of `Double` from a `JSON` value.
25+ /// - parameter json: An instance of `JSON`.
26+ /// - throws: The initializer will throw an instance of `JSON.Error` if
27+ /// an instance of `Double` cannot be created from the `JSON` value that was
28+ /// passed to this initializer.
29+ public init(json: JSON) throws {
30+ switch json {
31+ case let .Double(double):
32+ self = double
33+ case let .Int(int):
34+ self = Swift.Double(int)
35+ default:
36+ throw JSON.Error.ValueNotConvertible(value: json, to: Swift.Double)
37+ }
38+ }
39+
40+}
41+
42+extension Int: JSONDecodable {
43+
44+ /// An initializer to create an instance of `Int` from a `JSON` value.
45+ /// - parameter json: An instance of `JSON`.
46+ /// - throws: The initializer will throw an instance of `JSON.Error` if
47+ /// an instance of `Int` cannot be created from the `JSON` value that was
48+ /// passed to this initializer.
49+ public init(json: JSON) throws {
50+ switch json {
51+ case let .Double(double) where double <= Double(Swift.Int.max):
52+ self = Swift.Int(double)
53+ case let .Int(int):
54+ self = int
55+ default:
56+ throw JSON.Error.ValueNotConvertible(value: json, to: Swift.Int)
57+ }
58+ }
59+
60+}
61+
62+extension String: JSONDecodable {
63+
64+ /// An initializer to create an instance of `String` from a `JSON` value.
65+ /// - parameter json: An instance of `JSON`.
66+ /// - throws: The initializer will throw an instance of `JSON.Error` if
67+ /// an instance of `String` cannot be created from the `JSON` value that was
68+ /// passed to this initializer.
69+ public init(json: JSON) throws {
70+
71+ switch json {
72+ case let .String(string):
73+ self = string
74+ case let .Int(int):
75+ self = String(int)
76+ case let .Bool(bool):
77+ self = String(bool)
78+ case let .Double(double):
79+ self = String(double)
80+ default:
81+ throw JSON.Error.ValueNotConvertible(value: json, to: Swift.String)
82+ }
83+ }
84+
85+}
86+
87+extension Bool: JSONDecodable {
88+
89+ /// An initializer to create an instance of `Bool` from a `JSON` value.
90+ /// - parameter json: An instance of `JSON`.
91+ /// - throws: The initializer will throw an instance of `JSON.Error` if
92+ /// an instance of `Bool` cannot be created from the `JSON` value that was
93+ /// passed to this initializer.
94+ public init(json: JSON) throws {
95+ guard case let .Bool(bool) = json else {
96+ throw JSON.Error.ValueNotConvertible(value: json, to: Swift.Bool)
97+ }
98+ self = bool
99+ }
100+
101+}
102+
103+extension RawRepresentable where RawValue: JSONDecodable {
104+
105+ /// An initializer to create an instance of `RawRepresentable` from a `JSON` value.
106+ /// - parameter json: An instance of `JSON`.
107+ /// - throws: The initializer will throw an instance of `JSON.Error` if
108+ /// an instance of `RawRepresentable` cannot be created from the `JSON` value that was
109+ /// passed to this initializer.
110+ public init(json: JSON) throws {
111+ let raw = try json.decode(type: RawValue.self)
112+ guard let value = Self(rawValue: raw) else {
113+ throw JSON.Error.ValueNotConvertible(value: json, to: Self.self)
114+ }
115+ self = value
116+ }
117+}
118+
119+internal extension JSON {
120+
121+ /// Retrieves a `[JSON]` from the JSON.
122+ /// - parameter: A `JSON` to be used to create the returned `Array`.
123+ /// - returns: An `Array` of `JSON` elements
124+ /// - throws: Any of the `JSON.Error` cases thrown by `decode(type:)`.
125+ /// - seealso: `JSON.decode(_:type:)`
126+ static func getArray(json: JSON) throws -> [JSON] {
127+ // Ideally should be expressed as a conditional protocol implementation on Swift.Array.
128+ guard case let .Array(array) = json else {
129+ throw Error.ValueNotConvertible(value: json, to: Swift.Array<JSON>)
130+ }
131+ return array
132+ }
133+
134+ /// Retrieves a `[String: JSON]` from the JSON.
135+ /// - parameter: A `JSON` to be used to create the returned `Dictionary`.
136+ /// - returns: An `Dictionary` of `String` mapping to `JSON` elements
137+ /// - throws: Any of the `JSON.Error` cases thrown by `decode(type:)`.
138+ /// - seealso: `JSON.decode(_:type:)`
139+ static func getDictionary(json: JSON) throws -> [Swift.String: JSON] {
140+ // Ideally should be expressed as a conditional protocol implementation on Swift.Dictionary.
141+ guard case let .Dictionary(dictionary) = json else {
142+ throw Error.ValueNotConvertible(value: json, to: Swift.Dictionary<Swift.String, JSON>)
143+ }
144+ return dictionary
145+ }
146+
147+ /// Attempts to decode many values from a descendant JSON array at a path
148+ /// into JSON.
149+ /// - parameter: A `JSON` to be used to create the returned `Array` of some type conforming to `JSONDecodable`.
150+ /// - returns: An `Array` of `Decoded` elements.
151+ /// - throws: Any of the `JSON.Error` cases thrown by `decode(type:)`, as
152+ /// well as any error that arises from decoding the contained values.
153+ /// - seealso: `JSON.decode(_:type:)`
154+ static func getArrayOf<Decoded: JSONDecodable>(json: JSON) throws -> [Decoded] {
155+ // Ideally should be expressed as a conditional protocol implementation on Swift.Dictionary.
156+ // This implementation also doesn't do the `type = Type.self` trick.
157+ return try getArray(json).map(Decoded.init)
158+ }
159+
160+ /// Attempts to decode many values from a descendant JSON object at a path
161+ /// into JSON.
162+ /// - returns: A `Dictionary` of string keys and `Decoded` values.
163+ /// - throws: One of the `JSON.Error` cases thrown by `decode(_:type:)` or
164+ /// any error that arises from decoding the contained values.
165+ /// - seealso: `JSON.decode(_:type:)`
166+ static func getDictionaryOf<Decoded: JSONDecodable>(json: JSON) throws -> [Swift.String: Decoded] {
167+ guard case let .Dictionary(dictionary) = json else {
168+ throw Error.ValueNotConvertible(value: json, to: Swift.Dictionary<Swift.String, Decoded>)
169+ }
170+ var decodedDictionary = Swift.Dictionary<Swift.String, Decoded>(minimumCapacity: dictionary.count)
171+ for (key, value) in dictionary {
172+ decodedDictionary[key] = try Decoded(json: value)
173+ }
174+ return decodedDictionary
175+ }
176+
177+}
parsers/test_Freddy_20160830/test_Freddy/JSONEncodable.swiftnew file+83
@@ -0,0 +1,83 @@
1+//
2+// JSONEncodable.swift
3+// Freddy
4+//
5+// Created by Matthew Mathias on 1/4/16.
6+// Copyright © 2016 Big Nerd Ranch. All rights reserved.
7+//
8+
9+import Foundation
10+
11+/// A protocol to facilitate encoding and decoding of `JSON`.
12+public protocol JSONEncodable {
13+ /// Converts an instance of a conforming type to `JSON`.
14+ /// - returns: An instance of `JSON`.
15+ /// - Note: If conforming to `JSONEncodable` with a custom type of your own, you should return an instance of
16+ /// `JSON.Dictionary`.
17+ func toJSON() -> JSON
18+}
19+
20+extension Array where Element: JSONEncodable {
21+ /// Converts an instance of `Array` whose elements conform to `JSONEncodable` to `JSON`.
22+ /// - returns: An instance of `JSON` where the enum case is `.Array`.
23+ public func toJSON() -> JSON {
24+ let arrayOfJSON = self.map { $0.toJSON() }
25+ return .Array(arrayOfJSON)
26+ }
27+}
28+
29+extension Dictionary where Value: JSONEncodable {
30+ /// Converts an instance of `Dictionary` whose values conform to `JSONEncodable` to `JSON`. The keys in the resulting
31+ /// `JSON.Dictionary` will be of type `String`.
32+ /// - returns: An instance of `JSON` where the enum case is `.Dictionary`.
33+ public func toJSON() -> JSON {
34+ var jsonDictionary = [String: JSON]()
35+
36+ for (k, v) in self {
37+ let key = String(k)
38+ jsonDictionary[key] = v.toJSON()
39+ }
40+
41+ return .Dictionary(jsonDictionary)
42+ }
43+}
44+
45+extension Int: JSONEncodable {
46+ /// Converts an instance of a conforming type to `JSON`.
47+ /// - returns: An instance of `JSON` where the enum case is `.Int`.
48+ public func toJSON() -> JSON {
49+ return .Int(self)
50+ }
51+}
52+
53+extension Double: JSONEncodable {
54+ /// Converts an instance of a conforming type to `JSON`.
55+ /// - returns: An instance of `JSON` where the enum case is `.Double`.
56+ public func toJSON() -> JSON {
57+ return .Double(self)
58+ }
59+}
60+
61+extension String: JSONEncodable {
62+ /// Converts an instance of a conforming type to `JSON`.
63+ /// - returns: An instance of `JSON` where the enum case is `.String`.
64+ public func toJSON() -> JSON {
65+ return .String(self)
66+ }
67+}
68+
69+extension Bool: JSONEncodable {
70+ /// Converts an instance of a conforming type to `JSON`.
71+ /// - returns: An instance of `JSON` where the enum case is `.Bool`.
72+ public func toJSON() -> JSON {
73+ return .Bool(self)
74+ }
75+}
76+
77+extension RawRepresentable where RawValue: JSONEncodable {
78+ /// Converts an instance of a conforming type to `JSON`.
79+ /// - returns: An instance of `JSON` where the enum case is whatever the underlying `RawValue` converts to.
80+ public func toJSON() -> JSON {
81+ return rawValue.toJSON()
82+ }
83+}
parsers/test_Freddy_20160830/test_Freddy/JSONEncodingDetector.swiftnew file+110
@@ -0,0 +1,110 @@
1+//
2+// JSONEncodingDetector.swift
3+// Freddy
4+//
5+// Created by Robert Edwards on 1/27/16.
6+// Copyright © 2016 Big Nerd Ranch. All rights reserved.
7+//
8+
9+/// Struct for attempting to detect the Unicode encoding used with the data supplied to the JSONParser
10+public struct JSONEncodingDetector {
11+
12+ //// The Unicode encodings looked for during detection
13+ public enum Encoding {
14+ //// UTF-8
15+ case UTF8
16+ //// UTF-16 Little Endian
17+ case UTF16LE
18+ //// UTF-16 Big Endian
19+ case UTF16BE
20+ //// UTF-32 Little Endian
21+ case UTF32LE
22+ //// UTF-32 Big Endian
23+ case UTF32BE
24+ }
25+
26+ //// The Unicode encodings supported by JSONParser.swift
27+ public static let supportedEncodings: [Encoding] = [.UTF8]
28+
29+ typealias ByteStreamPrefixInformation = (encoding: Encoding, byteOrderMarkLength: Int)
30+
31+ //// Attempts to detect the Unicode encoding used for a given set of data.
32+ ////
33+ //// This function initially looks for a Byte Order Mark in the following form:
34+ ////
35+ //// Bytes | Encoding Form
36+ //// --------------|----------------
37+ //// 00 00 FE FF | UTF-32, big-endian
38+ //// FF FE 00 00 | UTF-32, little-endian
39+ //// FE FF | UTF-16, big-endian
40+ //// FF FE | UTF-16, little-endian
41+ //// EF BB BF | UTF-8
42+ ////
43+ //// If a BOM is not found then we detect using the following approach described in
44+ //// the JSON RFC http://www.ietf.org/rfc/rfc4627.txt:
45+ ////
46+ //// Since the first two characters of a JSON text will always be ASCII
47+ //// characters [RFC0020], it is possible to determine whether an octet
48+ //// stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking
49+ //// at the pattern of nulls in the first four octets.
50+ ////
51+ //// 00 00 00 xx UTF-32BE
52+ //// 00 xx 00 xx UTF-16BE
53+ //// xx 00 00 00 UTF-32LE
54+ //// xx 00 xx 00 UTF-16LE
55+ //// xx xx xx xx UTF-8
56+ ////
57+ //// - parameter header: The front Slice of data being read and evaluated.
58+ //// - returns: A tuple containing the detected Unicode encoding and the lenght of the byte order mark.
59+ static func detectEncoding(header: Slice<UnsafeBufferPointer<UInt8>>) -> ByteStreamPrefixInformation {
60+
61+ guard let prefix = prefixFromHeader(header) else {
62+ return (.UTF8, 0)
63+ }
64+
65+ if let prefixInfo = JSONEncodingDetector.encodingFromBOM(prefix) {
66+ return prefixInfo
67+ } else {
68+ switch prefix {
69+ case(0, 0, 0?, _):
70+ return (.UTF32BE, 0)
71+ case(_, 0, 0?, 0?):
72+ return (.UTF32LE, 0)
73+ case (0, _, 0?, _), (0, _, _, _):
74+ return (.UTF16BE, 0)
75+ case (_, 0, _, 0?), (_, 0, _, _):
76+ return (.UTF16LE, 0)
77+ default:
78+ return (.UTF8, 0)
79+ }
80+ }
81+ }
82+
83+ private typealias EncodingBytePrefix = (UInt8, UInt8, UInt8?, UInt8?)
84+
85+ private static func prefixFromHeader(header: Slice<UnsafeBufferPointer<UInt8>>) -> EncodingBytePrefix? {
86+ if header.count >= 4 {
87+ return(header[0], header[1], header[2], header[3])
88+ } else if header.count >= 2 {
89+ return (header[0], header[1], nil, nil)
90+ }
91+ return nil
92+ }
93+
94+ private static func encodingFromBOM(prefix: EncodingBytePrefix) -> ByteStreamPrefixInformation? {
95+ switch prefix {
96+ case(0xFE, 0xFF, _, _):
97+ return (.UTF16BE, 2)
98+ case(0x00, 0x00, 0xFE?, 0xFF?):
99+ return (.UTF32BE, 4)
100+ case(0xEF, 0xBB, 0xBF?, _):
101+ return (.UTF8, 3)
102+ case(0xFF, 0xFE, 0?, 0?):
103+ return (.UTF32LE, 4)
104+ case(0xFF, 0xFE, _, _):
105+ return (.UTF16LE, 2)
106+ default:
107+ return nil
108+ }
109+ }
110+}
parsers/test_Freddy_20160830/test_Freddy/JSONLiteralConvertible.swiftnew file+130
@@ -0,0 +1,130 @@
1+//
2+// JSONLiteralConvertible.swift
3+// Freddy
4+//
5+// Created by Zachary Waldowski on 5/11/15.
6+// Copyright © 2015 Big Nerd Ranch. Licensed under MIT.
7+//
8+
9+// MARK: - ArrayLiteralConvertible
10+
11+extension JSON: ArrayLiteralConvertible {
12+
13+ /// Create an instance by copying each element of the `collection` into a
14+ /// new `Array`.
15+ public init<Collection: CollectionType where Collection.Generator.Element == JSON>(_ collection: Collection) {
16+ self = .Array(Swift.Array(collection))
17+ }
18+
19+ /// Create an instance initialized with `elements`.
20+ public init(arrayLiteral elements: JSON...) {
21+ self.init(elements)
22+ }
23+
24+}
25+
26+// MARK: - DictionaryLiteralConvertible
27+
28+extension JSON: DictionaryLiteralConvertible {
29+
30+ /// Create an instance by copying each key/value pair of the `pairs` into
31+ /// a new `Dictionary`.
32+ public init<Dictionary: SequenceType where Dictionary.Generator.Element == (Swift.String, JSON)>(_ pairs: Dictionary) {
33+ var dictionary = Swift.Dictionary<Swift.String, JSON>(minimumCapacity: pairs.underestimateCount())
34+ for (key, value) in pairs {
35+ dictionary[key] = value
36+ }
37+ self = .Dictionary(dictionary)
38+ }
39+
40+ /// Create an instance initialized with `pairs`.
41+ public init(dictionaryLiteral pairs: (Swift.String, JSON)...) {
42+ self.init(pairs)
43+ }
44+
45+}
46+
47+// MARK: - FloatLiteralConvertible
48+
49+extension JSON: FloatLiteralConvertible {
50+
51+ /// Create an instance initialized to `Double` `value`.
52+ public init(_ value: Swift.Double) {
53+ self = .Double(value)
54+ }
55+
56+ /// Create a literal instance initialized to `value`.
57+ public init(floatLiteral value: Swift.Double) {
58+ self.init(value)
59+ }
60+
61+}
62+
63+// MARK: - IntegerLiteralConvertible
64+
65+extension JSON: IntegerLiteralConvertible {
66+
67+ /// Create an instance initialized to `Int` by `value`.
68+ public init(_ value: Swift.Int) {
69+ self = .Int(value)
70+ }
71+
72+ /// Create a literal instance initialized to `value`.
73+ public init(integerLiteral value: Swift.Int) {
74+ self.init(value)
75+ }
76+
77+}
78+
79+// MARK: - StringLiteralConvertible
80+
81+extension JSON: StringLiteralConvertible {
82+
83+ /// Create an instance initialized to `String` by `text`.
84+ public init(_ text: Swift.String) {
85+ self = .String(text)
86+ }
87+
88+ /// Create a literal instance initialized to `value`.
89+ public init(stringLiteral value: StringLiteralType) {
90+ self.init(value)
91+ }
92+
93+ /// Create a literal instance initialized to `value`.
94+ public init(extendedGraphemeClusterLiteral value: StringLiteralType) {
95+ self.init(value)
96+ }
97+
98+ /// Create a literal instance initialized to `value`.
99+ public init(unicodeScalarLiteral value: StringLiteralType) {
100+ self.init(value)
101+ }
102+
103+}
104+
105+// MARK: - BooleanLiteralConvertible
106+
107+extension JSON: BooleanLiteralConvertible {
108+
109+ /// Create an instance initialized to `Bool` by `value`.
110+ public init(_ value: Swift.Bool) {
111+ self = .Bool(value)
112+ }
113+
114+ /// Create a literal instance initialized to `value`.
115+ public init(booleanLiteral value: Swift.Bool) {
116+ self.init(value)
117+ }
118+
119+}
120+
121+// MARK: - NilLiteralConvertible
122+
123+extension JSON: NilLiteralConvertible {
124+
125+ /// Create an instance initialized with `nil`.
126+ public init(nilLiteral: ()) {
127+ self = .Null
128+ }
129+
130+}
parsers/test_Freddy_20160830/test_Freddy/JSONParser.swiftnew file+907
@@ -0,0 +1,907 @@
1+//
2+// JSONParser.swift
3+// Freddy
4+//
5+// Created by John Gallagher on 4/18/15.
6+// Copyright © 2015 Big Nerd Ranch. Licensed under MIT.
7+//
8+
9+import Foundation
10+
11+private struct Literal {
12+ static let BACKSLASH = UInt8(ascii: "\\")
13+ static let BACKSPACE = UInt8(ascii: "\u{0008}")
14+ static let COLON = UInt8(ascii: ":")
15+ static let COMMA = UInt8(ascii: ",")
16+ static let DOUBLE_QUOTE = UInt8(ascii: "\"")
17+ static let FORMFEED = UInt8(ascii: "\u{000c}")
18+ static let LEFT_BRACE = UInt8(ascii: "{")
19+ static let LEFT_BRACKET = UInt8(ascii: "[")
20+ static let MINUS = UInt8(ascii: "-")
21+ static let NEWLINE = UInt8(ascii: "\n")
22+ static let PERIOD = UInt8(ascii: ".")
23+ static let PLUS = UInt8(ascii: "+")
24+ static let RETURN = UInt8(ascii: "\r")
25+ static let RIGHT_BRACE = UInt8(ascii: "}")
26+ static let RIGHT_BRACKET = UInt8(ascii: "]")
27+ static let SLASH = UInt8(ascii: "/")
28+ static let SPACE = UInt8(ascii: " ")
29+ static let TAB = UInt8(ascii: "\t")
30+
31+ static let a = UInt8(ascii: "a")
32+ static let b = UInt8(ascii: "b")
33+ static let c = UInt8(ascii: "c")
34+ static let d = UInt8(ascii: "d")
35+ static let e = UInt8(ascii: "e")
36+ static let f = UInt8(ascii: "f")
37+ static let l = UInt8(ascii: "l")
38+ static let n = UInt8(ascii: "n")
39+ static let r = UInt8(ascii: "r")
40+ static let s = UInt8(ascii: "s")
41+ static let t = UInt8(ascii: "t")
42+ static let u = UInt8(ascii: "u")
43+
44+ static let A = UInt8(ascii: "A")
45+ static let B = UInt8(ascii: "B")
46+ static let C = UInt8(ascii: "C")
47+ static let D = UInt8(ascii: "D")
48+ static let E = UInt8(ascii: "E")
49+ static let F = UInt8(ascii: "F")
50+
51+ static let zero = UInt8(ascii: "0")
52+ static let one = UInt8(ascii: "1")
53+ static let two = UInt8(ascii: "2")
54+ static let three = UInt8(ascii: "3")
55+ static let four = UInt8(ascii: "4")
56+ static let five = UInt8(ascii: "5")
57+ static let six = UInt8(ascii: "6")
58+ static let seven = UInt8(ascii: "7")
59+ static let eight = UInt8(ascii: "8")
60+ static let nine = UInt8(ascii: "9")
61+}
62+
63+private let ParserMaximumDepth = 512
64+
65+
66+/// A pure Swift JSON parser. This parser is much faster than the
67+/// `NSJSONSerialization`-based parser (due to the overhead of having to
68+/// dynamically cast the Objective-C objects to determine their type); however,
69+/// it is much newer and has restrictions that the `NSJSONSerialization` parser
70+/// does not. Two restrictions in particular are that it requires UTF-8 data as
71+/// input and it does not allow trailing commas in arrays or dictionaries.
72+public struct JSONParser {
73+
74+ private enum Sign: Int {
75+ case Positive = 1
76+ case Negative = -1
77+ }
78+
79+ private let input: UnsafeBufferPointer<UInt8>
80+ private let owner: Any?
81+ private var loc = 0
82+ private var depth = 0
83+
84+ private init<T>(buffer: UnsafeBufferPointer<UInt8>, owner: T) {
85+ self.input = buffer
86+ self.owner = owner
87+ }
88+
89+ /// Decode the root element of the `JSON` stream. This may be any fragment
90+ /// or a structural element, per RFC 7159.
91+ ///
92+ /// The beginning bytes are used to determine the stream's encoding.
93+ /// `JSONParser` currently only supports UTF-8 encoding, with or without
94+ /// a byte-order mark.
95+ ///
96+ /// - throws: `JSONParser.Error` for any decoding failures, including a
97+ /// source location if needed.
98+ public mutating func parse() throws -> JSON {
99+ try guardAgainstUnsupportedEncodings()
100+ let value = try parseValue()
101+ skipWhitespace()
102+ guard loc == input.count else {
103+ throw Error.EndOfStreamGarbage(offset: loc)
104+ }
105+ return value
106+ }
107+
108+ private mutating func parseValue() throws -> JSON {
109+ guard depth <= ParserMaximumDepth else {
110+ throw Error.ExceededNestingLimit(offset: loc)
111+ }
112+
113+ guard input.count > 0 else {
114+ throw Error.EndOfStreamUnexpected
115+ }
116+
117+ advancing: while loc < input.count {
118+ do {
119+ switch input[loc] {
120+ case Literal.LEFT_BRACKET:
121+ depth += 1
122+ defer { depth -= 1 }
123+ return try decodeArray()
124+
125+ case Literal.LEFT_BRACE:
126+ depth += 1
127+ defer { depth -= 1 }
128+ return try decodeObject()
129+
130+ case Literal.DOUBLE_QUOTE:
131+ return try decodeString()
132+
133+ case Literal.f:
134+ return try decodeFalse()
135+
136+ case Literal.n:
137+ return try decodeNull()
138+
139+ case Literal.t:
140+ return try decodeTrue()
141+
142+ case Literal.MINUS:
143+ return try decodeIntegralValue(NumberParser(loc: loc, input: input, state: .LeadingMinus))
144+
145+ case Literal.zero:
146+ return try decodeIntegralValue(NumberParser(loc: loc, input: input, state: .LeadingZero))
147+
148+ case Literal.one...Literal.nine:
149+ return try decodeIntegralValue(NumberParser(loc: loc, input: input, state: .PreDecimalDigits))
150+
151+ case Literal.SPACE, Literal.TAB, Literal.RETURN, Literal.NEWLINE:
152+ loc = loc.successor()
153+
154+ default:
155+ break advancing
156+ }
157+ } catch let InternalError.NumberOverflow(offset: start) {
158+ return try decodeNumberAsString(start)
159+ }
160+ }
161+
162+ if loc < input.count {
163+ throw Error.ValueInvalid(offset: loc, character: UnicodeScalar(input[loc]))
164+ } else {
165+ throw Error.EndOfStreamUnexpected
166+ }
167+ }
168+
169+ private mutating func skipWhitespace() {
170+ while loc < input.count {
171+ switch input[loc] {
172+ case Literal.SPACE, Literal.TAB, Literal.RETURN, Literal.NEWLINE:
173+ loc = loc.successor()
174+
175+ default:
176+ return
177+ }
178+ }
179+ }
180+
181+ private mutating func guardAgainstUnsupportedEncodings() throws {
182+ let header = input.prefix(4)
183+ let encodingPrefixInformation = JSONEncodingDetector.detectEncoding(header)
184+ guard JSONEncodingDetector.supportedEncodings.contains(encodingPrefixInformation.encoding) else {
185+ throw Error.InvalidUnicodeStreamEncoding(detectedEncoding: encodingPrefixInformation.encoding)
186+ }
187+ loc = loc.advancedBy(encodingPrefixInformation.byteOrderMarkLength)
188+ }
189+
190+ private mutating func decodeNull() throws -> JSON {
191+ guard loc.advancedBy(3, limit: input.count) != input.count else {
192+ throw Error.LiteralNilMisspelled(offset: loc)
193+ }
194+
195+ if input[loc+1] != Literal.u
196+ || input[loc+2] != Literal.l
197+ || input[loc+3] != Literal.l {
198+ throw Error.LiteralNilMisspelled(offset: loc)
199+ }
200+
201+ loc += 4
202+ return .Null
203+ }
204+
205+ private mutating func decodeTrue() throws -> JSON {
206+ guard loc.advancedBy(3, limit: input.count) != input.count else {
207+ throw Error.LiteralTrueMisspelled(offset: loc)
208+ }
209+
210+ if input[loc+1] != Literal.r
211+ || input[loc+2] != Literal.u
212+ || input[loc+3] != Literal.e {
213+ throw Error.LiteralTrueMisspelled(offset: loc)
214+ }
215+
216+ loc += 4
217+ return .Bool(true)
218+ }
219+
220+ private mutating func decodeFalse() throws -> JSON {
221+ guard loc.advancedBy(4, limit: input.count) != input.count else {
222+ throw Error.LiteralFalseMisspelled(offset: loc)
223+ }
224+
225+ if input[loc+1] != Literal.a
226+ || input[loc+2] != Literal.l
227+ || input[loc+3] != Literal.s
228+ || input[loc+4] != Literal.e {
229+ throw Error.LiteralFalseMisspelled(offset: loc)
230+ }
231+
232+ loc += 5
233+ return .Bool(false)
234+ }
235+
236+ private var stringDecodingBuffer = [UInt8]()
237+ private mutating func decodeString() throws -> JSON {
238+ let start = loc
239+ loc = loc.successor()
240+ stringDecodingBuffer.removeAll(keepCapacity: true)
241+ while loc < input.count {
242+ switch input[loc] {
243+ case Literal.BACKSLASH:
244+ loc = loc.successor()
245+ switch input[loc] {
246+ case Literal.DOUBLE_QUOTE: stringDecodingBuffer.append(Literal.DOUBLE_QUOTE)
247+ case Literal.BACKSLASH: stringDecodingBuffer.append(Literal.BACKSLASH)
248+ case Literal.SLASH: stringDecodingBuffer.append(Literal.SLASH)
249+ case Literal.b: stringDecodingBuffer.append(Literal.BACKSPACE)
250+ case Literal.f: stringDecodingBuffer.append(Literal.FORMFEED)
251+ case Literal.r: stringDecodingBuffer.append(Literal.RETURN)
252+ case Literal.t: stringDecodingBuffer.append(Literal.TAB)
253+ case Literal.n: stringDecodingBuffer.append(Literal.NEWLINE)
254+ case Literal.u:
255+ loc = loc.successor()
256+ try readUnicodeEscape(start: loc - 2)
257+
258+ // readUnicodeEscape() advances loc on its own, so we'll `continue` now
259+ // to skip the typical "advance past this character" for all the other escapes
260+ continue
261+
262+ default:
263+ throw Error.ControlCharacterUnrecognized(offset: loc)
264+ }
265+ loc = loc.successor()
266+
267+ case Literal.DOUBLE_QUOTE:
268+ loc = loc.successor()
269+ stringDecodingBuffer.append(0)
270+
271+ guard let string = (stringDecodingBuffer.withUnsafeBufferPointer {
272+ String.fromCString(UnsafePointer($0.baseAddress))
273+ }) else {
274+ throw Error.UnicodeEscapeInvalid(offset: start)
275+ }
276+
277+ return .String(string)
278+
279+ case let other:
280+ stringDecodingBuffer.append(other)
281+ loc = loc.successor()
282+ }
283+ }
284+
285+ throw Error.EndOfStreamUnexpected
286+ }
287+
288+ private mutating func readCodeUnit() -> UInt16? {
289+ guard loc + 4 <= input.count else {
290+ return nil
291+ }
292+ var codeUnit: UInt16 = 0
293+ for c in input[loc..<loc+4] {
294+ let nibble: UInt16
295+
296+ switch c {
297+ case Literal.zero...Literal.nine:
298+ nibble = UInt16(c - Literal.zero)
299+
300+ case Literal.a...Literal.f:
301+ nibble = 10 + UInt16(c - Literal.a)
302+
303+ case Literal.A...Literal.F:
304+ nibble = 10 + UInt16(c - Literal.A)
305+
306+ default:
307+ return nil
308+ }
309+ codeUnit = (codeUnit << 4) | nibble
310+ }
311+ loc += 4
312+ return codeUnit
313+ }
314+
315+ private mutating func readUnicodeEscape(start start: Int) throws {
316+ guard let codeUnit = readCodeUnit() else {
317+ throw Error.UnicodeEscapeInvalid(offset: start)
318+ }
319+
320+ let codeUnits: [UInt16]
321+
322+ if UTF16.isLeadSurrogate(codeUnit) {
323+ // First half of a UTF16 surrogate pair - we must parse another code unit and combine them
324+
325+ // First confirm and skip over that we have another "\u"
326+ guard loc + 6 <= input.count && input[loc] == Literal.BACKSLASH && input[loc+1] == Literal.u else {
327+ throw Error.UnicodeEscapeInvalid(offset: start)
328+ }
329+ loc += 2
330+
331+ // Ensure the second code unit is valid for the surrogate pair
332+ guard let secondCodeUnit = readCodeUnit() where UTF16.isTrailSurrogate(secondCodeUnit) else {
333+ throw Error.UnicodeEscapeInvalid(offset: start)
334+ }
335+
336+ codeUnits = [codeUnit, secondCodeUnit]
337+ } else {
338+ codeUnits = [codeUnit]
339+ }
340+
341+ let transcodeHadError = transcode(UTF16.self, UTF8.self, codeUnits.generate(), { self.stringDecodingBuffer.append($0) }, stopOnError: true)
342+
343+ if transcodeHadError {
344+ throw Error.UnicodeEscapeInvalid(offset: start)
345+ }
346+ }
347+
348+ private mutating func decodeArray() throws -> JSON {
349+ let start = loc
350+ loc = loc.successor()
351+ var items = [JSON]()
352+
353+ while loc < input.count {
354+ skipWhitespace()
355+
356+ if loc < input.count && input[loc] == Literal.RIGHT_BRACKET {
357+ loc = loc.successor()
358+ return .Array(items)
359+ }
360+
361+ if !items.isEmpty {
362+ guard loc < input.count && input[loc] == Literal.COMMA else {
363+ throw Error.CollectionMissingSeparator(offset: start)
364+ }
365+ loc = loc.successor()
366+ }
367+
368+ items.append(try parseValue())
369+ }
370+
371+ throw Error.EndOfStreamUnexpected
372+ }
373+
374+ // Decoding objects can be recursive, so we have to keep more than one
375+ // buffer around for building up key/value pairs (to reduce allocations
376+ // when parsing large JSON documents).
377+ //
378+ // Rough estimate of the difference between this and using a fresh
379+ // [(String,JSON)] for the `pairs` variable in decodeObject() below is
380+ // about 12% on an iPhone 5.
381+ private struct DecodeObjectBuffers {
382+ var buffers = [[(String,JSON)]]()
383+
384+ mutating func getBuffer() -> [(String,JSON)] {
385+ if !buffers.isEmpty {
386+ var buffer = buffers.removeLast()
387+ buffer.removeAll(keepCapacity: true)
388+ return buffer
389+ }
390+ return [(String,JSON)]()
391+ }
392+
393+ mutating func putBuffer(buffer: [(String,JSON)]) {
394+ buffers.append(buffer)
395+ }
396+ }
397+
398+ private var decodeObjectBuffers = DecodeObjectBuffers()
399+
400+ private mutating func decodeObject() throws -> JSON {
401+ let start = loc
402+ loc = loc.successor()
403+ var pairs = decodeObjectBuffers.getBuffer()
404+
405+ while loc < input.count {
406+ skipWhitespace()
407+
408+ if loc < input.count && input[loc] == Literal.RIGHT_BRACE {
409+ loc = loc.successor()
410+ var obj = [String:JSON](minimumCapacity: pairs.count)
411+ for (k, v) in pairs {
412+ obj[k] = v
413+ }
414+ decodeObjectBuffers.putBuffer(pairs)
415+ return .Dictionary(obj)
416+ }
417+
418+ if !pairs.isEmpty {
419+ guard loc < input.count && input[loc] == Literal.COMMA else {
420+ throw Error.CollectionMissingSeparator(offset: start)
421+ }
422+ loc = loc.successor()
423+
424+ skipWhitespace()
425+ }
426+
427+ guard loc < input.count && input[loc] == Literal.DOUBLE_QUOTE else {
428+ throw Error.DictionaryMissingKey(offset: start)
429+ }
430+
431+ let key = try decodeString().string()
432+ skipWhitespace()
433+
434+ guard loc < input.count && input[loc] == Literal.COLON else {
435+ throw Error.CollectionMissingSeparator(offset: start)
436+ }
437+ loc = loc.successor()
438+
439+ pairs.append((key, try parseValue()))
440+ }
441+
442+ throw Error.EndOfStreamUnexpected
443+ }
444+
445+ private mutating func decodeIntegralValue(parser: NumberParser) throws -> JSON {
446+ var sign = Sign.Positive
447+ var parser = parser
448+ var value = 0
449+
450+ // This would be more natural as `while true { ... }` with a meaningful .Done case,
451+ // but that causes compile time explosion in Swift 2.2. :-|
452+ while parser.state != .Done {
453+ switch parser.state {
454+ case .LeadingMinus:
455+ sign = .Negative
456+ try parser.parseNegative()
457+
458+ case .LeadingZero:
459+ parser.parseLeadingZero()
460+
461+ case .PreDecimalDigits:
462+ try parser.parsePreDecimalDigits { c in
463+ guard case let (exponent, false) = Int.multiplyWithOverflow(10, value) else {
464+ throw InternalError.NumberOverflow(offset: parser.start)
465+ }
466+
467+ guard case let (newValue, false) = Int.addWithOverflow(exponent, Int(c - Literal.zero)) else {
468+ throw InternalError.NumberOverflow(offset: parser.start)
469+ }
470+
471+ value = newValue
472+ }
473+
474+ case .Decimal, .Exponent:
475+ return try detectingFloatingPointErrors(parser.start) {
476+ try decodeFloatingPointValue(parser, sign: sign, value: Double(value))
477+ }
478+
479+ case .PostDecimalDigits, .ExponentSign, .ExponentDigits:
480+ assertionFailure("Invalid internal state while parsing number")
481+
482+ case .Done:
483+ fatalError("impossible condition")
484+ }
485+ }
486+
487+ guard case let (signedValue, false) = Int.multiplyWithOverflow(sign.rawValue, value) else {
488+ throw InternalError.NumberOverflow(offset: parser.start)
489+ }
490+
491+ loc = parser.loc
492+ return .Int(signedValue)
493+ }
494+
495+ private mutating func decodeFloatingPointValue(parser: NumberParser, sign: Sign, value: Double) throws -> JSON {
496+ var parser = parser
497+ var value = value
498+ var exponentSign = Sign.Positive
499+ var exponent = Double(0)
500+ var position = 0.1
501+
502+ // This would be more natural as `while true { ... }` with a meaningful .Done case,
503+ // but that causes compile time explosion in Swift 2.2. :-|
504+ while parser.state != .Done {
505+ switch parser.state {
506+ case .LeadingMinus, .LeadingZero, .PreDecimalDigits:
507+ assertionFailure("Invalid internal state while parsing number")
508+
509+ case .Decimal:
510+ try parser.parseDecimal()
511+
512+ case .PostDecimalDigits:
513+ parser.parsePostDecimalDigits { c in
514+ value += position * Double(c - Literal.zero)
515+ position /= 10
516+ }
517+
518+ case .Exponent:
519+ exponentSign = try parser.parseExponent()
520+
521+ case .ExponentSign:
522+ try parser.parseExponentSign()
523+
524+ case .ExponentDigits:
525+ parser.parseExponentDigits { c in
526+ exponent = exponent * 10 + Double(c - Literal.zero)
527+ }
528+
529+ case .Done:
530+ fatalError("impossible condition")
531+ }
532+ }
533+
534+ loc = parser.loc
535+ return .Double(Double(sign.rawValue) * value * pow(10, Double(exponentSign.rawValue) * exponent))
536+ }
537+
538+ private mutating func decodeNumberAsString(start: Int) throws -> JSON {
539+ var parser: NumberParser = {
540+ let state: NumberParser.State
541+ switch input[start] {
542+ case Literal.MINUS: state = .LeadingMinus
543+ case Literal.zero: state = .LeadingZero
544+ case Literal.one...Literal.nine: state = .PreDecimalDigits
545+ default:
546+ fatalError("Internal error: decodeNumber called on not-a-number")
547+ }
548+ return NumberParser(loc: start, input: input, state: state)
549+ }()
550+
551+ stringDecodingBuffer.removeAll(keepCapacity: true)
552+
553+ while true {
554+ switch parser.state {
555+ case .LeadingMinus:
556+ try parser.parseNegative()
557+ stringDecodingBuffer.append(Literal.MINUS)
558+
559+ case .LeadingZero:
560+ parser.parseLeadingZero()
561+ stringDecodingBuffer.append(Literal.zero)
562+
563+ case .PreDecimalDigits:
564+ parser.parsePreDecimalDigits { stringDecodingBuffer.append($0) }
565+
566+ case .Decimal:
567+ try parser.parseDecimal()
568+ stringDecodingBuffer.append(Literal.PERIOD)
569+
570+ case .PostDecimalDigits:
571+ parser.parsePostDecimalDigits { stringDecodingBuffer.append($0) }
572+
573+ case .Exponent:
574+ stringDecodingBuffer.append(input[parser.loc])
575+ _ = try parser.parseExponent()
576+
577+ case .ExponentSign:
578+ stringDecodingBuffer.append(input[parser.loc])
579+ try parser.parseExponentSign()
580+
581+ case .ExponentDigits:
582+ parser.parseExponentDigits { stringDecodingBuffer.append($0) }
583+
584+ case .Done:
585+ stringDecodingBuffer.append(0)
586+ guard let string = (stringDecodingBuffer.withUnsafeBufferPointer {
587+ String.fromCString(UnsafePointer($0.baseAddress))
588+ }) else {
589+ // Should never fail - any problems with the number string should
590+ // result in thrown errors above
591+ fatalError("Internal error: Invalid numeric string")
592+ }
593+
594+ loc = parser.loc
595+ return .String(string)
596+ }
597+ }
598+ }
599+
600+ private func detectingFloatingPointErrors<T>(loc: Int, @noescape _ f: () throws -> T) throws -> T {
601+ let flags = FE_UNDERFLOW | FE_OVERFLOW
602+ feclearexcept(flags)
603+ let value = try f()
604+ guard fetestexcept(flags) == 0 else {
605+ throw InternalError.NumberOverflow(offset: loc)
606+ }
607+ return value
608+ }
609+}
610+
611+private struct NumberParser {
612+ enum State {
613+ case LeadingMinus
614+ case LeadingZero
615+ case PreDecimalDigits
616+ case Decimal
617+ case PostDecimalDigits
618+ case Exponent
619+ case ExponentSign
620+ case ExponentDigits
621+ case Done
622+ }
623+
624+ let start: Int
625+ var loc = 0
626+ var state: State
627+ let input: UnsafeBufferPointer<UInt8>
628+
629+ init(loc: Int, input: UnsafeBufferPointer<UInt8>, state: State) {
630+ assert(loc < input.count, "Invalid input to NumberParser")
631+ self.start = loc
632+ self.loc = loc
633+ self.input = input
634+ self.state = state
635+ }
636+
637+ mutating func parseNegative() throws {
638+ assert(state == .LeadingMinus, "Unexpected state entering parseNegative")
639+
640+ loc = loc.successor()
641+ guard loc < input.count else {
642+ throw JSONParser.Error.EndOfStreamUnexpected
643+ }
644+
645+ switch input[loc] {
646+ case Literal.zero:
647+ state = .LeadingZero
648+
649+ case Literal.one...Literal.nine:
650+ state = .PreDecimalDigits
651+
652+ default:
653+ throw JSONParser.Error.NumberSymbolMissingDigits(offset: start)
654+ }
655+ }
656+
657+ mutating func parseLeadingZero() {
658+ assert(state == .LeadingZero, "Unexpected state entering parseLeadingZero")
659+
660+ loc = loc.successor()
661+ guard loc < input.count else {
662+ state = .Done
663+ return
664+ }
665+
666+ guard input[loc] == Literal.PERIOD else {
667+ state = .Done
668+ return
669+ }
670+
671+ state = .Decimal
672+ }
673+
674+ mutating func parsePreDecimalDigits(@noescape f: (UInt8) throws -> Void) rethrows {
675+ assert(state == .PreDecimalDigits, "Unexpected state entering parsePreDecimalDigits")
676+ advancing: while loc < input.count {
677+ let c = input[loc]
678+ switch c {
679+ case Literal.zero...Literal.nine:
680+ try f(c)
681+ loc = loc.successor()
682+
683+ case Literal.PERIOD:
684+ state = .Decimal
685+ return
686+
687+ case Literal.e, Literal.E:
688+ state = .Exponent
689+ return
690+
691+ default:
692+ break advancing
693+ }
694+ }
695+
696+ state = .Done
697+ }
698+
699+ mutating func parseDecimal() throws {
700+ assert(state == .Decimal, "Unexpected state entering parseDecimal")
701+ loc = loc.successor()
702+ guard loc < input.count else {
703+ throw JSONParser.Error.EndOfStreamUnexpected
704+ }
705+
706+ switch input[loc] {
707+ case Literal.zero...Literal.nine:
708+ state = .PostDecimalDigits
709+
710+ default:
711+ throw JSONParser.Error.NumberMissingFractionalDigits(offset: start)
712+ }
713+ }
714+
715+ mutating func parsePostDecimalDigits(@noescape f: (UInt8) throws -> Void) rethrows {
716+ assert(state == .PostDecimalDigits, "Unexpected state entering parsePostDecimalDigits")
717+
718+ advancing: while loc < input.count {
719+ let c = input[loc]
720+ switch c {
721+ case Literal.zero...Literal.nine:
722+ try f(c)
723+ loc = loc.successor()
724+
725+ case Literal.e, Literal.E:
726+ state = .Exponent
727+ return
728+
729+ default:
730+ break advancing
731+ }
732+ }
733+
734+ state = .Done
735+ }
736+
737+ mutating func parseExponent() throws -> JSONParser.Sign {
738+ assert(state == .Exponent, "Unexpected state entering parseExponent")
739+
740+ loc = loc.successor()
741+ guard loc < input.count else {
742+ throw JSONParser.Error.EndOfStreamUnexpected
743+ }
744+
745+ switch input[loc] {
746+ case Literal.zero...Literal.nine:
747+ state = .ExponentDigits
748+
749+ case Literal.PLUS:
750+ state = .ExponentSign
751+
752+ case Literal.MINUS:
753+ state = .ExponentSign
754+ return .Negative
755+
756+ default:
757+ throw JSONParser.Error.NumberSymbolMissingDigits(offset: start)
758+ }
759+
760+ return .Positive
761+ }
762+
763+ mutating func parseExponentSign() throws {
764+ assert(state == .ExponentSign, "Unexpected state entering parseExponentSign")
765+ loc = loc.successor()
766+ guard loc < input.count else {
767+ throw JSONParser.Error.EndOfStreamUnexpected
768+ }
769+
770+ switch input[loc] {
771+ case Literal.zero...Literal.nine:
772+ state = .ExponentDigits
773+
774+ default:
775+ throw JSONParser.Error.NumberSymbolMissingDigits(offset: start)
776+ }
777+ }
778+
779+ mutating func parseExponentDigits(@noescape f: (UInt8) throws -> Void) rethrows {
780+ assert(state == .ExponentDigits, "Unexpected state entering parseExponentDigits")
781+ advancing: while loc < input.count {
782+ let c = input[loc]
783+ switch c {
784+ case Literal.zero...Literal.nine:
785+ try f(c)
786+ loc = loc.successor()
787+
788+ default:
789+ break advancing
790+ }
791+ }
792+
793+ state = .Done
794+ }
795+}
796+
797+public extension JSONParser {
798+
799+ /// Creates a `JSONParser` ready to parse UTF-8 encoded `NSData`.
800+ ///
801+ /// If the data is mutable, it is copied before parsing. The data's lifetime
802+ /// is extended for the duration of parsing.
803+ init(utf8Data inData: NSData) {
804+ let data = inData.copy() as! NSData
805+ let buffer = UnsafeBufferPointer(start: UnsafePointer<UInt8>(data.bytes), count: data.length)
806+ self.init(buffer: buffer, owner: data)
807+ }
808+
809+ /// Creates a `JSONParser` from the code units represented by the `string`.
810+ ///
811+ /// The synthesized string is lifetime-extended for the duration of parsing.
812+ init(string: String) {
813+ let codePoints = string.nulTerminatedUTF8
814+ let buffer = codePoints.withUnsafeBufferPointer { nulTerminatedBuffer in
815+ // don't want to include the nul termination in the buffer - trim it off
816+ UnsafeBufferPointer(start: nulTerminatedBuffer.baseAddress, count: nulTerminatedBuffer.count - 1)
817+ }
818+ self.init(buffer: buffer, owner: codePoints)
819+ }
820+
821+}
822+
823+extension JSONParser: JSONParserType {
824+
825+ /// Creates an instance of `JSON` from UTF-8 encoded `NSData`.
826+ /// - parameter data: An instance of `NSData` to parse `JSON` from.
827+ /// - throws: Any `JSONParser.Error` that arises during decoding.
828+ /// - seealso: JSONParser.parse()
829+ public static func createJSONFromData(data: NSData) throws -> JSON {
830+ var parser = JSONParser(utf8Data: data)
831+ return try parser.parse()
832+ }
833+
834+}
835+
836+// MARK: - Errors
837+
838+extension JSONParser {
839+
840+ /// Enumeration describing possible errors that occur while parsing a JSON
841+ /// document. Most errors include an associated `offset`, representing the
842+ /// offset into the UTF-8 characters making up the document where the error
843+ /// occurred.
844+ public enum Error: ErrorType {
845+ /// The parser ran out of data prematurely. This usually means a value
846+ /// was not escaped, such as a string literal not ending with a double
847+ /// quote.
848+ case EndOfStreamUnexpected
849+
850+ /// Unexpected non-whitespace data was left around `offset` after
851+ /// parsing all valid JSON.
852+ case EndOfStreamGarbage(offset: Int)
853+
854+ /// Too many nested objects or arrays occured at the literal started
855+ /// around `offset`.
856+ case ExceededNestingLimit(offset: Int)
857+
858+ /// A `character` was not a valid start of a value around `offset`.
859+ case ValueInvalid(offset: Int, character: UnicodeScalar)
860+
861+ /// Badly-formed Unicode escape sequence at `offset`. A Unicode escape
862+ /// uses the text "\u" followed by 4 hex digits, such as "\uF09F\uA684"
863+ /// to represent U+1F984, "UNICORN FACE".
864+ case UnicodeEscapeInvalid(offset: Int)
865+
866+ /// Badly-formed control character around `offset`. JSON supports
867+ /// backslash-escaped double quotes, slashes, whitespace control codes,
868+ /// and Unicode escape sequences.
869+ case ControlCharacterUnrecognized(offset: Int)
870+
871+ /// Invalid token, expected `null` around `offset`
872+ case LiteralNilMisspelled(offset: Int)
873+
874+ /// Invalid token, expected `true` around `offset`
875+ case LiteralTrueMisspelled(offset: Int)
876+
877+ /// Invalid token, expected `false` around `offset`
878+ case LiteralFalseMisspelled(offset: Int)
879+
880+ /// Badly-formed collection at given `offset`, expected `,` or `:`
881+ case CollectionMissingSeparator(offset: Int)
882+
883+ /// While parsing an object literal, a value was found without a key
884+ /// around `offset`. The start of a string literal was expected.
885+ case DictionaryMissingKey(offset: Int)
886+
887+ /// Badly-formed number with no digits around `offset`. After a decimal
888+ /// point, a number must include some number of digits.
889+ case NumberMissingFractionalDigits(offset: Int)
890+
891+ /// Badly-formed number with symbols ("-" or "e") but no following
892+ /// digits around `offset`.
893+ case NumberSymbolMissingDigits(offset: Int)
894+
895+ /// Supplied data is encoded in an unsupported format.
896+ case InvalidUnicodeStreamEncoding(detectedEncoding: JSONEncodingDetector.Encoding)
897+ }
898+
899+ private enum InternalError: ErrorType {
900+ /// Attempted to parse an integer outside the range of [Int.min, Int.max]
901+ /// or a double outside the range of representable doubles. Note that
902+ /// for doubles, this could be an overflow or an underflow - we don't
903+ /// get enough information from Swift here to know which it is. The number
904+ /// causing the overflow/underflow began at `offset`.
905+ case NumberOverflow(offset: Int)
906+ }
907+}
parsers/test_Freddy_20160830/test_Freddy/JSONParsing.swiftnew file+126
@@ -0,0 +1,126 @@
1+//
2+// JSONParsing.swift
3+// Freddy
4+//
5+// Created by Matthew D. Mathias on 3/17/15.
6+// Copyright © 2015 Big Nerd Ranch. All rights reserved.
7+//
8+
9+import Foundation
10+
11+// MARK: - Deserialize JSON
12+
13+/// Protocol describing a backend parser that can produce `JSON` from `NSData`.
14+public protocol JSONParserType {
15+
16+ /// Creates an instance of `JSON` from `NSData`.
17+ /// - parameter data: An instance of `NSData` to use to create `JSON`.
18+ /// - throws: An error that may arise from calling `JSONObjectWithData(_:options:)` on `NSJSONSerialization` with the given data.
19+ /// - returns: An instance of `JSON`.
20+ static func createJSONFromData(data: NSData) throws -> JSON
21+
22+}
23+
24+extension JSON {
25+
26+ /// Create `JSON` from UTF-8 `data`. By default, parses using the
27+ /// Swift-native `JSONParser` backend.
28+ public init(data: NSData, usingParser parser: JSONParserType.Type = JSONParser.self) throws {
29+ self = try parser.createJSONFromData(data)
30+ }
31+
32+ /// Create `JSON` from UTF-8 `string`.
33+ public init(jsonString: Swift.String, usingParser parser: JSONParserType.Type = JSONParser.self) throws {
34+ self = try parser.createJSONFromData((jsonString as NSString).dataUsingEncoding(NSUTF8StringEncoding) ?? NSData())
35+ }
36+}
37+
38+// MARK: - NSJSONSerialization
39+
40+extension NSJSONSerialization: JSONParserType {
41+
42+ // MARK: Decode NSData
43+
44+ /// Use the built-in, Objective-C based JSON parser to create `JSON`.
45+ /// - parameter data: An instance of `NSData`.
46+ /// - returns: An instance of `JSON`.
47+ /// - throws: An error that may arise if the `NSData` cannot be parsed into an object.
48+ public static func createJSONFromData(data: NSData) throws -> JSON {
49+ return makeJSON(try NSJSONSerialization.JSONObjectWithData(data, options: []))
50+ }
51+
52+ // MARK: Make JSON
53+
54+ /// Makes a `JSON` object by matching its argument to a case in the `JSON` enum.
55+ /// - parameter object: The instance of `AnyObject` returned from serializing the JSON.
56+ /// - returns: An instance of `JSON` matching the JSON given to the function.
57+ private static func makeJSON(object: AnyObject) -> JSON {
58+ switch object {
59+ case let n as NSNumber:
60+ let numberType = CFNumberGetType(n)
61+ switch numberType {
62+ case .CharType:
63+ return .Bool(n.boolValue)
64+
65+ case .ShortType, .IntType, .LongType, .CFIndexType, .NSIntegerType, .SInt8Type, .SInt16Type, .SInt32Type:
66+ return .Int(n.integerValue)
67+
68+ case .SInt64Type, .LongLongType /* overflows 32-bit Int */:
69+ #if /* 32-bit arch */ arch(arm) || arch(i386)
70+ // Why double, when the Freddy parser would bump to String?
71+ //
72+ // Returning Double avoids making the type depend on whether you're running
73+ // 32-bit or 64-bit code when using the NSJSONSerialization parser.
74+ // NSJSONSerialization appears to bump numbers larger than Int.max to Double on
75+ // 64-bit platforms but use .SInt64Type on 32-bit platforms.
76+ // If we returned a String here, you'd get a String value on 32-bit,
77+ // but a Double value on 64-bit. Instead, we return Double.
78+ //
79+ // This means that, if you switch parsers,
80+ // you'll have to switch from .double to .string for pulling out
81+ // overflowing values, but if you stick with a single parser,
82+ // you at least won't have architecture-dependent lookups!
83+ return .Double(n.doubleValue)
84+ #else
85+ return .Int(n.integerValue)
86+ #endif
87+
88+ case .Float32Type, .Float64Type, .FloatType, .DoubleType, .CGFloatType:
89+ return .Double(n.doubleValue)
90+ }
91+
92+ case let arr as [AnyObject]:
93+ return makeJSONArray(arr)
94+
95+ case let dict as [Swift.String: AnyObject]:
96+ return makeJSONDictionary(dict)
97+
98+ case let s as Swift.String:
99+ return .String(s)
100+
101+ default:
102+ return .Null
103+ }
104+ }
105+
106+ // MARK: Make a JSON Array
107+
108+ /// Makes a `JSON` array from the object passed in.
109+ /// - parameter jsonArray: The array to transform into a `JSON`.
110+ /// - returns: An instance of `JSON` matching the array.
111+ private static func makeJSONArray(jsonArray: [AnyObject]) -> JSON {
112+ return .Array(jsonArray.map(makeJSON))
113+ }
114+
115+ // MARK: Make a JSON Dictionary
116+
117+ /// Makes a `JSON` dictionary from the Cocoa dictionary passed in.
118+ /// - parameter jsonDict: The dictionary to transform into `JSON`.
119+ /// - returns: An instance of `JSON` matching the dictionary.
120+ private static func makeJSONDictionary(jsonDict: [Swift.String: AnyObject]) -> JSON {
121+ return JSON(jsonDict.lazy.map { (key, value) in
122+ (key, makeJSON(value))
123+ })
124+ }
125+
126+}
parsers/test_Freddy_20160830/test_Freddy/JSONSerializing.swiftnew file+43
@@ -0,0 +1,43 @@
1+// Copyright (C) 2016 Big Nerd Ranch, Inc. Licensed under the MIT license WITHOUT ANY WARRANTY.
2+
3+import Foundation
4+
5+// MARK: - Serialize JSON
6+
7+extension JSON {
8+
9+ /// Attempt to serialize `JSON` into an `NSData`.
10+ /// - returns: A byte-stream containing the `JSON` ready for wire transfer.
11+ /// - throws: Errors that arise from `NSJSONSerialization`.
12+ /// - see: Foundation.NSJSONSerialization
13+ public func serialize() throws -> NSData {
14+ let obj: AnyObject = toNSJSONSerializationObject()
15+ return try NSJSONSerialization.dataWithJSONObject(obj, options: [])
16+ }
17+
18+ /// A function to help with the serialization of `JSON`.
19+ /// - returns: An `AnyObject` suitable for `NSJSONSerialization`'s use.
20+ private func toNSJSONSerializationObject() -> AnyObject {
21+ switch self {
22+ case .Array(let jsonArray):
23+ return jsonArray.map { $0.toNSJSONSerializationObject() }
24+ case .Dictionary(let jsonDictionary):
25+ var cocoaDictionary = Swift.Dictionary<Swift.String, AnyObject>(minimumCapacity: jsonDictionary.count)
26+ for (key, json) in jsonDictionary {
27+ cocoaDictionary[key] = json.toNSJSONSerializationObject()
28+ }
29+ return cocoaDictionary
30+ case .String(let str):
31+ return str
32+ case .Double(let num):
33+ return num
34+ case .Int(let int):
35+ return int
36+ case .Bool(let b):
37+ return b
38+ case .Null:
39+ return NSNull()
40+ }
41+
42+ }
43+}
parsers/test_Freddy_20160830/test_Freddy/JSONSubscripting.swiftnew file+705
@@ -0,0 +1,705 @@
1+//
2+// JSONSubscripting.swift
3+// Freddy
4+//
5+// Created by Zachary Waldowski on 8/15/15.
6+// Copyright © 2015 Big Nerd Ranch. All rights reserved.
7+//
8+
9+// MARK: JSONPathType
10+
11+/// A protocol used to define a path within an instance of `JSON` that leads to some desired value.
12+///
13+/// A custom type, such as a `RawRepresentable` enum, may be made to conform to `JSONPathType`
14+/// and used with the subscript APIs.
15+public protocol JSONPathType {
16+ /// Use `self` to key into a `dictionary`.
17+ ///
18+ /// Unlike Swift dictionaries, failing to find a value for a key should throw
19+ /// an error rather than convert to `nil`.
20+ ///
21+ /// Upon failure, implementers should throw an error from `JSON.Error`.
22+ func valueInDictionary(dictionary: [Swift.String : JSON]) throws -> JSON
23+
24+ /// Use `self` to index into an `array`.
25+ ///
26+ /// Unlike Swift array, attempting to index outside the collection's bounds
27+ /// should throw an error rather than crash.
28+ ///
29+ /// Upon failure, implementers should throw an error from `JSON.Error`.
30+ func valueInArray(array: [JSON]) throws -> JSON
31+}
32+
33+extension JSONPathType {
34+
35+ /// The default behavior for keying into a dictionary is to throw
36+ /// `JSON.Error.UnexpectedSubscript`.
37+ public func valueInDictionary(dictionary: [Swift.String : JSON]) throws -> JSON {
38+ throw JSON.Error.UnexpectedSubscript(type: Self.self)
39+ }
40+
41+ /// The default behavior for indexing into an array is to throw
42+ /// `JSON.Error.UnexpectedSubscript`.
43+ public func valueInArray(array: [JSON]) throws -> JSON {
44+ throw JSON.Error.UnexpectedSubscript(type: Self.self)
45+ }
46+
47+}
48+
49+extension String: JSONPathType {
50+
51+ /// A method used to retrieve a value from a given dictionary for a specific key.
52+ /// - parameter dictionary: A `Dictionary` with `String` keys and `JSON` values.
53+ /// - throws: `.KeyNotFound` with an associated value of `self`, where `self` is a `String`,
54+ /// should the key not be present within the `JSON`.
55+ /// - returns: The `JSON` value associated with the given key.
56+ public func valueInDictionary(dictionary: [Swift.String : JSON]) throws -> JSON {
57+ guard let next = dictionary[self] else {
58+ throw JSON.Error.KeyNotFound(key: self)
59+ }
60+ return next
61+ }
62+
63+}
64+
65+extension Int: JSONPathType {
66+
67+ /// A method used to retrieve a value from a given array for a specific index.
68+ /// - parameter array: An `Array` of `JSON`.
69+ /// - throws: `.IndexOutOfBounds` with an associated value of `self`, where `self` is an `Int`,
70+ /// should the index not be within the valid range for the array of `JSON`.
71+ /// - returns: The `JSON` value found at the given index.
72+ public func valueInArray(array: [JSON]) throws -> JSON {
73+ guard case array.indices = self else {
74+ throw JSON.Error.IndexOutOfBounds(index: self)
75+ }
76+ return array[self]
77+ }
78+
79+}
80+
81+// MARK: - Subscripting core
82+
83+private extension JSON {
84+
85+ enum SubscriptError: ErrorType {
86+ case SubscriptIntoNull(JSONPathType)
87+ }
88+
89+ func valueForPathFragment(fragment: JSONPathType, detectNull: Swift.Bool) throws -> JSON {
90+ switch self {
91+ case .Null where detectNull:
92+ throw SubscriptError.SubscriptIntoNull(fragment)
93+ case let .Dictionary(dict):
94+ return try fragment.valueInDictionary(dict)
95+ case let .Array(array):
96+ return try fragment.valueInArray(array)
97+ default:
98+ throw Error.UnexpectedSubscript(type: fragment.dynamicType)
99+ }
100+ }
101+
102+ func valueAtPath(path: [JSONPathType], detectNull: Swift.Bool = false) throws -> JSON {
103+ var result = self
104+ for fragment in path {
105+ result = try result.valueForPathFragment(fragment, detectNull: detectNull)
106+ }
107+ return result
108+ }
109+
110+}
111+
112+// MARK: - Subscripting operator
113+
114+extension JSON {
115+
116+ public subscript(key: Swift.String) -> JSON? {
117+ return try? valueForPathFragment(key, detectNull: false)
118+ }
119+
120+ public subscript(index: Swift.Int) -> JSON? {
121+ return try? valueForPathFragment(index, detectNull: false)
122+ }
123+
124+}
125+
126+// MARK: - Simple member unpacking
127+
128+extension JSON {
129+
130+ /// Attempts to decode into the returning type from a path into JSON.
131+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`.
132+ /// - parameter type: If the context this method is called from does not
133+ /// make the return type clear, pass a type implementing `JSONDecodable`
134+ /// to disambiguate the type to decode with.
135+ /// - returns: An initialized member from the inner JSON.
136+ /// - throws: One of the following errors contained in `JSON.Error`:
137+ /// * `KeyNotFound`: A given `String` key does not exist inside a
138+ /// descendant `JSON` dictionary.
139+ /// * `IndexOutOfBounds`: A given `Int` index is outside the bounds of a
140+ /// descendant `JSON` array.
141+ /// * `UnexpectedSubscript`: A given subscript cannot be used with the
142+ /// corresponding `JSON` value.
143+ /// * `TypeNotConvertible`: The target value's type inside of
144+ /// the `JSON` instance does not match `Decoded`.
145+ public func decode<Decoded: JSONDecodable>(path: JSONPathType..., type: Decoded.Type = Decoded.self) throws -> Decoded {
146+ return try Decoded(json: valueAtPath(path))
147+ }
148+
149+ /// Retrieves a `Double` from a path into JSON.
150+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
151+ /// - returns: A floating-point `Double`
152+ /// - throws: One of the `JSON.Error` cases thrown by `decode(_:type:)`.
153+ /// - seealso: `JSON.decode(_:type:)`
154+ public func double(path: JSONPathType...) throws -> Swift.Double {
155+ return try Swift.Double(json: valueAtPath(path))
156+ }
157+
158+ /// Retrieves an `Int` from a path into JSON.
159+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
160+ /// - returns: A numeric `Int`
161+ /// - throws: One of the `JSON.Error` cases thrown by `decode(_:type:)`.
162+ /// - seealso: `JSON.decode(_:type:)`
163+ public func int(path: JSONPathType...) throws -> Swift.Int {
164+ return try Swift.Int(json: valueAtPath(path))
165+ }
166+
167+ /// Retrieves a `String` from a path into JSON.
168+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
169+ /// - returns: A textual `String`
170+ /// - throws: One of the `JSON.Error` cases thrown by `decode(_:type:)`.
171+ /// - seealso: `JSON.decode(_:type:)`
172+ public func string(path: JSONPathType...) throws -> Swift.String {
173+ return try Swift.String(json: valueAtPath(path))
174+ }
175+
176+ /// Retrieves a `Bool` from a path into JSON.
177+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
178+ /// - returns: A truthy `Bool`
179+ /// - throws: One of the `JSON.Error` cases thrown by `decode(_:type:)`.
180+ /// - seealso: `JSON.decode(_:type:)`
181+ public func bool(path: JSONPathType...) throws -> Swift.Bool {
182+ return try Swift.Bool(json: valueAtPath(path))
183+ }
184+
185+ /// Retrieves a `[JSON]` from a path into JSON.
186+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
187+ /// - returns: An `Array` of `JSON` elements
188+ /// - throws: One of the `JSON.Error` cases thrown by `decode(_:type:)`.
189+ /// - seealso: `JSON.decode(_:type:)`
190+ public func array(path: JSONPathType...) throws -> [JSON] {
191+ return try JSON.getArray(valueAtPath(path))
192+ }
193+
194+ /// Attempts to decode many values from a descendant JSON array at a path
195+ /// into JSON.
196+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
197+ /// - parameter type: If the context this method is called from does not
198+ /// make the return type clear, pass a type implementing `JSONDecodable`
199+ /// to disambiguate the type to decode with.
200+ /// - returns: An `Array` of decoded elements
201+ /// - throws: One of the `JSON.Error` cases thrown by `decode(_:type:)`, or
202+ /// any error that arises from decoding the contained values.
203+ /// - seealso: `JSON.decode(_:type:)`
204+ public func arrayOf<Decoded: JSONDecodable>(path: JSONPathType..., type: Decoded.Type = Decoded.self) throws -> [Decoded] {
205+ return try JSON.getArrayOf(valueAtPath(path))
206+ }
207+
208+ /// Retrieves a `[String: JSON]` from a path into JSON.
209+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
210+ /// - returns: An `Dictionary` of `String` mapping to `JSON` elements
211+ /// - throws: One of the `JSON.Error` cases thrown by `decode(_:type:)`.
212+ /// - seealso: `JSON.decode(_:type:)`
213+ public func dictionary(path: JSONPathType...) throws -> [Swift.String: JSON] {
214+ return try JSON.getDictionary(valueAtPath(path))
215+ }
216+
217+ /// Attempts to decode many values from a descendant JSON object at a path
218+ /// into JSON.
219+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
220+ /// - parameter type: If the context this method is called from does not
221+ /// make the return type clear, pass a type implementing `JSONDecodable`
222+ /// to disambiguate the value type to decode with.
223+ /// - returns: A `Dictionary` of `String` keys and decoded values.
224+ /// - throws: One of the `JSON.Error` cases thrown by `decode(_:type:)` or
225+ /// any error that arises from decoding the contained values.
226+ /// - seealso: `JSON.decode(_:type:)`
227+ public func dictionaryOf<Decoded: JSONDecodable>(path: JSONPathType..., type: Decoded.Type = Decoded.self) throws -> [Swift.String: Decoded] {
228+ return try JSON.getDictionaryOf(valueAtPath(path))
229+ }
230+
231+}
232+
233+// MARK: - NotFound-Or-Null-to-Optional unpacking
234+
235+extension JSON {
236+
237+ /// An `OptionSetType` used to represent the different options available for subscripting `JSON` with `null` values or missing keys.
238+ /// * `.NullBecomesNil` - Treat `null` values as `nil`.
239+ /// * `.MissingKeyBecomesNil` - Treat missing keys as `nil`.
240+ public struct SubscriptingOptions: OptionSetType {
241+ public let rawValue: Swift.Int
242+ public init(rawValue: Swift.Int) {
243+ self.rawValue = rawValue
244+ }
245+
246+ /// Treat `null` values as `nil`.
247+ public static let NullBecomesNil = SubscriptingOptions(rawValue: 1 << 0)
248+ /// Treat missing keys as `nil`.
249+ public static let MissingKeyBecomesNil = SubscriptingOptions(rawValue: 1 << 1)
250+ }
251+
252+ private func mapOptionalAtPath<Value>(path: [JSONPathType], alongPath: SubscriptingOptions, @noescape transform: JSON throws -> Value) throws -> Value? {
253+ let detectNull = alongPath.contains(.NullBecomesNil)
254+ let detectNotFound = alongPath.contains(.MissingKeyBecomesNil)
255+ var json: JSON?
256+ do {
257+ json = try valueAtPath(path, detectNull: detectNull)
258+ return try json.map(transform)
259+ } catch Error.IndexOutOfBounds where detectNotFound {
260+ return nil
261+ } catch Error.KeyNotFound where detectNotFound {
262+ return nil
263+ } catch Error.ValueNotConvertible where detectNull && json == .Null {
264+ return nil
265+ } catch SubscriptError.SubscriptIntoNull where detectNull {
266+ return nil
267+ }
268+ }
269+}
270+
271+extension JSON {
272+
273+ /// Optionally decodes into the returning type from a path into JSON.
274+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
275+ /// - parameter alongPath: Options that control what should be done with values that are `null` or keys that are missing.
276+ /// - parameter type: If the context this method is called from does not
277+ /// make the return type clear, pass a type implementing `JSONDecodable`
278+ /// to disambiguate the type to decode with.
279+ /// - returns: A decoded value from the inner JSON if found, or `nil`.
280+ /// - throws: One of the following errors contained in `JSON.Error`:
281+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
282+ /// `JSON` dictionary.
283+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
284+ /// descendant `JSON` array.
285+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
286+ /// corresponding `JSON` value.
287+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
288+ /// instance does not match the decoded value.
289+ /// * Any error that arises from decoding the value.
290+ public func decode<Decoded: JSONDecodable>(path: JSONPathType..., alongPath options: SubscriptingOptions, type: Decoded.Type = Decoded.self) throws -> Decoded? {
291+ return try mapOptionalAtPath(path, alongPath: options, transform: Decoded.init)
292+ }
293+
294+ /// Optionally retrieves a `Double` from a path into JSON.
295+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`.
296+ /// - parameter alongPath: Options that control what should be done with values that are `null` or keys that are missing.
297+ /// - returns: A `Double` if a value could be found, otherwise `nil`.
298+ /// - throws: One of the following errors contained in `JSON.Error`:
299+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
300+ /// `JSON` dictionary.
301+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
302+ /// descendant `JSON` array.
303+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
304+ /// corresponding `JSON` value.
305+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
306+ /// instance does not match the decoded value.
307+ public func double(path: JSONPathType..., alongPath options: SubscriptingOptions) throws -> Swift.Double? {
308+ return try mapOptionalAtPath(path, alongPath: options, transform: Swift.Double.init)
309+ }
310+
311+ /// Optionally retrieves a `Int` from a path into JSON.
312+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
313+ /// - parameter alongPath: Options that control what should be done with values that are `null` or keys that are missing.
314+ /// - returns: A numeric `Int` if a value could be found, otherwise `nil`.
315+ /// - throws: One of the following errors contained in `JSON.Error`:
316+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
317+ /// `JSON` dictionary.
318+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
319+ /// descendant `JSON` array.
320+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
321+ /// corresponding `JSON` value.
322+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
323+ /// instance does not match the decoded value.
324+ public func int(path: JSONPathType..., alongPath options: SubscriptingOptions) throws -> Swift.Int? {
325+ return try mapOptionalAtPath(path, alongPath: options, transform: Swift.Int.init)
326+ }
327+
328+ /// Optionally retrieves a `String` from a path into JSON.
329+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
330+ /// - parameter alongPath: Options that control what should be done with values that are `null` or keys that are missing.
331+ /// - returns: A text `String` if a value could be found, otherwise `nil`.
332+ /// - throws: One of the following errors contained in `JSON.Error`:
333+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
334+ /// `JSON` dictionary.
335+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
336+ /// descendant `JSON` array.
337+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
338+ /// corresponding `JSON` value.
339+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
340+ /// instance does not match the decoded value.
341+ public func string(path: JSONPathType..., alongPath options: SubscriptingOptions) throws -> Swift.String? {
342+ return try mapOptionalAtPath(path, alongPath: options, transform: Swift.String.init)
343+ }
344+
345+ /// Optionally retrieves a `Bool` from a path into JSON.
346+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
347+ /// - parameter alongPath: Options that control what should be done with values that are `null` or keys that are missing.
348+ /// - returns: A truthy `Bool` if a value could be found, otherwise `nil`.
349+ /// - throws: One of the following errors contained in `JSON.Error`:
350+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
351+ /// `JSON` dictionary.
352+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
353+ /// descendant `JSON` array.
354+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
355+ /// corresponding `JSON` value.
356+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
357+ /// instance does not match the decoded value.
358+ public func bool(path: JSONPathType..., alongPath options: SubscriptingOptions) throws -> Swift.Bool? {
359+ return try mapOptionalAtPath(path, alongPath: options, transform: Swift.Bool.init)
360+ }
361+
362+ /// Optionally retrieves a `[JSON]` from a path into the recieving structure.
363+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
364+ /// - parameter alongPath: Options that control what should be done with values that are `null` or keys that are missing.
365+ /// - returns: An `Array` of `JSON` elements if a value could be found,
366+ /// otherwise `nil`.
367+ /// - throws: One of the following errors contained in `JSON.Error`:
368+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
369+ /// `JSON` dictionary.
370+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
371+ /// descendant `JSON` array.
372+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
373+ /// corresponding `JSON` value.
374+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
375+ /// instance does not match the decoded value.
376+ public func array(path: JSONPathType..., alongPath options: SubscriptingOptions) throws -> [JSON]? {
377+ return try mapOptionalAtPath(path, alongPath: options, transform: JSON.getArray)
378+ }
379+
380+ /// Optionally decodes many values from a descendant array at a path into
381+ /// JSON.
382+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
383+ /// - parameter alongPath: Options that control what should be done with values that are `null` or keys that are missing.
384+ /// - parameter type: If the context this method is called from does not
385+ /// make the return type clear, pass a type implementing `JSONDecodable`
386+ /// to disambiguate the value type to decode with.
387+ /// - returns: An `Array` of decoded elements if found, otherwise `nil`.
388+ /// - throws: One of the following errors contained in `JSON.Error`:
389+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
390+ /// `JSON` dictionary.
391+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
392+ /// descendant `JSON` array.
393+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
394+ /// corresponding `JSON` value.
395+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
396+ /// instance does not match the decoded value.
397+ /// * Any error that arises from decoding the value.
398+ public func arrayOf<Decoded: JSONDecodable>(path: JSONPathType..., alongPath options: SubscriptingOptions, type: Decoded.Type = Decoded.self) throws -> [Decoded]? {
399+ return try mapOptionalAtPath(path, alongPath: options, transform: JSON.getArrayOf)
400+ }
401+
402+ /// Optionally retrieves a `[String: JSON]` from a path into the recieving
403+ /// structure.
404+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
405+ /// - parameter alongPath: Options that control what should be done with values that are `null` or keys that are missing.
406+ /// - returns: A `Dictionary` of `String` mapping to `JSON` elements if a
407+ /// value could be found, otherwise `nil`.
408+ /// - throws: One of the following errors contained in `JSON.Error`:
409+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
410+ /// `JSON` dictionary.
411+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
412+ /// descendant `JSON` array.
413+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
414+ /// corresponding `JSON` value.
415+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
416+ /// instance does not match the decoded value.
417+ public func dictionary(path: JSONPathType..., alongPath options: SubscriptingOptions) throws -> [Swift.String: JSON]? {
418+ return try mapOptionalAtPath(path, alongPath: options, transform: JSON.getDictionary)
419+ }
420+
421+ /// Optionally attempts to decode many values from a descendant object at a path
422+ /// into JSON.
423+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
424+ /// - parameter alongPath: Options that control what should be done with values that are `null` or keys that are missing.
425+ /// - parameter type: If the context this method is called from does not
426+ /// make the return type clear, pass a type implementing `JSONDecodable`
427+ /// to disambiguate the value type to decode with.
428+ /// - returns: A `Dictionary` of `String` mapping to decoded elements if a
429+ /// value could be found, otherwise `nil`.
430+ /// - throws: One of the following errors contained in `JSON.Error`:
431+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
432+ /// `JSON` dictionary.
433+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
434+ /// descendant `JSON` array.
435+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
436+ /// corresponding `JSON` value.
437+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
438+ /// instance does not match the decoded value.
439+ /// * Any error that arises from decoding the value.
440+ public func dictionaryOf<Decoded: JSONDecodable>(path: JSONPathType..., alongPath options: SubscriptingOptions, type: Decoded.Type = Decoded.self) throws -> [Swift.String: Decoded]? {
441+ return try mapOptionalAtPath(path, alongPath: options, transform: JSON.getDictionaryOf)
442+ }
443+
444+}
445+
446+// MARK: - Missing-with-fallback unpacking
447+
448+extension JSON {
449+
450+ private func mapOptionalAtPath<Value>(path: [JSONPathType], @noescape fallback: () -> Value, @noescape transform: JSON throws -> Value) throws -> Value {
451+ return try mapOptionalAtPath(path, alongPath: .MissingKeyBecomesNil, transform: transform) ?? fallback()
452+ }
453+
454+ /// Attempts to decode into the returning type from a path into
455+ /// JSON, or returns a fallback if not found.
456+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
457+ /// - parameter fallback: Value to use when one is missing at the subscript.
458+ /// - returns: An initialized member from the inner JSON.
459+ /// - throws: One of the following errors contained in `JSON.Error`:
460+ /// * `UnexpectedSubscript`: A given subscript cannot be used with the
461+ /// corresponding `JSON` value.
462+ /// * `TypeNotConvertible`: The target value's type inside of
463+ /// the `JSON` instance does not match `Decoded`.
464+ public func decode<Decoded: JSONDecodable>(path: JSONPathType..., @autoclosure or fallback: () -> Decoded) throws -> Decoded {
465+ return try mapOptionalAtPath(path, fallback: fallback, transform: Decoded.init)
466+ }
467+
468+ /// Retrieves a `Double` from a path into JSON or a fallback if not found.
469+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
470+ /// - parameter fallback: `Double` to use when one is missing at the subscript.
471+ /// - returns: A floating-point `Double`
472+ /// - throws: One of the `JSON.Error` cases thrown by calling `mapOptionalAtPath(_:fallback:transform:)`.
473+ /// - seealso: `optionalAtPath(_:ifNotFound)`.
474+ public func double(path: JSONPathType..., @autoclosure or fallback: () -> Swift.Double) throws -> Swift.Double {
475+ return try mapOptionalAtPath(path, fallback: fallback, transform: Swift.Double.init)
476+ }
477+
478+ /// Retrieves an `Int` from a path into JSON or a fallback if not found.
479+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
480+ /// - parameter fallback: `Int` to use when one is missing at the subscript.
481+ /// - returns: A numeric `Int`
482+ /// - throws: One of the following errors contained in `JSON.Error`:
483+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
484+ /// `JSON` dictionary.
485+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
486+ /// descendant `JSON` array.
487+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
488+ /// corresponding `JSON` value.
489+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
490+ /// instance does not match the decoded value.
491+ public func int(path: JSONPathType..., @autoclosure or fallback: () -> Swift.Int) throws -> Swift.Int {
492+ return try mapOptionalAtPath(path, fallback: fallback, transform: Swift.Int.init)
493+ }
494+
495+ /// Retrieves a `String` from a path into JSON or a fallback if not found.
496+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
497+ /// - parameter fallback: `String` to use when one is missing at the subscript.
498+ /// - returns: A textual `String`
499+ /// - throws: One of the following errors contained in `JSON.Error`:
500+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
501+ /// `JSON` dictionary.
502+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
503+ /// descendant `JSON` array.
504+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
505+ /// corresponding `JSON` value.
506+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
507+ /// instance does not match the decoded value.
508+ public func string(path: JSONPathType..., @autoclosure or fallback: () -> Swift.String) throws -> Swift.String {
509+ return try mapOptionalAtPath(path, fallback: fallback, transform: Swift.String.init)
510+ }
511+
512+ /// Retrieves a `Bool` from a path into JSON or a fallback if not found.
513+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
514+ /// - parameter fallback: `Bool` to use when one is missing at the subscript.
515+ /// - returns: A truthy `Bool`
516+ /// - throws: One of the following errors contained in `JSON.Error`:
517+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
518+ /// `JSON` dictionary.
519+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
520+ /// descendant `JSON` array.
521+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
522+ /// corresponding `JSON` value.
523+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
524+ /// instance does not match the decoded value.
525+ public func bool(path: JSONPathType..., @autoclosure or fallback: () -> Swift.Bool) throws -> Swift.Bool {
526+ return try mapOptionalAtPath(path, fallback: fallback, transform: Swift.Bool.init)
527+ }
528+
529+ /// Retrieves a `[JSON]` from a path into JSON or a fallback if not found.
530+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
531+ /// - parameter fallback: `Array` to use when one is missing at the subscript.
532+ /// - returns: An `Array` of `JSON` elements
533+ /// - throws: One of the following errors contained in `JSON.Error`:
534+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
535+ /// `JSON` dictionary.
536+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
537+ /// descendant `JSON` array.
538+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
539+ /// corresponding `JSON` value.
540+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
541+ /// instance does not match the decoded value.
542+ public func array(path: JSONPathType..., @autoclosure or fallback: () -> [JSON]) throws -> [JSON] {
543+ return try mapOptionalAtPath(path, fallback: fallback, transform: JSON.getArray)
544+ }
545+
546+ /// Attempts to decodes many values from a desendant JSON array at a path
547+ /// into the recieving structure, returning a fallback if not found.
548+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
549+ /// - parameter fallback: `Array` to use when one is missing at the subscript.
550+ /// - returns: An `Array` of decoded elements
551+ /// - throws: One of the following errors contained in `JSON.Error`:
552+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
553+ /// `JSON` dictionary.
554+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
555+ /// descendant `JSON` array.
556+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
557+ /// corresponding `JSON` value.
558+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
559+ /// instance does not match the decoded value.
560+ /// * Any error that arises from decoding the value.
561+ public func arrayOf<Decoded: JSONDecodable>(path: JSONPathType..., @autoclosure or fallback: () -> [Decoded]) throws -> [Decoded] {
562+ return try mapOptionalAtPath(path, fallback: fallback, transform: JSON.getArrayOf)
563+ }
564+
565+ /// Retrieves a `[String: JSON]` from a path into JSON or a fallback if not
566+ /// found.
567+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
568+ /// - parameter fallback: `Dictionary` to use when one is missing at the subscript.
569+ /// - returns: An `Dictionary` of `String` mapping to `JSON` elements
570+ /// - throws: One of the following errors contained in `JSON.Error`:
571+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
572+ /// `JSON` dictionary.
573+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
574+ /// descendant `JSON` array.
575+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
576+ /// corresponding `JSON` value.
577+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
578+ /// instance does not match the decoded value.
579+ public func dictionary(path: JSONPathType..., @autoclosure or fallback: () -> [Swift.String: JSON]) throws -> [Swift.String: JSON] {
580+ return try mapOptionalAtPath(path, fallback: fallback, transform: JSON.getDictionary)
581+ }
582+
583+ /// Attempts to decode many values from a descendant JSON object at a path
584+ /// into the receiving structure, returning a fallback if not found.
585+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
586+ /// - parameter fallback: Value to use when one is missing at the subscript
587+ /// - returns: A `Dictionary` of `String` mapping to decoded elements.
588+ /// - throws: One of the following errors contained in `JSON.Error`:
589+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
590+ /// `JSON` dictionary.
591+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
592+ /// descendant `JSON` array.
593+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
594+ /// corresponding `JSON` value.
595+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
596+ /// instance does not match the decoded value.
597+ /// * Any error that arises from decoding the value.
598+ public func dictionaryOf<Decoded: JSONDecodable>(path: JSONPathType..., @autoclosure or fallback: () -> [Swift.String: Decoded]) throws -> [Swift.String: Decoded] {
599+ return try mapOptionalAtPath(path, fallback: fallback, transform: JSON.getDictionaryOf)
600+ }
601+
602+
603+}
604+
605+// MARK: - Deprecated methods
606+
607+extension JSON {
608+
609+ @available(*, deprecated, message="Use 'decode(_:alongPath:type:)' with options '[.MissingKeyBecomesNil]'")
610+ public func decode<Decoded: JSONDecodable>(path: JSONPathType..., ifNotFound: Swift.Bool, type: Decoded.Type = Decoded.self) throws -> Decoded? {
611+ let options: SubscriptingOptions = ifNotFound ? [.MissingKeyBecomesNil] : []
612+ return try mapOptionalAtPath(path, alongPath: options, transform: Decoded.init)
613+ }
614+
615+ @available(*, deprecated, message="Use 'decode(_:alongPath:type:)' with options '[.NullBecomesNil]'")
616+ public func decode<Decoded: JSONDecodable>(path: JSONPathType..., ifNull: Swift.Bool, type: Decoded.Type = Decoded.self) throws -> Decoded? {
617+ let options: SubscriptingOptions = ifNull ? [.NullBecomesNil] : []
618+ return try mapOptionalAtPath(path, alongPath: options, transform: Decoded.init)
619+ }
620+
621+ @available(*, deprecated, message="Use 'double(_:alongPath:)' with options '[.MissingKeyBecomesNil]'")
622+ public func double(path: JSONPathType..., ifNotFound: Swift.Bool) throws -> Swift.Double? {
623+ let options: SubscriptingOptions = ifNotFound ? [.MissingKeyBecomesNil] : []
624+ return try mapOptionalAtPath(path, alongPath: options, transform: Swift.Double.init)
625+ }
626+
627+ @available(*, deprecated, message="Use 'double(_:alongPath:)' with options '[.NullBecomesNil]'")
628+ public func double(path: JSONPathType..., ifNull: Swift.Bool) throws -> Swift.Double? {
629+ let options: SubscriptingOptions = ifNull ? [.NullBecomesNil] : []
630+ return try mapOptionalAtPath(path, alongPath: options, transform: Swift.Double.init)
631+ }
632+
633+ @available(*, deprecated, message="Use 'int(_:alongPath:)' with options '[.MissingKeyBecomesNil]'")
634+ public func int(path: JSONPathType..., ifNotFound: Swift.Bool) throws -> Swift.Int? {
635+ let options: SubscriptingOptions = ifNotFound ? [.MissingKeyBecomesNil] : []
636+ return try mapOptionalAtPath(path, alongPath: options, transform: Swift.Int.init)
637+ }
638+
639+ @available(*, deprecated, message="Use 'int(_:alongPath:)' with options '[.NullBecomesNil]'")
640+ public func int(path: JSONPathType..., ifNull: Swift.Bool) throws -> Swift.Int? {
641+ let options: SubscriptingOptions = ifNull ? [.NullBecomesNil] : []
642+ return try mapOptionalAtPath(path, alongPath: options, transform: Swift.Int.init)
643+ }
644+
645+ @available(*, deprecated, message="Use 'string(_:alongPath:)' with options '[.MissingKeyBecomesNil]'")
646+ public func string(path: JSONPathType..., ifNotFound: Swift.Bool) throws -> Swift.String? {
647+ let options: SubscriptingOptions = ifNotFound ? [.MissingKeyBecomesNil] : []
648+ return try mapOptionalAtPath(path, alongPath: options, transform: Swift.String.init)
649+ }
650+
651+ @available(*, deprecated, message="Use 'string(_:alongPath:)' with options '[.NullBecomesNil]'")
652+ public func string(path: JSONPathType..., ifNull: Swift.Bool) throws -> Swift.String? {
653+ let options: SubscriptingOptions = ifNull ? [.NullBecomesNil] : []
654+ return try mapOptionalAtPath(path, alongPath: options, transform: Swift.String.init)
655+ }
656+
657+ @available(*, deprecated, message="Use 'bool(_:alongPath:)' with options '[.MissingKeyBecomesNil]'")
658+ public func bool(path: JSONPathType..., ifNotFound: Swift.Bool) throws -> Swift.Bool? {
659+ let options: SubscriptingOptions = ifNotFound ? [.MissingKeyBecomesNil] : []
660+ return try mapOptionalAtPath(path, alongPath: options, transform: Swift.Bool.init)
661+ }
662+
663+ @available(*, deprecated, message="Use 'bool(_:alongPath:)' with options '[.NullBecomesNil]'")
664+ public func bool(path: JSONPathType..., ifNull: Swift.Bool) throws -> Swift.Bool? {
665+ let options: SubscriptingOptions = ifNull ? [.NullBecomesNil] : []
666+ return try mapOptionalAtPath(path, alongPath: options, transform: Swift.Bool.init)
667+ }
668+
669+ @available(*, deprecated, message="Use 'array(_:alongPath:)' with options '[.MissingKeyBecomesNil]'")
670+ public func array(path: JSONPathType..., ifNotFound: Swift.Bool) throws -> [JSON]? {
671+ let options: SubscriptingOptions = ifNotFound ? [.MissingKeyBecomesNil] : []
672+ return try mapOptionalAtPath(path, alongPath: options, transform: JSON.getArray)
673+ }
674+
675+ @available(*, deprecated, message="Use 'array(_:alongPath:)' with options '[.NullBecomesNil]'")
676+ public func array(path: JSONPathType..., ifNull: Swift.Bool) throws -> [JSON]? {
677+ let options: SubscriptingOptions = ifNull ? [.NullBecomesNil] : []
678+ return try mapOptionalAtPath(path, alongPath: options, transform: JSON.getArray)
679+ }
680+
681+ @available(*, deprecated, message="Use 'arrayOf(_:alongPath:)' with options '[.MissingKeyBecomesNil]'")
682+ public func arrayOf<Decoded: JSONDecodable>(path: JSONPathType..., ifNotFound: Swift.Bool) throws -> [Decoded]? {
683+ let options: SubscriptingOptions = ifNotFound ? [.MissingKeyBecomesNil] : []
684+ return try mapOptionalAtPath(path, alongPath: options, transform: JSON.getArrayOf)
685+ }
686+
687+ @available(*, deprecated, message="Use 'arrayOf(_:alongPath:)' with options '[.NullBecomesNil]'")
688+ public func arrayOf<Decoded: JSONDecodable>(path: JSONPathType..., ifNull: Swift.Bool) throws -> [Decoded]? {
689+ let options: SubscriptingOptions = ifNull ? [.NullBecomesNil] : []
690+ return try mapOptionalAtPath(path, alongPath: options, transform: JSON.getArrayOf)
691+ }
692+
693+ @available(*, deprecated, message="Use 'dictionary(_:alongPath:)' with options '[.MissingKeyBecomesNil]'")
694+ public func dictionary(path: JSONPathType..., ifNotFound: Swift.Bool) throws -> [Swift.String: JSON]? {
695+ let options: SubscriptingOptions = ifNotFound ? [.MissingKeyBecomesNil] : []
696+ return try mapOptionalAtPath(path, alongPath: options, transform: JSON.getDictionary)
697+ }
698+
699+ @available(*, deprecated, message="Use 'dictionary(_:alongPath:)' with options '[.NullBecomesNil]'")
700+ public func dictionary(path: JSONPathType..., ifNull: Swift.Bool) throws -> [Swift.String: JSON]? {
701+ let options: SubscriptingOptions = ifNull ? [.NullBecomesNil] : []
702+ return try mapOptionalAtPath(path, alongPath: options, transform: JSON.getDictionary)
703+ }
704+
705+}
parsers/test_Freddy_20160830/test_Freddy/main.swiftnew file+37
@@ -0,0 +1,37 @@
1+//
2+// main.swift
3+// test_Freddy
4+//
5+// Created by nst on 10/08/16.
6+// Copyright © 2016 Nicolas Seriot. All rights reserved.
7+//
8+
9+import Foundation
10+
11+func main() {
12+
13+ guard Process.arguments.count == 2 else {
14+ let url = NSURL(fileURLWithPath: Process.arguments[0])
15+ guard let programName = url.lastPathComponent else { exit(1) }
16+ print("Usage: ./\(programName) file.json")
17+ exit(1)
18+ }
19+
20+ let path = Process.arguments[1]
21+ let url = NSURL.fileURLWithPath(path)
22+
23+ guard let data = NSData(contentsOfURL:url) else {
24+ print("*** CANNOT READ DATA AT \(url)")
25+ return
26+ }
27+
28+ var p = JSONParser(utf8Data: data)
29+ do {
30+ try p.parse()
31+ exit(0)
32+ } catch {
33+ exit(1)
34+ }
35+}
36+
37+main()
parsers/test_Freddy_20161018/bin/test_Freddynew file

Binary file not shown.

parsers/test_Freddy_20161018/test_Freddy.xcodeproj/project.pbxprojnew file+300
@@ -0,0 +1,300 @@
1+// !$*UTF8*$!
2+{
3+ archiveVersion = 1;
4+ classes = {
5+ };
6+ objectVersion = 46;
7+ objects = {
8+
9+/* Begin PBXBuildFile section */
10+ 03D84ABB1D5B0A1000776402 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03D84ABA1D5B0A1000776402 /* main.swift */; };
11+ 03F8F7811D5B75600021630C /* JSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03F8F7781D5B75600021630C /* JSON.swift */; };
12+ 03F8F7821D5B75600021630C /* JSONDecodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03F8F7791D5B75600021630C /* JSONDecodable.swift */; };
13+ 03F8F7831D5B75600021630C /* JSONEncodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03F8F77A1D5B75600021630C /* JSONEncodable.swift */; };
14+ 03F8F7841D5B75600021630C /* JSONEncodingDetector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03F8F77B1D5B75600021630C /* JSONEncodingDetector.swift */; };
15+ 03F8F7851D5B75600021630C /* JSONLiteralConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03F8F77C1D5B75600021630C /* JSONLiteralConvertible.swift */; };
16+ 03F8F7861D5B75600021630C /* JSONParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03F8F77D1D5B75600021630C /* JSONParser.swift */; };
17+ 03F8F7871D5B75600021630C /* JSONParsing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03F8F77E1D5B75600021630C /* JSONParsing.swift */; };
18+ 03F8F7881D5B75600021630C /* JSONSerializing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03F8F77F1D5B75600021630C /* JSONSerializing.swift */; };
19+ 03F8F7891D5B75600021630C /* JSONSubscripting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03F8F7801D5B75600021630C /* JSONSubscripting.swift */; };
20+/* End PBXBuildFile section */
21+
22+/* Begin PBXCopyFilesBuildPhase section */
23+ 03D84AB51D5B0A1000776402 /* CopyFiles */ = {
24+ isa = PBXCopyFilesBuildPhase;
25+ buildActionMask = 2147483647;
26+ dstPath = /usr/share/man/man1;
27+ dstSubfolderSpec = 0;
28+ files = (
29+ );
30+ runOnlyForDeploymentPostprocessing = 1;
31+ };
32+/* End PBXCopyFilesBuildPhase section */
33+
34+/* Begin PBXFileReference section */
35+ 03D84AB71D5B0A1000776402 /* test_Freddy */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = test_Freddy; sourceTree = BUILT_PRODUCTS_DIR; };
36+ 03D84ABA1D5B0A1000776402 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
37+ 03F8F7781D5B75600021630C /* JSON.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = JSON.swift; path = test_Freddy/JSON.swift; sourceTree = "<group>"; };
38+ 03F8F7791D5B75600021630C /* JSONDecodable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = JSONDecodable.swift; path = test_Freddy/JSONDecodable.swift; sourceTree = "<group>"; };
39+ 03F8F77A1D5B75600021630C /* JSONEncodable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = JSONEncodable.swift; path = test_Freddy/JSONEncodable.swift; sourceTree = "<group>"; };
40+ 03F8F77B1D5B75600021630C /* JSONEncodingDetector.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = JSONEncodingDetector.swift; path = test_Freddy/JSONEncodingDetector.swift; sourceTree = "<group>"; };
41+ 03F8F77C1D5B75600021630C /* JSONLiteralConvertible.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = JSONLiteralConvertible.swift; path = test_Freddy/JSONLiteralConvertible.swift; sourceTree = "<group>"; };
42+ 03F8F77D1D5B75600021630C /* JSONParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = JSONParser.swift; path = test_Freddy/JSONParser.swift; sourceTree = "<group>"; };
43+ 03F8F77E1D5B75600021630C /* JSONParsing.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = JSONParsing.swift; path = test_Freddy/JSONParsing.swift; sourceTree = "<group>"; };
44+ 03F8F77F1D5B75600021630C /* JSONSerializing.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = JSONSerializing.swift; path = test_Freddy/JSONSerializing.swift; sourceTree = "<group>"; };
45+ 03F8F7801D5B75600021630C /* JSONSubscripting.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = JSONSubscripting.swift; path = test_Freddy/JSONSubscripting.swift; sourceTree = "<group>"; };
46+/* End PBXFileReference section */
47+
48+/* Begin PBXFrameworksBuildPhase section */
49+ 03D84AB41D5B0A1000776402 /* Frameworks */ = {
50+ isa = PBXFrameworksBuildPhase;
51+ buildActionMask = 2147483647;
52+ files = (
53+ );
54+ runOnlyForDeploymentPostprocessing = 0;
55+ };
56+/* End PBXFrameworksBuildPhase section */
57+
58+/* Begin PBXGroup section */
59+ 03D84AAE1D5B0A1000776402 = {
60+ isa = PBXGroup;
61+ children = (
62+ 03F8F7781D5B75600021630C /* JSON.swift */,
63+ 03F8F7791D5B75600021630C /* JSONDecodable.swift */,
64+ 03F8F77A1D5B75600021630C /* JSONEncodable.swift */,
65+ 03F8F77B1D5B75600021630C /* JSONEncodingDetector.swift */,
66+ 03F8F77C1D5B75600021630C /* JSONLiteralConvertible.swift */,
67+ 03F8F77D1D5B75600021630C /* JSONParser.swift */,
68+ 03F8F77E1D5B75600021630C /* JSONParsing.swift */,
69+ 03F8F77F1D5B75600021630C /* JSONSerializing.swift */,
70+ 03F8F7801D5B75600021630C /* JSONSubscripting.swift */,
71+ 03D84AB91D5B0A1000776402 /* test_Freddy */,
72+ 03D84AB81D5B0A1000776402 /* Products */,
73+ );
74+ sourceTree = "<group>";
75+ };
76+ 03D84AB81D5B0A1000776402 /* Products */ = {
77+ isa = PBXGroup;
78+ children = (
79+ 03D84AB71D5B0A1000776402 /* test_Freddy */,
80+ );
81+ name = Products;
82+ sourceTree = "<group>";
83+ };
84+ 03D84AB91D5B0A1000776402 /* test_Freddy */ = {
85+ isa = PBXGroup;
86+ children = (
87+ 03D84ABA1D5B0A1000776402 /* main.swift */,
88+ );
89+ path = test_Freddy;
90+ sourceTree = "<group>";
91+ };
92+/* End PBXGroup section */
93+
94+/* Begin PBXNativeTarget section */
95+ 03D84AB61D5B0A1000776402 /* test_Freddy */ = {
96+ isa = PBXNativeTarget;
97+ buildConfigurationList = 03D84ABE1D5B0A1000776402 /* Build configuration list for PBXNativeTarget "test_Freddy" */;
98+ buildPhases = (
99+ 03D84AB31D5B0A1000776402 /* Sources */,
100+ 03D84AB41D5B0A1000776402 /* Frameworks */,
101+ 03D84AB51D5B0A1000776402 /* CopyFiles */,
102+ );
103+ buildRules = (
104+ );
105+ dependencies = (
106+ );
107+ name = test_Freddy;
108+ productName = test_Freddy;
109+ productReference = 03D84AB71D5B0A1000776402 /* test_Freddy */;
110+ productType = "com.apple.product-type.tool";
111+ };
112+/* End PBXNativeTarget section */
113+
114+/* Begin PBXProject section */
115+ 03D84AAF1D5B0A1000776402 /* Project object */ = {
116+ isa = PBXProject;
117+ attributes = {
118+ LastSwiftUpdateCheck = 0800;
119+ LastUpgradeCheck = 0800;
120+ ORGANIZATIONNAME = "Nicolas Seriot";
121+ TargetAttributes = {
122+ 03D84AB61D5B0A1000776402 = {
123+ CreatedOnToolsVersion = 8.0;
124+ DevelopmentTeam = VBYRKYS73S;
125+ DevelopmentTeamName = "Nicolas Seriot";
126+ ProvisioningStyle = Automatic;
127+ };
128+ };
129+ };
130+ buildConfigurationList = 03D84AB21D5B0A1000776402 /* Build configuration list for PBXProject "test_Freddy" */;
131+ compatibilityVersion = "Xcode 3.2";
132+ developmentRegion = English;
133+ hasScannedForEncodings = 0;
134+ knownRegions = (
135+ en,
136+ );
137+ mainGroup = 03D84AAE1D5B0A1000776402;
138+ productRefGroup = 03D84AB81D5B0A1000776402 /* Products */;
139+ projectDirPath = "";
140+ projectRoot = "";
141+ targets = (
142+ 03D84AB61D5B0A1000776402 /* test_Freddy */,
143+ );
144+ };
145+/* End PBXProject section */
146+
147+/* Begin PBXSourcesBuildPhase section */
148+ 03D84AB31D5B0A1000776402 /* Sources */ = {
149+ isa = PBXSourcesBuildPhase;
150+ buildActionMask = 2147483647;
151+ files = (
152+ 03F8F7881D5B75600021630C /* JSONSerializing.swift in Sources */,
153+ 03F8F7821D5B75600021630C /* JSONDecodable.swift in Sources */,
154+ 03F8F7851D5B75600021630C /* JSONLiteralConvertible.swift in Sources */,
155+ 03F8F7871D5B75600021630C /* JSONParsing.swift in Sources */,
156+ 03F8F7861D5B75600021630C /* JSONParser.swift in Sources */,
157+ 03F8F7831D5B75600021630C /* JSONEncodable.swift in Sources */,
158+ 03D84ABB1D5B0A1000776402 /* main.swift in Sources */,
159+ 03F8F7811D5B75600021630C /* JSON.swift in Sources */,
160+ 03F8F7891D5B75600021630C /* JSONSubscripting.swift in Sources */,
161+ 03F8F7841D5B75600021630C /* JSONEncodingDetector.swift in Sources */,
162+ );
163+ runOnlyForDeploymentPostprocessing = 0;
164+ };
165+/* End PBXSourcesBuildPhase section */
166+
167+/* Begin XCBuildConfiguration section */
168+ 03D84ABC1D5B0A1000776402 /* Debug */ = {
169+ isa = XCBuildConfiguration;
170+ buildSettings = {
171+ ALWAYS_SEARCH_USER_PATHS = NO;
172+ CLANG_ANALYZER_NONNULL = YES;
173+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
174+ CLANG_CXX_LIBRARY = "libc++";
175+ CLANG_ENABLE_MODULES = YES;
176+ CLANG_ENABLE_OBJC_ARC = YES;
177+ CLANG_WARN_BOOL_CONVERSION = YES;
178+ CLANG_WARN_CONSTANT_CONVERSION = YES;
179+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
180+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
181+ CLANG_WARN_EMPTY_BODY = YES;
182+ CLANG_WARN_ENUM_CONVERSION = YES;
183+ CLANG_WARN_INT_CONVERSION = YES;
184+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
185+ CLANG_WARN_UNREACHABLE_CODE = YES;
186+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
187+ CODE_SIGN_IDENTITY = "-";
188+ COPY_PHASE_STRIP = NO;
189+ DEBUG_INFORMATION_FORMAT = dwarf;
190+ ENABLE_STRICT_OBJC_MSGSEND = YES;
191+ ENABLE_TESTABILITY = YES;
192+ GCC_C_LANGUAGE_STANDARD = gnu99;
193+ GCC_DYNAMIC_NO_PIC = NO;
194+ GCC_NO_COMMON_BLOCKS = YES;
195+ GCC_OPTIMIZATION_LEVEL = 0;
196+ GCC_PREPROCESSOR_DEFINITIONS = (
197+ "DEBUG=1",
198+ "$(inherited)",
199+ );
200+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
201+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
202+ GCC_WARN_UNDECLARED_SELECTOR = YES;
203+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
204+ GCC_WARN_UNUSED_FUNCTION = YES;
205+ GCC_WARN_UNUSED_VARIABLE = YES;
206+ MACOSX_DEPLOYMENT_TARGET = 10.11;
207+ MTL_ENABLE_DEBUG_INFO = YES;
208+ ONLY_ACTIVE_ARCH = YES;
209+ SDKROOT = macosx;
210+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
211+ };
212+ name = Debug;
213+ };
214+ 03D84ABD1D5B0A1000776402 /* Release */ = {
215+ isa = XCBuildConfiguration;
216+ buildSettings = {
217+ ALWAYS_SEARCH_USER_PATHS = NO;
218+ CLANG_ANALYZER_NONNULL = YES;
219+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
220+ CLANG_CXX_LIBRARY = "libc++";
221+ CLANG_ENABLE_MODULES = YES;
222+ CLANG_ENABLE_OBJC_ARC = YES;
223+ CLANG_WARN_BOOL_CONVERSION = YES;
224+ CLANG_WARN_CONSTANT_CONVERSION = YES;
225+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
226+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
227+ CLANG_WARN_EMPTY_BODY = YES;
228+ CLANG_WARN_ENUM_CONVERSION = YES;
229+ CLANG_WARN_INT_CONVERSION = YES;
230+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
231+ CLANG_WARN_UNREACHABLE_CODE = YES;
232+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
233+ CODE_SIGN_IDENTITY = "-";
234+ COPY_PHASE_STRIP = NO;
235+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
236+ ENABLE_NS_ASSERTIONS = NO;
237+ ENABLE_STRICT_OBJC_MSGSEND = YES;
238+ GCC_C_LANGUAGE_STANDARD = gnu99;
239+ GCC_NO_COMMON_BLOCKS = YES;
240+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
241+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
242+ GCC_WARN_UNDECLARED_SELECTOR = YES;
243+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
244+ GCC_WARN_UNUSED_FUNCTION = YES;
245+ GCC_WARN_UNUSED_VARIABLE = YES;
246+ MACOSX_DEPLOYMENT_TARGET = 10.11;
247+ MTL_ENABLE_DEBUG_INFO = NO;
248+ SDKROOT = macosx;
249+ };
250+ name = Release;
251+ };
252+ 03D84ABF1D5B0A1000776402 /* Debug */ = {
253+ isa = XCBuildConfiguration;
254+ buildSettings = {
255+ FRAMEWORK_SEARCH_PATHS = (
256+ "$(inherited)",
257+ "$(PROJECT_DIR)",
258+ );
259+ PRODUCT_NAME = "$(TARGET_NAME)";
260+ SWIFT_VERSION = 3.0;
261+ };
262+ name = Debug;
263+ };
264+ 03D84AC01D5B0A1000776402 /* Release */ = {
265+ isa = XCBuildConfiguration;
266+ buildSettings = {
267+ FRAMEWORK_SEARCH_PATHS = (
268+ "$(inherited)",
269+ "$(PROJECT_DIR)",
270+ );
271+ PRODUCT_NAME = "$(TARGET_NAME)";
272+ SWIFT_VERSION = 3.0;
273+ };
274+ name = Release;
275+ };
276+/* End XCBuildConfiguration section */
277+
278+/* Begin XCConfigurationList section */
279+ 03D84AB21D5B0A1000776402 /* Build configuration list for PBXProject "test_Freddy" */ = {
280+ isa = XCConfigurationList;
281+ buildConfigurations = (
282+ 03D84ABC1D5B0A1000776402 /* Debug */,
283+ 03D84ABD1D5B0A1000776402 /* Release */,
284+ );
285+ defaultConfigurationIsVisible = 0;
286+ defaultConfigurationName = Release;
287+ };
288+ 03D84ABE1D5B0A1000776402 /* Build configuration list for PBXNativeTarget "test_Freddy" */ = {
289+ isa = XCConfigurationList;
290+ buildConfigurations = (
291+ 03D84ABF1D5B0A1000776402 /* Debug */,
292+ 03D84AC01D5B0A1000776402 /* Release */,
293+ );
294+ defaultConfigurationIsVisible = 0;
295+ defaultConfigurationName = Release;
296+ };
297+/* End XCConfigurationList section */
298+ };
299+ rootObject = 03D84AAF1D5B0A1000776402 /* Project object */;
300+}
parsers/test_Freddy_20161018/test_Freddy.xcodeproj/project.xcworkspace/contents.xcworkspacedatanew file+7
@@ -0,0 +1,7 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<Workspace
3+ version = "1.0">
4+ <FileRef
5+ location = "self:test_Freddy.xcodeproj">
6+ </FileRef>
7+</Workspace>
parsers/test_Freddy_20161018/test_Freddy.xcodeproj/project.xcworkspace/xcshareddata/test_Freddy.xcscmblueprintnew file+30
@@ -0,0 +1,30 @@
1+{
2+ "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "ED13D74FC1ED9BC322EA1859E5AD7D001676FA6A",
3+ "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : {
4+
5+ },
6+ "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : {
7+ "6ADA245F937D8ED6D99F5A7865E19F5267A169E2" : 0,
8+ "ED13D74FC1ED9BC322EA1859E5AD7D001676FA6A" : 0
9+ },
10+ "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "7B3DFA55-F9BF-41D8-8FD5-204D3162EB03",
11+ "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : {
12+ "6ADA245F937D8ED6D99F5A7865E19F5267A169E2" : "dropbox\/JSON\/test_Freddy\/Vendor\/Freddy\/",
13+ "ED13D74FC1ED9BC322EA1859E5AD7D001676FA6A" : "dropbox\/"
14+ },
15+ "DVTSourceControlWorkspaceBlueprintNameKey" : "test_Freddy",
16+ "DVTSourceControlWorkspaceBlueprintVersion" : 204,
17+ "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "JSON\/test_Freddy\/test_Freddy.xcodeproj",
18+ "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [
19+ {
20+ "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/bignerdranch\/Freddy.git",
21+ "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
22+ "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "6ADA245F937D8ED6D99F5A7865E19F5267A169E2"
23+ },
24+ {
25+ "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "\/Users\/nst\/Dropbox\/dropbox.git",
26+ "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
27+ "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "ED13D74FC1ED9BC322EA1859E5AD7D001676FA6A"
28+ }
29+ ]
30+}
parsers/test_Freddy_20161018/test_Freddy.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstatenew file

Binary file not shown.

parsers/test_Freddy_20161018/test_Freddy.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test_Freddy.xcschemenew file+91
@@ -0,0 +1,91 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<Scheme
3+ LastUpgradeVersion = "0800"
4+ version = "1.3">
5+ <BuildAction
6+ parallelizeBuildables = "YES"
7+ buildImplicitDependencies = "YES">
8+ <BuildActionEntries>
9+ <BuildActionEntry
10+ buildForTesting = "YES"
11+ buildForRunning = "YES"
12+ buildForProfiling = "YES"
13+ buildForArchiving = "YES"
14+ buildForAnalyzing = "YES">
15+ <BuildableReference
16+ BuildableIdentifier = "primary"
17+ BlueprintIdentifier = "03D84AB61D5B0A1000776402"
18+ BuildableName = "test_Freddy"
19+ BlueprintName = "test_Freddy"
20+ ReferencedContainer = "container:test_Freddy.xcodeproj">
21+ </BuildableReference>
22+ </BuildActionEntry>
23+ </BuildActionEntries>
24+ </BuildAction>
25+ <TestAction
26+ buildConfiguration = "Debug"
27+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
28+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
29+ shouldUseLaunchSchemeArgsEnv = "YES">
30+ <Testables>
31+ </Testables>
32+ <MacroExpansion>
33+ <BuildableReference
34+ BuildableIdentifier = "primary"
35+ BlueprintIdentifier = "03D84AB61D5B0A1000776402"
36+ BuildableName = "test_Freddy"
37+ BlueprintName = "test_Freddy"
38+ ReferencedContainer = "container:test_Freddy.xcodeproj">
39+ </BuildableReference>
40+ </MacroExpansion>
41+ <AdditionalOptions>
42+ </AdditionalOptions>
43+ </TestAction>
44+ <LaunchAction
45+ buildConfiguration = "Debug"
46+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
47+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
48+ launchStyle = "0"
49+ useCustomWorkingDirectory = "NO"
50+ ignoresPersistentStateOnLaunch = "NO"
51+ debugDocumentVersioning = "YES"
52+ debugServiceExtension = "internal"
53+ allowLocationSimulation = "YES">
54+ <BuildableProductRunnable
55+ runnableDebuggingMode = "0">
56+ <BuildableReference
57+ BuildableIdentifier = "primary"
58+ BlueprintIdentifier = "03D84AB61D5B0A1000776402"
59+ BuildableName = "test_Freddy"
60+ BlueprintName = "test_Freddy"
61+ ReferencedContainer = "container:test_Freddy.xcodeproj">
62+ </BuildableReference>
63+ </BuildableProductRunnable>
64+ <AdditionalOptions>
65+ </AdditionalOptions>
66+ </LaunchAction>
67+ <ProfileAction
68+ buildConfiguration = "Release"
69+ shouldUseLaunchSchemeArgsEnv = "YES"
70+ savedToolIdentifier = ""
71+ useCustomWorkingDirectory = "NO"
72+ debugDocumentVersioning = "YES">
73+ <BuildableProductRunnable
74+ runnableDebuggingMode = "0">
75+ <BuildableReference
76+ BuildableIdentifier = "primary"
77+ BlueprintIdentifier = "03D84AB61D5B0A1000776402"
78+ BuildableName = "test_Freddy"
79+ BlueprintName = "test_Freddy"
80+ ReferencedContainer = "container:test_Freddy.xcodeproj">
81+ </BuildableReference>
82+ </BuildableProductRunnable>
83+ </ProfileAction>
84+ <AnalyzeAction
85+ buildConfiguration = "Debug">
86+ </AnalyzeAction>
87+ <ArchiveAction
88+ buildConfiguration = "Release"
89+ revealArchiveInOrganizer = "YES">
90+ </ArchiveAction>
91+</Scheme>
parsers/test_Freddy_20161018/test_Freddy.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plistnew file+22
@@ -0,0 +1,22 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+<plist version="1.0">
4+<dict>
5+ <key>SchemeUserState</key>
6+ <dict>
7+ <key>test_Freddy.xcscheme</key>
8+ <dict>
9+ <key>orderHint</key>
10+ <integer>0</integer>
11+ </dict>
12+ </dict>
13+ <key>SuppressBuildableAutocreation</key>
14+ <dict>
15+ <key>03D84AB61D5B0A1000776402</key>
16+ <dict>
17+ <key>primary</key>
18+ <true/>
19+ </dict>
20+ </dict>
21+</dict>
22+</plist>
parsers/test_Freddy_20161018/test_Freddy/JSON.swiftnew file+98
@@ -0,0 +1,98 @@
1+//
2+// JSON.swift
3+// Freddy
4+//
5+// Created by Matthew D. Mathias on 3/17/15.
6+// Copyright © 2015 Big Nerd Ranch. Licensed under MIT.
7+//
8+
9+/// An enum to describe the structure of JSON.
10+public enum JSON {
11+ /// A case for denoting an array with an associated value of `[JSON]`
12+ case array([JSON])
13+ /// A case for denoting a dictionary with an associated value of `[Swift.String: JSON]`
14+ case dictionary([String: JSON])
15+ /// A case for denoting a double with an associated value of `Swift.Double`.
16+ case double(Double)
17+ /// A case for denoting an integer with an associated value of `Swift.Int`.
18+ case int(Int)
19+ /// A case for denoting a string with an associated value of `Swift.String`.
20+ case string(String)
21+ /// A case for denoting a boolean with an associated value of `Swift.Bool`.
22+ case bool(Bool)
23+ /// A case for denoting null.
24+ case null
25+}
26+
27+// MARK: - Errors
28+
29+extension JSON {
30+
31+ /// An enum to encapsulate errors that may arise in working with `JSON`.
32+ public enum Error: Swift.Error {
33+ /// The `index` is out of bounds for a JSON array
34+ case indexOutOfBounds(index: Int)
35+
36+ /// The `key` was not found in the JSON dictionary
37+ case keyNotFound(key: String)
38+
39+ /// The JSON is not subscriptable with `type`
40+ case unexpectedSubscript(type: JSONPathType.Type)
41+
42+ /// Unexpected JSON `value` was found that is not convertible `to` type
43+ case valueNotConvertible(value: JSON, to: Any.Type)
44+
45+ /// The JSON is not serializable to a `String`.
46+ case stringSerializationError
47+ }
48+
49+}
50+
51+// MARK: - Test Equality
52+
53+/// Return `true` if `lhs` is equal to `rhs`.
54+public func ==(lhs: JSON, rhs: JSON) -> Bool {
55+ switch (lhs, rhs) {
56+ case (.array(let arrL), .array(let arrR)):
57+ return arrL == arrR
58+ case (.dictionary(let dictL), .dictionary(let dictR)):
59+ return dictL == dictR
60+ case (.string(let strL), .string(let strR)):
61+ return strL == strR
62+ case (.double(let dubL), .double(let dubR)):
63+ return dubL == dubR
64+ case (.double(let dubL), .int(let intR)):
65+ return dubL == Double(intR)
66+ case (.int(let intL), .int(let intR)):
67+ return intL == intR
68+ case (.int(let intL), .double(let dubR)):
69+ return Double(intL) == dubR
70+ case (.bool(let bL), .bool(let bR)):
71+ return bL == bR
72+ case (.null, .null):
73+ return true
74+ default:
75+ return false
76+ }
77+}
78+
79+extension JSON: Equatable {}
80+
81+// MARK: - Printing
82+
83+extension JSON: CustomStringConvertible {
84+
85+ /// A textual representation of `self`.
86+ public var description: Swift.String {
87+ switch self {
88+ case .array(let arr): return String(describing: arr)
89+ case .dictionary(let dict): return String(describing: dict)
90+ case .string(let string): return string
91+ case .double(let double): return String(describing: double)
92+ case .int(let int): return String(describing: int)
93+ case .bool(let bool): return String(describing: bool)
94+ case .null: return "null"
95+ }
96+ }
97+
98+}
parsers/test_Freddy_20161018/test_Freddy/JSONDecodable.swiftnew file+186
@@ -0,0 +1,186 @@
1+//
2+// JSONDecodable.swift
3+// Freddy
4+//
5+// Created by Matthew D. Mathias on 3/24/15.
6+// Copyright © 2015 Big Nerd Ranch. Licensed under MIT.
7+//
8+
9+/// A protocol to provide functionality for creating a model object with a `JSON`
10+/// value.
11+public protocol JSONDecodable {
12+
13+ /// Creates an instance of the model with a `JSON` instance.
14+ /// - parameter json: An instance of a `JSON` value from which to
15+ /// construct an instance of the implementing type.
16+ /// - throws: Any `JSON.Error` for errors derived from inspecting the
17+ /// `JSON` value, or any other error involved in decoding.
18+ init(json: JSON) throws
19+
20+}
21+
22+extension Double: JSONDecodable {
23+
24+ /// An initializer to create an instance of `Double` from a `JSON` value.
25+ /// - parameter json: An instance of `JSON`.
26+ /// - throws: The initializer will throw an instance of `JSON.Error` if
27+ /// an instance of `Double` cannot be created from the `JSON` value that was
28+ /// passed to this initializer.
29+ public init(json: JSON) throws {
30+ if case let .double(double) = json {
31+ self = double
32+ } else if case let .int(int) = json {
33+ self = Double(int)
34+ } else if case let .string(string) = json, let s = Double(string) {
35+ self = s
36+ } else {
37+ throw JSON.Error.valueNotConvertible(value: json, to: Double.self)
38+ }
39+ }
40+
41+}
42+
43+extension Int: JSONDecodable {
44+
45+ /// An initializer to create an instance of `Int` from a `JSON` value.
46+ /// - parameter json: An instance of `JSON`.
47+ /// - throws: The initializer will throw an instance of `JSON.Error` if
48+ /// an instance of `Int` cannot be created from the `JSON` value that was
49+ /// passed to this initializer.
50+ public init(json: JSON) throws {
51+
52+ if case let .double(double) = json, double <= Double(Int.max) {
53+ self = Int(double)
54+ } else if case let .int(int) = json {
55+ self = int
56+ } else if case let .string(string) = json, let int = Int(string) {
57+ self = int
58+ } else if case let .string(string) = json,
59+ let double = Double(string),
60+ let decimalSeparator = string.characters.index(of: "."),
61+ let int = Int(String(string.characters.prefix(upTo: decimalSeparator))),
62+ double == Double(int) {
63+ self = int
64+ } else {
65+ throw JSON.Error.valueNotConvertible(value: json, to: Int.self)
66+ }
67+ }
68+
69+}
70+
71+extension String: JSONDecodable {
72+
73+ /// An initializer to create an instance of `String` from a `JSON` value.
74+ /// - parameter json: An instance of `JSON`.
75+ /// - throws: The initializer will throw an instance of `JSON.Error` if
76+ /// an instance of `String` cannot be created from the `JSON` value that was
77+ /// passed to this initializer.
78+ public init(json: JSON) throws {
79+ switch json {
80+ case let .string(string):
81+ self = string
82+ case let .int(int):
83+ self = String(int)
84+ case let .bool(bool):
85+ self = String(bool)
86+ case let .double(double):
87+ self = String(double)
88+ default:
89+ throw JSON.Error.valueNotConvertible(value: json, to: String.self)
90+ }
91+ }
92+
93+}
94+
95+extension Bool: JSONDecodable {
96+
97+ /// An initializer to create an instance of `Bool` from a `JSON` value.
98+ /// - parameter json: An instance of `JSON`.
99+ /// - throws: The initializer will throw an instance of `JSON.Error` if
100+ /// an instance of `Bool` cannot be created from the `JSON` value that was
101+ /// passed to this initializer.
102+ public init(json: JSON) throws {
103+ guard case let .bool(bool) = json else {
104+ throw JSON.Error.valueNotConvertible(value: json, to: Bool.self)
105+ }
106+ self = bool
107+ }
108+
109+}
110+
111+extension RawRepresentable where RawValue: JSONDecodable {
112+
113+ /// An initializer to create an instance of `RawRepresentable` from a `JSON` value.
114+ /// - parameter json: An instance of `JSON`.
115+ /// - throws: The initializer will throw an instance of `JSON.Error` if
116+ /// an instance of `RawRepresentable` cannot be created from the `JSON` value that was
117+ /// passed to this initializer.
118+ public init(json: JSON) throws {
119+ let raw = try json.decode(type: RawValue.self)
120+ guard let value = Self(rawValue: raw) else {
121+ throw JSON.Error.valueNotConvertible(value: json, to: Self.self)
122+ }
123+ self = value
124+ }
125+}
126+
127+internal extension JSON {
128+
129+ /// Retrieves a `[JSON]` from the JSON.
130+ /// - parameter: A `JSON` to be used to create the returned `Array`.
131+ /// - returns: An `Array` of `JSON` elements
132+ /// - throws: Any of the `JSON.Error` cases thrown by `decode(type:)`.
133+ /// - seealso: `JSON.decode(_:type:)`
134+ static func getArray(from json: JSON) throws -> [JSON] {
135+ // Ideally should be expressed as a conditional protocol implementation on Swift.Array.
136+ guard case let .array(array) = json else {
137+ throw Error.valueNotConvertible(value: json, to: Swift.Array<JSON>)
138+ }
139+ return array
140+ }
141+
142+ /// Retrieves a `[String: JSON]` from the JSON.
143+ /// - parameter: A `JSON` to be used to create the returned `Dictionary`.
144+ /// - returns: An `Dictionary` of `String` mapping to `JSON` elements
145+ /// - throws: Any of the `JSON.Error` cases thrown by `decode(type:)`.
146+ /// - seealso: `JSON.decode(_:type:)`
147+ static func getDictionary(from json: JSON) throws -> [String: JSON] {
148+ // Ideally should be expressed as a conditional protocol implementation on Swift.Dictionary.
149+ guard case let .dictionary(dictionary) = json else {
150+ throw Error.valueNotConvertible(value: json, to: Swift.Dictionary<String, JSON>)
151+ }
152+ return dictionary
153+ }
154+
155+ /// Attempts to decode many values from a descendant JSON array at a path
156+ /// into JSON.
157+ /// - parameter json: A `JSON` to be used to create the returned `Array` of some type conforming to `JSONDecodable`.
158+ /// - returns: An `Array` of `Decoded` elements.
159+ /// - throws: Any of the `JSON.Error` cases thrown by `decode(type:)`, as
160+ /// well as any error that arises from decoding the contained values.
161+ /// - seealso: `JSON.decode(_:type:)`
162+ static func decodedArray<Decoded: JSONDecodable>(from json: JSON) throws -> [Decoded] {
163+ // Ideally should be expressed as a conditional protocol implementation on Swift.Dictionary.
164+ // This implementation also doesn't do the `type = Type.self` trick.
165+ return try getArray(from: json).map(Decoded.init)
166+ }
167+
168+ /// Attempts to decode many values from a descendant JSON object at a path
169+ /// into JSON.
170+ /// - parameter json: A `JSON` to be used to create the returned `Dictionary` of some type conforming to `JSONDecodable`.
171+ /// - returns: A `Dictionary` of string keys and `Decoded` values.
172+ /// - throws: One of the `JSON.Error` cases thrown by `decode(_:type:)` or
173+ /// any error that arises from decoding the contained values.
174+ /// - seealso: `JSON.decode(_:type:)`
175+ static func decodedDictionary<Decoded: JSONDecodable>(from json: JSON) throws -> [Swift.String: Decoded] {
176+ guard case let .dictionary(dictionary) = json else {
177+ throw Error.valueNotConvertible(value: json, to: Swift.Dictionary<String, Decoded>)
178+ }
179+ var decodedDictionary = Swift.Dictionary<String, Decoded>(minimumCapacity: dictionary.count)
180+ for (key, value) in dictionary {
181+ decodedDictionary[key] = try Decoded(json: value)
182+ }
183+ return decodedDictionary
184+ }
185+
186+}
parsers/test_Freddy_20161018/test_Freddy/JSONEncodable.swiftnew file+83
@@ -0,0 +1,83 @@
1+//
2+// JSONEncodable.swift
3+// Freddy
4+//
5+// Created by Matthew Mathias on 1/4/16.
6+// Copyright © 2016 Big Nerd Ranch. All rights reserved.
7+//
8+
9+import Foundation
10+
11+/// A protocol to facilitate encoding and decoding of `JSON`.
12+public protocol JSONEncodable {
13+ /// Converts an instance of a conforming type to `JSON`.
14+ /// - returns: An instance of `JSON`.
15+ /// - Note: If conforming to `JSONEncodable` with a custom type of your own, you should return an instance of
16+ /// `JSON.dictionary`.
17+ func toJSON() -> JSON
18+}
19+
20+extension Array where Element: JSONEncodable {
21+ /// Converts an instance of `Array` whose elements conform to `JSONEncodable` to `JSON`.
22+ /// - returns: An instance of `JSON` where the enum case is `.array`.
23+ public func toJSON() -> JSON {
24+ let arrayOfJSON = self.map { $0.toJSON() }
25+ return .array(arrayOfJSON)
26+ }
27+}
28+
29+extension Dictionary where Value: JSONEncodable {
30+ /// Converts an instance of `Dictionary` whose values conform to `JSONEncodable` to `JSON`. The keys in the resulting
31+ /// `JSON.dictionary` will be of type `String`.
32+ /// - returns: An instance of `JSON` where the enum case is `.dictionary`.
33+ public func toJSON() -> JSON {
34+ var jsonDictionary = [String: JSON]()
35+
36+ for (k, v) in self {
37+ let key = String(describing: k)
38+ jsonDictionary[key] = v.toJSON()
39+ }
40+
41+ return .dictionary(jsonDictionary)
42+ }
43+}
44+
45+extension Int: JSONEncodable {
46+ /// Converts an instance of a conforming type to `JSON`.
47+ /// - returns: An instance of `JSON` where the enum case is `.int`.
48+ public func toJSON() -> JSON {
49+ return .int(self)
50+ }
51+}
52+
53+extension Double: JSONEncodable {
54+ /// Converts an instance of a conforming type to `JSON`.
55+ /// - returns: An instance of `JSON` where the enum case is `.double`.
56+ public func toJSON() -> JSON {
57+ return .double(self)
58+ }
59+}
60+
61+extension String: JSONEncodable {
62+ /// Converts an instance of a conforming type to `JSON`.
63+ /// - returns: An instance of `JSON` where the enum case is `.string`.
64+ public func toJSON() -> JSON {
65+ return .string(self)
66+ }
67+}
68+
69+extension Bool: JSONEncodable {
70+ /// Converts an instance of a conforming type to `JSON`.
71+ /// - returns: An instance of `JSON` where the enum case is `.bool`.
72+ public func toJSON() -> JSON {
73+ return .bool(self)
74+ }
75+}
76+
77+extension RawRepresentable where RawValue: JSONEncodable {
78+ /// Converts an instance of a conforming type to `JSON`.
79+ /// - returns: An instance of `JSON` where the enum case is whatever the underlying `RawValue` converts to.
80+ public func toJSON() -> JSON {
81+ return rawValue.toJSON()
82+ }
83+}
parsers/test_Freddy_20161018/test_Freddy/JSONEncodingDetector.swiftnew file+110
@@ -0,0 +1,110 @@
1+//
2+// JSONEncodingDetector.swift
3+// Freddy
4+//
5+// Created by Robert Edwards on 1/27/16.
6+// Copyright © 2016 Big Nerd Ranch. All rights reserved.
7+//
8+
9+/// Struct for attempting to detect the Unicode encoding used with the data supplied to the JSONParser
10+public struct JSONEncodingDetector {
11+
12+ //// The Unicode encodings looked for during detection
13+ public enum Encoding {
14+ //// UTF-8
15+ case utf8
16+ //// UTF-16 Little Endian
17+ case utf16LE
18+ //// UTF-16 Big Endian
19+ case utf16BE
20+ //// UTF-32 Little Endian
21+ case utf32LE
22+ //// UTF-32 Big Endian
23+ case utf32BE
24+ }
25+
26+ //// The Unicode encodings supported by JSONParser.swift
27+ public static let supportedEncodings: [Encoding] = [.utf8]
28+
29+ typealias ByteStreamPrefixInformation = (encoding: Encoding, byteOrderMarkLength: Int)
30+
31+ //// Attempts to detect the Unicode encoding used for a given set of data.
32+ ////
33+ //// This function initially looks for a Byte Order Mark in the following form:
34+ ////
35+ //// Bytes | Encoding Form
36+ //// --------------|----------------
37+ //// 00 00 FE FF | UTF-32, big-endian
38+ //// FF FE 00 00 | UTF-32, little-endian
39+ //// FE FF | UTF-16, big-endian
40+ //// FF FE | UTF-16, little-endian
41+ //// EF BB BF | UTF-8
42+ ////
43+ //// If a BOM is not found then we detect using the following approach described in
44+ //// the JSON RFC http://www.ietf.org/rfc/rfc4627.txt:
45+ ////
46+ //// Since the first two characters of a JSON text will always be ASCII
47+ //// characters [RFC0020], it is possible to determine whether an octet
48+ //// stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking
49+ //// at the pattern of nulls in the first four octets.
50+ ////
51+ //// 00 00 00 xx UTF-32BE
52+ //// 00 xx 00 xx UTF-16BE
53+ //// xx 00 00 00 UTF-32LE
54+ //// xx 00 xx 00 UTF-16LE
55+ //// xx xx xx xx UTF-8
56+ ////
57+ //// - parameter header: The front Slice of data being read and evaluated.
58+ //// - returns: A tuple containing the detected Unicode encoding and the lenght of the byte order mark.
59+ static func detectEncoding(_ header: RandomAccessSlice<UnsafeBufferPointer<UInt8>>) -> ByteStreamPrefixInformation {
60+
61+ guard let prefix = prefixFromHeader(header) else {
62+ return (.utf8, 0)
63+ }
64+
65+ if let prefixInfo = JSONEncodingDetector.encodingFromBOM(prefix) {
66+ return prefixInfo
67+ } else {
68+ switch prefix {
69+ case(0, 0, 0?, _):
70+ return (.utf32BE, 0)
71+ case(_, 0, 0?, 0?):
72+ return (.utf32LE, 0)
73+ case (0, _, 0?, _), (0, _, _, _):
74+ return (.utf16BE, 0)
75+ case (_, 0, _, 0?), (_, 0, _, _):
76+ return (.utf16LE, 0)
77+ default:
78+ return (.utf8, 0)
79+ }
80+ }
81+ }
82+
83+ private typealias EncodingBytePrefix = (UInt8, UInt8, UInt8?, UInt8?)
84+
85+ private static func prefixFromHeader(_ header: RandomAccessSlice<UnsafeBufferPointer<UInt8>>) -> EncodingBytePrefix? {
86+ if header.count >= 4 {
87+ return(header[0], header[1], header[2], header[3])
88+ } else if header.count >= 2 {
89+ return (header[0], header[1], nil, nil)
90+ }
91+ return nil
92+ }
93+
94+ private static func encodingFromBOM(_ prefix: EncodingBytePrefix) -> ByteStreamPrefixInformation? {
95+ switch prefix {
96+ case(0xFE, 0xFF, _, _):
97+ return (.utf16BE, 2)
98+ case(0x00, 0x00, 0xFE?, 0xFF?):
99+ return (.utf32BE, 4)
100+ case(0xEF, 0xBB, 0xBF?, _):
101+ return (.utf8, 3)
102+ case(0xFF, 0xFE, 0?, 0?):
103+ return (.utf32LE, 4)
104+ case(0xFF, 0xFE, _, _):
105+ return (.utf16LE, 2)
106+ default:
107+ return nil
108+ }
109+ }
110+}
parsers/test_Freddy_20161018/test_Freddy/JSONLiteralConvertible.swiftnew file+134
@@ -0,0 +1,134 @@
1+//
2+// JSONLiteralConvertible.swift
3+// Freddy
4+//
5+// Created by Zachary Waldowski on 5/11/15.
6+// Copyright © 2015 Big Nerd Ranch. Licensed under MIT.
7+//
8+
9+// MARK: - ArrayLiteralConvertible
10+
11+extension JSON: ExpressibleByArrayLiteral {
12+
13+ /// Create an instance by copying each element of the `collection` into a
14+ /// new `Array`.
15+ public init<Collection: Swift.Collection>(_ collection: Collection) where Collection.Iterator.Element == JSON {
16+ self = .array(Swift.Array(collection))
17+ }
18+
19+ /// Create an instance initialized with `elements`.
20+ public init(arrayLiteral elements: JSON...) {
21+ self.init(elements)
22+ }
23+
24+}
25+
26+// MARK: - DictionaryLiteralConvertible
27+
28+extension JSON: ExpressibleByDictionaryLiteral {
29+
30+ /// Create an instance by copying each key/value pair of the `pairs` into
31+ /// a new `Dictionary`.
32+ public init<Dictionary: Sequence>(_ pairs: Dictionary) where Dictionary.Iterator.Element == (Swift.String, JSON) {
33+ var dictionary = Swift.Dictionary<Swift.String, JSON>(minimumCapacity: pairs.underestimatedCount)
34+ for (key, value) in pairs {
35+ dictionary[key] = value
36+ }
37+ self.init(dictionary)
38+ }
39+
40+ /// Create an instance initialized with `pairs`.
41+ public init(dictionaryLiteral pairs: (Swift.String, JSON)...) {
42+ self.init(pairs)
43+ }
44+
45+ /// Create an instance initialized to `dictionary`.
46+ public init(_ dictionary: Swift.Dictionary<Swift.String, JSON>) {
47+ self = .dictionary(dictionary)
48+ }
49+}
50+
51+// MARK: - FloatLiteralConvertible
52+
53+extension JSON: ExpressibleByFloatLiteral {
54+
55+ /// Create an instance initialized to `Double` `value`.
56+ public init(_ value: Swift.Double) {
57+ self = .double(value)
58+ }
59+
60+ /// Create a literal instance initialized to `value`.
61+ public init(floatLiteral value: Swift.Double) {
62+ self.init(value)
63+ }
64+
65+}
66+
67+// MARK: - IntegerLiteralConvertible
68+
69+extension JSON: ExpressibleByIntegerLiteral {
70+
71+ /// Create an instance initialized to `Int` by `value`.
72+ public init(_ value: Swift.Int) {
73+ self = .int(value)
74+ }
75+
76+ /// Create a literal instance initialized to `value`.
77+ public init(integerLiteral value: Swift.Int) {
78+ self.init(value)
79+ }
80+
81+}
82+
83+// MARK: - StringLiteralConvertible
84+
85+extension JSON: ExpressibleByStringLiteral {
86+
87+ /// Create an instance initialized to `String` by `text`.
88+ public init(_ text: Swift.String) {
89+ self = .string(text)
90+ }
91+
92+ /// Create a literal instance initialized to `value`.
93+ public init(stringLiteral value: StringLiteralType) {
94+ self.init(value)
95+ }
96+
97+ /// Create a literal instance initialized to `value`.
98+ public init(extendedGraphemeClusterLiteral value: StringLiteralType) {
99+ self.init(value)
100+ }
101+
102+ /// Create a literal instance initialized to `value`.
103+ public init(unicodeScalarLiteral value: StringLiteralType) {
104+ self.init(value)
105+ }
106+
107+}
108+
109+// MARK: - BooleanLiteralConvertible
110+
111+extension JSON: ExpressibleByBooleanLiteral {
112+
113+ /// Create an instance initialized to `Bool` by `value`.
114+ public init(_ value: Swift.Bool) {
115+ self = .bool(value)
116+ }
117+
118+ /// Create a literal instance initialized to `value`.
119+ public init(booleanLiteral value: Swift.Bool) {
120+ self.init(value)
121+ }
122+
123+}
124+
125+// MARK: - NilLiteralConvertible
126+
127+extension JSON: ExpressibleByNilLiteral {
128+
129+ /// Create an instance initialized with `nil`.
130+ public init(nilLiteral: ()) {
131+ self = .null
132+ }
133+
134+}
parsers/test_Freddy_20161018/test_Freddy/JSONParser.swiftnew file+918
@@ -0,0 +1,918 @@
1+//
2+// JSONParser.swift
3+// Freddy
4+//
5+// Created by John Gallagher on 4/18/15.
6+// Copyright © 2015 Big Nerd Ranch. Licensed under MIT.
7+//
8+
9+import Foundation
10+
11+private struct Literal {
12+ static let BACKSLASH = UInt8(ascii: "\\")
13+ static let BACKSPACE = UInt8(ascii: "\u{0008}")
14+ static let COLON = UInt8(ascii: ":")
15+ static let COMMA = UInt8(ascii: ",")
16+ static let DOUBLE_QUOTE = UInt8(ascii: "\"")
17+ static let FORMFEED = UInt8(ascii: "\u{000c}")
18+ static let LEFT_BRACE = UInt8(ascii: "{")
19+ static let LEFT_BRACKET = UInt8(ascii: "[")
20+ static let MINUS = UInt8(ascii: "-")
21+ static let NEWLINE = UInt8(ascii: "\n")
22+ static let PERIOD = UInt8(ascii: ".")
23+ static let PLUS = UInt8(ascii: "+")
24+ static let RETURN = UInt8(ascii: "\r")
25+ static let RIGHT_BRACE = UInt8(ascii: "}")
26+ static let RIGHT_BRACKET = UInt8(ascii: "]")
27+ static let SLASH = UInt8(ascii: "/")
28+ static let SPACE = UInt8(ascii: " ")
29+ static let TAB = UInt8(ascii: "\t")
30+
31+ static let a = UInt8(ascii: "a")
32+ static let b = UInt8(ascii: "b")
33+ static let c = UInt8(ascii: "c")
34+ static let d = UInt8(ascii: "d")
35+ static let e = UInt8(ascii: "e")
36+ static let f = UInt8(ascii: "f")
37+ static let l = UInt8(ascii: "l")
38+ static let n = UInt8(ascii: "n")
39+ static let r = UInt8(ascii: "r")
40+ static let s = UInt8(ascii: "s")
41+ static let t = UInt8(ascii: "t")
42+ static let u = UInt8(ascii: "u")
43+
44+ static let A = UInt8(ascii: "A")
45+ static let B = UInt8(ascii: "B")
46+ static let C = UInt8(ascii: "C")
47+ static let D = UInt8(ascii: "D")
48+ static let E = UInt8(ascii: "E")
49+ static let F = UInt8(ascii: "F")
50+
51+ static let zero = UInt8(ascii: "0")
52+ static let one = UInt8(ascii: "1")
53+ static let two = UInt8(ascii: "2")
54+ static let three = UInt8(ascii: "3")
55+ static let four = UInt8(ascii: "4")
56+ static let five = UInt8(ascii: "5")
57+ static let six = UInt8(ascii: "6")
58+ static let seven = UInt8(ascii: "7")
59+ static let eight = UInt8(ascii: "8")
60+ static let nine = UInt8(ascii: "9")
61+}
62+
63+private let ParserMaximumDepth = 512
64+
65+
66+/// A pure Swift JSON parser. This parser is much faster than the
67+/// `NSJSONSerialization`-based parser (due to the overhead of having to
68+/// dynamically cast the Objective-C objects to determine their type); however,
69+/// it is much newer and has restrictions that the `NSJSONSerialization` parser
70+/// does not. Two restrictions in particular are that it requires UTF-8 data as
71+/// input and it does not allow trailing commas in arrays or dictionaries.
72+public struct JSONParser {
73+
74+ fileprivate enum Sign: Int {
75+ case positive = 1
76+ case negative = -1
77+ }
78+
79+ private let input: UnsafeBufferPointer<UInt8>
80+ private var loc = 0
81+ private var depth = 0
82+
83+ fileprivate init(input: UnsafeBufferPointer<UInt8>) {
84+ self.input = input
85+ }
86+
87+ /// Decode the root element of the `JSON` stream. This may be any fragment
88+ /// or a structural element, per RFC 7159.
89+ ///
90+ /// The beginning bytes are used to determine the stream's encoding.
91+ /// `JSONParser` currently only supports UTF-8 encoding, with or without
92+ /// a byte-order mark.
93+ ///
94+ /// - throws: `JSONParser.Error` for any decoding failures, including a
95+ /// source location if needed.
96+ public mutating func parse() throws -> JSON {
97+ try guardAgainstUnsupportedEncodings()
98+ let value = try parseValue()
99+ skipWhitespace()
100+ guard loc == input.count else {
101+ throw Error.endOfStreamGarbage(offset: loc)
102+ }
103+ return value
104+ }
105+
106+ private mutating func parseValue() throws -> JSON {
107+ guard depth <= ParserMaximumDepth else {
108+ throw Error.exceededNestingLimit(offset: loc)
109+ }
110+
111+ guard input.count > 0 else {
112+ throw Error.endOfStreamUnexpected
113+ }
114+
115+ advancing: while loc < input.count {
116+ do {
117+ switch input[loc] {
118+ case Literal.LEFT_BRACKET:
119+ depth += 1
120+ defer { depth -= 1 }
121+ return try decodeArray()
122+
123+ case Literal.LEFT_BRACE:
124+ depth += 1
125+ defer { depth -= 1 }
126+ return try decodeObject()
127+
128+ case Literal.DOUBLE_QUOTE:
129+ return try decodeString()
130+
131+ case Literal.f:
132+ return try decodeFalse()
133+
134+ case Literal.n:
135+ return try decodeNull()
136+
137+ case Literal.t:
138+ return try decodeTrue()
139+
140+ case Literal.MINUS:
141+ return try decodeIntegralValue(NumberParser(loc: loc, input: input, state: .leadingMinus))
142+
143+ case Literal.zero:
144+ return try decodeIntegralValue(NumberParser(loc: loc, input: input, state: .leadingZero))
145+
146+ case Literal.one...Literal.nine:
147+ return try decodeIntegralValue(NumberParser(loc: loc, input: input, state: .preDecimalDigits))
148+
149+ case Literal.SPACE, Literal.TAB, Literal.RETURN, Literal.NEWLINE:
150+ loc = (loc + 1)
151+
152+ default:
153+ break advancing
154+ }
155+ } catch let InternalError.numberOverflow(offset: start) {
156+ return try decodeNumberAsString(from: start)
157+ }
158+ }
159+ if loc < input.count {
160+ throw Error.valueInvalid(offset: loc, character: UnicodeScalar(input[loc]))
161+ } else {
162+ throw Error.endOfStreamUnexpected
163+ }
164+ }
165+
166+ private mutating func skipWhitespace() {
167+ while loc < input.count {
168+ switch input[loc] {
169+ case Literal.SPACE, Literal.TAB, Literal.RETURN, Literal.NEWLINE:
170+ loc = (loc + 1)
171+ default:
172+ return
173+ }
174+ }
175+ }
176+
177+ private mutating func guardAgainstUnsupportedEncodings() throws {
178+ let header = input.prefix(4)
179+ let encodingPrefixInformation = JSONEncodingDetector.detectEncoding(header)
180+ guard JSONEncodingDetector.supportedEncodings.contains(encodingPrefixInformation.encoding) else {
181+ throw Error.invalidUnicodeStreamEncoding(detectedEncoding: encodingPrefixInformation.encoding)
182+ }
183+ loc = loc.advanced(by: encodingPrefixInformation.byteOrderMarkLength)
184+ }
185+
186+ private mutating func decodeNull() throws -> JSON {
187+ guard input.index(loc, offsetBy: 3, limitedBy: input.count) != input.count else {
188+ throw Error.literalNilMisspelled(offset: loc)
189+ }
190+
191+ if input[loc+1] != Literal.u
192+ || input[loc+2] != Literal.l
193+ || input[loc+3] != Literal.l {
194+ throw Error.literalNilMisspelled(offset: loc)
195+ }
196+
197+ loc += 4
198+ return .null
199+ }
200+
201+ private mutating func decodeTrue() throws -> JSON {
202+ guard input.index(loc, offsetBy: 3, limitedBy: input.count) != input.count else {
203+ throw Error.literalNilMisspelled(offset: loc)
204+ }
205+
206+ if input[loc+1] != Literal.r
207+ || input[loc+2] != Literal.u
208+ || input[loc+3] != Literal.e {
209+ throw Error.literalTrueMisspelled(offset: loc)
210+ }
211+
212+ loc += 4
213+ return .bool(true)
214+ }
215+
216+ private mutating func decodeFalse() throws -> JSON {
217+ guard input.index(loc, offsetBy: 4, limitedBy: input.count) != input.count else {
218+ throw Error.literalNilMisspelled(offset: loc)
219+ }
220+
221+ if input[loc+1] != Literal.a
222+ || input[loc+2] != Literal.l
223+ || input[loc+3] != Literal.s
224+ || input[loc+4] != Literal.e {
225+ throw Error.literalFalseMisspelled(offset: loc)
226+ }
227+
228+ loc += 5
229+ return .bool(false)
230+ }
231+
232+ private var stringDecodingBuffer = [UInt8]()
233+ private mutating func decodeString() throws -> JSON {
234+ loc = (loc + 1)
235+ stringDecodingBuffer.removeAll(keepingCapacity: true)
236+ while loc < input.count {
237+ switch input[loc] {
238+ case Literal.BACKSLASH:
239+ loc = (loc + 1)
240+ switch input[loc] {
241+ case Literal.DOUBLE_QUOTE: stringDecodingBuffer.append(Literal.DOUBLE_QUOTE)
242+ case Literal.BACKSLASH: stringDecodingBuffer.append(Literal.BACKSLASH)
243+ case Literal.SLASH: stringDecodingBuffer.append(Literal.SLASH)
244+ case Literal.b: stringDecodingBuffer.append(Literal.BACKSPACE)
245+ case Literal.f: stringDecodingBuffer.append(Literal.FORMFEED)
246+ case Literal.r: stringDecodingBuffer.append(Literal.RETURN)
247+ case Literal.t: stringDecodingBuffer.append(Literal.TAB)
248+ case Literal.n: stringDecodingBuffer.append(Literal.NEWLINE)
249+ case Literal.u:
250+ loc = (loc + 1)
251+ try readUnicodeEscape(start: loc - 2)
252+
253+ // readUnicodeEscape() advances loc on its own, so we'll `continue` now
254+ // to skip the typical "advance past this character" for all the other escapes
255+ continue
256+
257+ default:
258+ throw Error.controlCharacterUnrecognized(offset: loc)
259+ }
260+ loc = (loc + 1)
261+
262+ case Literal.DOUBLE_QUOTE:
263+ loc = (loc + 1)
264+ stringDecodingBuffer.append(0)
265+
266+ let string = stringDecodingBuffer.withUnsafeBufferPointer {
267+ String(cString: UnsafePointer($0.baseAddress!))
268+ }
269+
270+ return .string(string)
271+
272+ case let other:
273+ stringDecodingBuffer.append(other)
274+ loc = (loc + 1)
275+ }
276+ }
277+
278+ throw Error.endOfStreamUnexpected
279+ }
280+
281+ private mutating func readCodeUnit() -> UInt16? {
282+ guard loc + 4 <= input.count else {
283+ return nil
284+ }
285+ var codeUnit: UInt16 = 0
286+ for c in input[loc..<loc+4] {
287+ let nibble: UInt16
288+
289+ switch c {
290+ case Literal.zero...Literal.nine:
291+ nibble = UInt16(c - Literal.zero)
292+
293+ case Literal.a...Literal.f:
294+ nibble = 10 + UInt16(c - Literal.a)
295+
296+ case Literal.A...Literal.F:
297+ nibble = 10 + UInt16(c - Literal.A)
298+
299+ default:
300+ return nil
301+ }
302+ codeUnit = (codeUnit << 4) | nibble
303+ }
304+ loc += 4
305+ return codeUnit
306+ }
307+
308+ private mutating func readUnicodeEscape(start: Int) throws {
309+ guard let codeUnit = readCodeUnit() else {
310+ throw Error.unicodeEscapeInvalid(offset: start)
311+ }
312+
313+ let codeUnits: [UInt16]
314+
315+ if UTF16.isLeadSurrogate(codeUnit) {
316+ // First half of a UTF16 surrogate pair - we must parse another code unit and combine them
317+
318+ // First confirm and skip over that we have another "\u"
319+ guard loc + 6 <= input.count && input[loc] == Literal.BACKSLASH && input[loc+1] == Literal.u else {
320+ throw Error.unicodeEscapeInvalid(offset: start)
321+ }
322+ loc += 2
323+
324+ // Ensure the second code unit is valid for the surrogate pair
325+ guard let secondCodeUnit = readCodeUnit(), UTF16.isTrailSurrogate(secondCodeUnit) else {
326+ throw Error.unicodeEscapeInvalid(offset: start)
327+ }
328+
329+ codeUnits = [codeUnit, secondCodeUnit]
330+ } else {
331+ codeUnits = [codeUnit]
332+ }
333+
334+ let transcodeHadError = transcode(codeUnits.makeIterator(), from: UTF16.self, to: UTF8.self, stoppingOnError: true) { (outputEncodingCodeUnit) in
335+ self.stringDecodingBuffer.append(outputEncodingCodeUnit)
336+ }
337+
338+ if transcodeHadError {
339+ throw Error.unicodeEscapeInvalid(offset: start)
340+ }
341+ }
342+
343+ private mutating func decodeArray() throws -> JSON {
344+ let start = loc
345+ loc = (loc + 1)
346+ var items = [JSON]()
347+
348+ while loc < input.count {
349+ skipWhitespace()
350+
351+ if loc < input.count && input[loc] == Literal.RIGHT_BRACKET {
352+ loc = (loc + 1)
353+ return .array(items)
354+ }
355+
356+ if !items.isEmpty {
357+ guard loc < input.count && input[loc] == Literal.COMMA else {
358+ throw Error.collectionMissingSeparator(offset: start)
359+ }
360+ loc = (loc + 1)
361+ }
362+
363+ items.append(try parseValue())
364+ }
365+
366+ throw Error.endOfStreamUnexpected
367+ }
368+
369+ // Decoding objects can be recursive, so we have to keep more than one
370+ // buffer around for building up key/value pairs (to reduce allocations
371+ // when parsing large JSON documents).
372+ //
373+ // Rough estimate of the difference between this and using a fresh
374+ // [(String,JSON)] for the `pairs` variable in decodeObject() below is
375+ // about 12% on an iPhone 5.
376+ private struct DecodeObjectBuffers {
377+ var buffers = [[(String,JSON)]]()
378+
379+ mutating func getBuffer() -> [(String,JSON)] {
380+ if !buffers.isEmpty {
381+ var buffer = buffers.removeLast()
382+ buffer.removeAll(keepingCapacity: true)
383+ return buffer
384+ }
385+ return [(String,JSON)]()
386+ }
387+
388+ mutating func putBuffer(_ buffer: [(String,JSON)]) {
389+ buffers.append(buffer)
390+ }
391+ }
392+
393+ private var decodeObjectBuffers = DecodeObjectBuffers()
394+
395+ private mutating func decodeObject() throws -> JSON {
396+ let start = loc
397+ loc = (loc + 1)
398+ var pairs = decodeObjectBuffers.getBuffer()
399+
400+ while loc < input.count {
401+ skipWhitespace()
402+
403+ if loc < input.count && input[loc] == Literal.RIGHT_BRACE {
404+ loc = (loc + 1)
405+ var obj = [String:JSON](minimumCapacity: pairs.count)
406+ for (k, v) in pairs {
407+ obj[k] = v
408+ }
409+ decodeObjectBuffers.putBuffer(pairs)
410+ return .dictionary(obj)
411+ }
412+
413+ if !pairs.isEmpty {
414+ guard loc < input.count && input[loc] == Literal.COMMA else {
415+ throw Error.collectionMissingSeparator(offset: start)
416+ }
417+ loc = (loc + 1)
418+
419+ skipWhitespace()
420+ }
421+
422+ guard loc < input.count && input[loc] == Literal.DOUBLE_QUOTE else {
423+ throw Error.dictionaryMissingKey(offset: start)
424+ }
425+
426+ let key = try decodeString().getString()
427+ skipWhitespace()
428+
429+ guard loc < input.count && input[loc] == Literal.COLON else {
430+ throw Error.collectionMissingSeparator(offset: start)
431+ }
432+ loc = (loc + 1)
433+
434+ pairs.append((key, try parseValue()))
435+ }
436+
437+ throw Error.endOfStreamUnexpected
438+ }
439+
440+ private mutating func decodeIntegralValue(_ parser: NumberParser) throws -> JSON {
441+ var sign = Sign.positive
442+ var parser = parser
443+ var value = 0
444+
445+ // This would be more natural as `while true { ... }` with a meaningful .Done case,
446+ // but that causes compile time explosion in Swift 2.2. :-|
447+ while parser.state != .done {
448+ switch parser.state {
449+ case .leadingMinus:
450+ sign = .negative
451+ try parser.parseNegative()
452+
453+ case .leadingZero:
454+ parser.parseLeadingZero()
455+
456+ case .preDecimalDigits:
457+ try parser.parsePreDecimalDigits { c in
458+ guard case let (exponent, false) = Int.multiplyWithOverflow(10, value) else {
459+ throw InternalError.numberOverflow(offset: parser.start)
460+ }
461+
462+ guard case let (newValue, false) = Int.addWithOverflow(exponent, Int(c - Literal.zero)) else {
463+ throw InternalError.numberOverflow(offset: parser.start)
464+ }
465+
466+ value = newValue
467+ }
468+
469+ case .decimal, .exponent:
470+ return try detectingFloatingPointErrors(start: parser.start) {
471+ try decodeFloatingPointValue(parser, sign: sign, value: Double(value))
472+ }
473+
474+ case .postDecimalDigits, .exponentSign, .exponentDigits:
475+ assertionFailure("Invalid internal state while parsing number")
476+
477+ case .done:
478+ fatalError("impossible condition")
479+ }
480+ }
481+
482+ guard case let (signedValue, false) = Int.multiplyWithOverflow(sign.rawValue, value) else {
483+ throw InternalError.numberOverflow(offset: parser.start)
484+ }
485+
486+ loc = parser.loc
487+ return .int(signedValue)
488+ }
489+
490+ private mutating func decodeFloatingPointValue(_ parser: NumberParser, sign: Sign, value: Double) throws -> JSON {
491+ var parser = parser
492+ var value = value
493+ var exponentSign = Sign.positive
494+ var exponent = Double(0)
495+ var position = 0.1
496+
497+ // This would be more natural as `while true { ... }` with a meaningful .Done case,
498+ // but that causes compile time explosion in Swift 2.2. :-|
499+ while parser.state != .done {
500+ switch parser.state {
501+ case .leadingMinus, .leadingZero, .preDecimalDigits:
502+ assertionFailure("Invalid internal state while parsing number")
503+
504+ case .decimal:
505+ try parser.parseDecimal()
506+
507+ case .postDecimalDigits:
508+ parser.parsePostDecimalDigits { c in
509+ value += position * Double(c - Literal.zero)
510+ position /= 10
511+ }
512+
513+ case .exponent:
514+ exponentSign = try parser.parseExponent()
515+
516+ case .exponentSign:
517+ try parser.parseExponentSign()
518+
519+ case .exponentDigits:
520+ parser.parseExponentDigits { c in
521+ exponent = exponent * 10 + Double(c - Literal.zero)
522+ }
523+
524+ case .done:
525+ fatalError("impossible condition")
526+ }
527+ }
528+
529+ loc = parser.loc
530+ return .double(Double(sign.rawValue) * value * pow(10, Double(exponentSign.rawValue) * exponent))
531+ }
532+
533+
534+ private mutating func decodeNumberAsString(from position: Int) throws -> JSON {
535+ var parser: NumberParser = {
536+ let state: NumberParser.State
537+ switch input[position] {
538+ case Literal.MINUS: state = .leadingMinus
539+ case Literal.zero: state = .leadingZero
540+ case Literal.one...Literal.nine: state = .preDecimalDigits
541+ default:
542+ fatalError("Internal error: decodeNumber called on not-a-number")
543+ }
544+ return NumberParser(loc: position, input: input, state: state)
545+ }()
546+
547+ stringDecodingBuffer.removeAll(keepingCapacity: true)
548+
549+ while true {
550+ switch parser.state {
551+ case .leadingMinus:
552+ try parser.parseNegative()
553+ stringDecodingBuffer.append(Literal.MINUS)
554+
555+ case .leadingZero:
556+ parser.parseLeadingZero()
557+ stringDecodingBuffer.append(Literal.zero)
558+
559+ case .preDecimalDigits:
560+ parser.parsePreDecimalDigits { stringDecodingBuffer.append($0) }
561+
562+ case .decimal:
563+ try parser.parseDecimal()
564+ stringDecodingBuffer.append(Literal.PERIOD)
565+
566+ case .postDecimalDigits:
567+ parser.parsePostDecimalDigits { stringDecodingBuffer.append($0) }
568+
569+ case .exponent:
570+ stringDecodingBuffer.append(input[parser.loc])
571+ _ = try parser.parseExponent()
572+
573+ case .exponentSign:
574+ stringDecodingBuffer.append(input[parser.loc])
575+ try parser.parseExponentSign()
576+
577+ case .exponentDigits:
578+ parser.parseExponentDigits { stringDecodingBuffer.append($0) }
579+
580+ case .done:
581+ stringDecodingBuffer.append(0)
582+ let string = stringDecodingBuffer.withUnsafeBufferPointer {
583+ String(cString: UnsafePointer($0.baseAddress!))
584+ }
585+
586+ loc = parser.loc
587+ return .string(string)
588+ }
589+ }
590+ }
591+
592+ private func detectingFloatingPointErrors<T>(start loc: Int, _ f: () throws -> T) throws -> T {
593+ let flags = FE_UNDERFLOW | FE_OVERFLOW
594+ feclearexcept(flags)
595+ let value = try f()
596+ guard fetestexcept(flags) == 0 else {
597+ throw InternalError.numberOverflow(offset: loc)
598+ }
599+ return value
600+ }
601+}
602+
603+private struct NumberParser {
604+ enum State {
605+ case leadingMinus
606+ case leadingZero
607+ case preDecimalDigits
608+ case decimal
609+ case postDecimalDigits
610+ case exponent
611+ case exponentSign
612+ case exponentDigits
613+ case done
614+ }
615+
616+ let start: Int
617+ var loc = 0
618+ var state: State
619+ let input: UnsafeBufferPointer<UInt8>
620+
621+ init(loc: Int, input: UnsafeBufferPointer<UInt8>, state: State) {
622+ assert(loc < input.count, "Invalid input to NumberParser")
623+ self.start = loc
624+ self.loc = loc
625+ self.input = input
626+ self.state = state
627+ }
628+
629+ mutating func parseNegative() throws {
630+ assert(state == .leadingMinus, "Unexpected state entering parseNegative")
631+
632+ loc = (loc + 1)
633+ guard loc < input.count else {
634+ throw JSONParser.Error.endOfStreamUnexpected
635+ }
636+
637+ switch input[loc] {
638+ case Literal.zero:
639+ state = .leadingZero
640+
641+ case Literal.one...Literal.nine:
642+ state = .preDecimalDigits
643+
644+ default:
645+ throw JSONParser.Error.numberSymbolMissingDigits(offset: start)
646+ }
647+ }
648+
649+ mutating func parseLeadingZero() {
650+ assert(state == .leadingZero, "Unexpected state entering parseLeadingZero")
651+
652+ loc = (loc + 1)
653+ guard loc < input.count else {
654+ state = .done
655+ return
656+ }
657+
658+ switch input[loc] {
659+ case Literal.PERIOD:
660+ state = .decimal
661+
662+ case Literal.e, Literal.E:
663+ state = .exponent
664+
665+ default:
666+ state = .done
667+ }
668+ }
669+
670+ mutating func parsePreDecimalDigits(f: (UInt8) throws -> Void) rethrows {
671+ assert(state == .preDecimalDigits, "Unexpected state entering parsePreDecimalDigits")
672+ advancing: while loc < input.count {
673+ let c = input[loc]
674+ switch c {
675+ case Literal.zero...Literal.nine:
676+ try f(c)
677+ loc = (loc + 1)
678+
679+ case Literal.PERIOD:
680+ state = .decimal
681+ return
682+
683+ case Literal.e, Literal.E:
684+ state = .exponent
685+ return
686+
687+ default:
688+ break advancing
689+ }
690+ }
691+
692+ state = .done
693+ }
694+
695+ mutating func parseDecimal() throws {
696+ assert(state == .decimal, "Unexpected state entering parseDecimal")
697+ loc = (loc + 1)
698+ guard loc < input.count else {
699+ throw JSONParser.Error.endOfStreamUnexpected
700+ }
701+
702+ switch input[loc] {
703+ case Literal.zero...Literal.nine:
704+ state = .postDecimalDigits
705+
706+ default:
707+ throw JSONParser.Error.numberMissingFractionalDigits(offset: start)
708+ }
709+ }
710+
711+ mutating func parsePostDecimalDigits(f: (UInt8) throws -> Void) rethrows {
712+ assert(state == .postDecimalDigits, "Unexpected state entering parsePostDecimalDigits")
713+
714+ advancing: while loc < input.count {
715+ let c = input[loc]
716+ switch c {
717+ case Literal.zero...Literal.nine:
718+ try f(c)
719+ loc = (loc + 1)
720+
721+ case Literal.e, Literal.E:
722+ state = .exponent
723+ return
724+
725+ default:
726+ break advancing
727+ }
728+ }
729+
730+ state = .done
731+ }
732+
733+ mutating func parseExponent() throws -> JSONParser.Sign {
734+ assert(state == .exponent, "Unexpected state entering parseExponent")
735+
736+ loc = (loc + 1)
737+ guard loc < input.count else {
738+ throw JSONParser.Error.endOfStreamUnexpected
739+ }
740+
741+ switch input[loc] {
742+ case Literal.zero...Literal.nine:
743+ state = .exponentDigits
744+
745+ case Literal.PLUS:
746+ state = .exponentSign
747+
748+ case Literal.MINUS:
749+ state = .exponentSign
750+ return .negative
751+
752+ default:
753+ throw JSONParser.Error.numberSymbolMissingDigits(offset: start)
754+ }
755+
756+ return .positive
757+ }
758+
759+ mutating func parseExponentSign() throws {
760+ assert(state == .exponentSign, "Unexpected state entering parseExponentSign")
761+ loc = (loc + 1)
762+ guard loc < input.count else {
763+ throw JSONParser.Error.endOfStreamUnexpected
764+ }
765+
766+ switch input[loc] {
767+ case Literal.zero...Literal.nine:
768+ state = .exponentDigits
769+
770+ default:
771+ throw JSONParser.Error.numberSymbolMissingDigits(offset: start)
772+ }
773+ }
774+
775+ mutating func parseExponentDigits(f: (UInt8) throws -> Void) rethrows {
776+ assert(state == .exponentDigits, "Unexpected state entering parseExponentDigits")
777+ advancing: while loc < input.count {
778+ let c = input[loc]
779+ switch c {
780+ case Literal.zero...Literal.nine:
781+ try f(c)
782+ loc = (loc + 1)
783+
784+ default:
785+ break advancing
786+ }
787+ }
788+
789+ state = .done
790+ }
791+}
792+
793+public extension JSONParser {
794+
795+ /// Creates a `JSONParser` ready to parse UTF-8 encoded `Data`.
796+ ///
797+ /// If the data is mutable, it is copied before parsing. The data's lifetime
798+ /// is extended for the duration of parsing.
799+ @available(*, unavailable, message: "Replaced with parse(utf8:)")
800+ init(utf8Data inData: Data) {
801+ fatalError("unavailable code cannot be executed")
802+ }
803+
804+ /// Creates a `JSONParser` from the code units represented by the `string`.
805+ ///
806+ /// The synthesized string is lifetime-extended for the duration of parsing.
807+ @available(*, unavailable, message: "Replaced with parse(utf8:)")
808+ init(string: String) {
809+ fatalError("unavailable code cannot be executed")
810+ }
811+
812+ /// Creates an instance of `JSON` from UTF-8 encoded `data`.
813+ static func parse(utf8 data: Data) throws -> JSON {
814+ return try data.withUnsafeBytes { (ptr: UnsafePointer<UInt8>) -> JSON in
815+ let buffer = UnsafeBufferPointer(start: ptr, count: data.count)
816+ var parser = JSONParser(input: buffer)
817+ return try parser.parse()
818+ }
819+ }
820+
821+ /// Creates an instance of `JSON` from `string`.
822+ static func parse(_ string: String) throws -> JSON {
823+ return try string.utf8CString.withUnsafeBufferPointer { (nulTerminatedBuffer) throws -> JSON in
824+ return try nulTerminatedBuffer.baseAddress!.withMemoryRebound(to: UInt8.self, capacity: nulTerminatedBuffer.count) { (utf8Base) throws -> JSON in
825+ // don't want to include the nul termination in the buffer - trim it off
826+ let buffer = UnsafeBufferPointer(start: utf8Base, count: nulTerminatedBuffer.count - 1)
827+ var parser = JSONParser(input: buffer)
828+ return try parser.parse()
829+ }
830+ }
831+ }
832+
833+}
834+
835+extension JSONParser: JSONParserType {
836+
837+ /// Creates an instance of `JSON` from UTF-8 encoded `Data`.
838+ /// - parameter data: An instance of `Data` to parse `JSON` from.
839+ /// - throws: Any `JSONParser.Error` that arises during decoding.
840+ /// - seealso: JSONParser.parse()
841+ public static func createJSON(from data: Data) throws -> JSON {
842+ return try parse(utf8: data)
843+ }
844+
845+}
846+
847+// MARK: - Errors
848+
849+extension JSONParser {
850+
851+ /// Enumeration describing possible errors that occur while parsing a JSON
852+ /// document. Most errors include an associated `offset`, representing the
853+ /// offset into the UTF-8 characters making up the document where the error
854+ /// occurred.
855+ public enum Error: Swift.Error {
856+ /// The parser ran out of data prematurely. This usually means a value
857+ /// was not escaped, such as a string literal not ending with a double
858+ /// quote.
859+ case endOfStreamUnexpected
860+
861+ /// Unexpected non-whitespace data was left around `offset` after
862+ /// parsing all valid JSON.
863+ case endOfStreamGarbage(offset: Int)
864+
865+ /// Too many nested objects or arrays occured at the literal started
866+ /// around `offset`.
867+ case exceededNestingLimit(offset: Int)
868+
869+ /// A `character` was not a valid start of a value around `offset`.
870+ case valueInvalid(offset: Int, character: UnicodeScalar)
871+
872+ /// Badly-formed Unicode escape sequence at `offset`. A Unicode escape
873+ /// uses the text "\u" followed by 4 hex digits, such as "\uF09F\uA684"
874+ /// to represent U+1F984, "UNICORN FACE".
875+ case unicodeEscapeInvalid(offset: Int)
876+
877+ /// Badly-formed control character around `offset`. JSON supports
878+ /// backslash-escaped double quotes, slashes, whitespace control codes,
879+ /// and Unicode escape sequences.
880+ case controlCharacterUnrecognized(offset: Int)
881+
882+ /// Invalid token, expected `null` around `offset`
883+ case literalNilMisspelled(offset: Int)
884+
885+ /// Invalid token, expected `true` around `offset`
886+ case literalTrueMisspelled(offset: Int)
887+
888+ /// Invalid token, expected `false` around `offset`
889+ case literalFalseMisspelled(offset: Int)
890+
891+ /// Badly-formed collection at given `offset`, expected `,` or `:`
892+ case collectionMissingSeparator(offset: Int)
893+
894+ /// While parsing an object literal, a value was found without a key
895+ /// around `offset`. The start of a string literal was expected.
896+ case dictionaryMissingKey(offset: Int)
897+
898+ /// Badly-formed number with no digits around `offset`. After a decimal
899+ /// point, a number must include some number of digits.
900+ case numberMissingFractionalDigits(offset: Int)
901+
902+ /// Badly-formed number with symbols ("-" or "e") but no following
903+ /// digits around `offset`.
904+ case numberSymbolMissingDigits(offset: Int)
905+
906+ /// Supplied data is encoded in an unsupported format.
907+ case invalidUnicodeStreamEncoding(detectedEncoding: JSONEncodingDetector.Encoding)
908+ }
909+
910+ fileprivate enum InternalError: Swift.Error {
911+ /// Attempted to parse an integer outside the range of [Int.min, Int.max]
912+ /// or a double outside the range of representable doubles. Note that
913+ /// for doubles, this could be an overflow or an underflow - we don't
914+ /// get enough information from Swift here to know which it is. The number
915+ /// causing the overflow/underflow began at `offset`.
916+ case numberOverflow(offset: Int)
917+ }
918+}
parsers/test_Freddy_20161018/test_Freddy/JSONParsing.swiftnew file+126
@@ -0,0 +1,126 @@
1+//
2+// JSONParsing.swift
3+// Freddy
4+//
5+// Created by Matthew D. Mathias on 3/17/15.
6+// Copyright © 2015 Big Nerd Ranch. All rights reserved.
7+//
8+
9+import Foundation
10+
11+// MARK: - Deserialize JSON
12+
13+/// Protocol describing a backend parser that can produce `JSON` from `Data`.
14+public protocol JSONParserType {
15+
16+ /// Creates an instance of `JSON` from `Data`.
17+ /// - parameter data: An instance of `Data` to use to create `JSON`.
18+ /// - throws: An error that may arise from calling `JSONObjectWithData(_:options:)` on `NSJSONSerialization` with the given data.
19+ /// - returns: An instance of `JSON`.
20+ static func createJSON(from data: Data) throws -> JSON
21+
22+}
23+
24+extension JSON {
25+
26+ /// Create `JSON` from UTF-8 `data`. By default, parses using the
27+ /// Swift-native `JSONParser` backend.
28+ public init(data: Data, usingParser parser: JSONParserType.Type = JSONParser.self) throws {
29+ self = try parser.createJSON(from: data)
30+ }
31+
32+ /// Create `JSON` from UTF-8 `string`.
33+ public init(jsonString: Swift.String, usingParser parser: JSONParserType.Type = JSONParser.self) throws {
34+ self = try parser.createJSON(from: jsonString.data(using: Swift.String.Encoding.utf8) ?? Data())
35+ }
36+}
37+
38+// MARK: - NSJSONSerialization
39+
40+extension JSONSerialization: JSONParserType {
41+
42+ // MARK: Decode Data
43+
44+ /// Use the built-in, Objective-C based JSON parser to create `JSON`.
45+ /// - parameter data: An instance of `Data`.
46+ /// - returns: An instance of `JSON`.
47+ /// - throws: An error that may arise if the `Data` cannot be parsed into an object.
48+ public static func createJSON(from data: Data) throws -> JSON {
49+ return makeJSON(with: try JSONSerialization.jsonObject(with: data, options: []))
50+ }
51+
52+ // MARK: Make JSON
53+
54+ /// Makes a `JSON` object by matching its argument to a case in the `JSON` enum.
55+ /// - parameter object: The instance of `Any` returned from serializing the JSON.
56+ /// - returns: An instance of `JSON` matching the JSON given to the function.
57+ private static func makeJSON(with object: Any) -> JSON {
58+ switch object {
59+ case let n as NSNumber:
60+ let numberType = CFNumberGetType(n)
61+ switch numberType {
62+ case .charType:
63+ return .bool(n.boolValue)
64+
65+ case .shortType, .intType, .longType, .cfIndexType, .nsIntegerType, .sInt8Type, .sInt16Type, .sInt32Type:
66+ return .int(n.intValue)
67+
68+ case .sInt64Type, .longLongType /* overflows 32-bit Int */:
69+ #if /* 32-bit arch */ arch(arm) || arch(i386)
70+ // Why double, when the Freddy parser would bump to String?
71+ //
72+ // Returning Double avoids making the type depend on whether you're running
73+ // 32-bit or 64-bit code when using the NSJSONSerialization parser.
74+ // NSJSONSerialization appears to bump numbers larger than Int.max to Double on
75+ // 64-bit platforms but use .SInt64Type on 32-bit platforms.
76+ // If we returned a String here, you'd get a String value on 32-bit,
77+ // but a Double value on 64-bit. Instead, we return Double.
78+ //
79+ // This means that, if you switch parsers,
80+ // you'll have to switch from .double to .string for pulling out
81+ // overflowing values, but if you stick with a single parser,
82+ // you at least won't have architecture-dependent lookups!
83+ return .double(n.doubleValue)
84+ #else
85+ return .int(n.intValue)
86+ #endif
87+
88+ case .float32Type, .float64Type, .floatType, .doubleType, .cgFloatType:
89+ return .double(n.doubleValue)
90+ }
91+
92+ case let arr as [Any]:
93+ return makeJSONArray(arr)
94+
95+ case let dict as [Swift.String: Any]:
96+ return makeJSONDictionary(dict)
97+
98+ case let s as Swift.String:
99+ return .string(s)
100+
101+ default:
102+ return .null
103+ }
104+ }
105+
106+ // MARK: Make a JSON Array
107+
108+ /// Makes a `JSON` array from the object passed in.
109+ /// - parameter jsonArray: The array to transform into a `JSON`.
110+ /// - returns: An instance of `JSON` matching the array.
111+ private static func makeJSONArray(_ jsonArray: [Any]) -> JSON {
112+ return .array(jsonArray.map(makeJSON))
113+ }
114+
115+ // MARK: Make a JSON Dictionary
116+
117+ /// Makes a `JSON` dictionary from the Cocoa dictionary passed in.
118+ /// - parameter jsonDict: The dictionary to transform into `JSON`.
119+ /// - returns: An instance of `JSON` matching the dictionary.
120+ private static func makeJSONDictionary(_ jsonDict: [Swift.String: Any]) -> JSON {
121+ return JSON(jsonDict.lazy.map { (key, value) in
122+ (key, makeJSON(with: value))
123+ })
124+ }
125+
126+}
parsers/test_Freddy_20161018/test_Freddy/JSONSerializing.swiftnew file+54
@@ -0,0 +1,54 @@
1+// Copyright (C) 2016 Big Nerd Ranch, Inc. Licensed under the MIT license WITHOUT ANY WARRANTY.
2+
3+import Foundation
4+
5+// MARK: - Serialize JSON
6+
7+extension JSON {
8+
9+ /// Attempt to serialize `JSON` into an `Data`.
10+ /// - returns: A byte-stream containing the `JSON` ready for wire transfer.
11+ /// - throws: Errors that arise from `JSONSerialization`.
12+ /// - see: Foundation.JSONSerialization
13+ public func serialize() throws -> Data {
14+ return try JSONSerialization.data(withJSONObject: toJSONSerializationValue(), options: [])
15+ }
16+
17+ /// Attempt to serialize `JSON` into a `String`.
18+ /// - returns: A `String` containing the `JSON`.
19+ /// - throws: A `JSON.Error.StringSerializationError` or errors that arise from `JSONSerialization`.
20+ /// - see: Foundation.JSONSerialization
21+ public func serializeString() throws -> String {
22+ let data = try self.serialize()
23+ guard let json = String(data: data, encoding: String.Encoding.utf8) else {
24+ throw Error.stringSerializationError
25+ }
26+ return json
27+ }
28+
29+ /// A function to help with the serialization of `JSON`.
30+ /// - returns: An `Any` suitable for `JSONSerialization`'s use.
31+ private func toJSONSerializationValue() -> Any {
32+ switch self {
33+ case .array(let jsonArray):
34+ return jsonArray.map { $0.toJSONSerializationValue() }
35+ case .dictionary(let jsonDictionary):
36+ var cocoaDictionary = Swift.Dictionary<Swift.String, Any>(minimumCapacity: jsonDictionary.count)
37+ for (key, json) in jsonDictionary {
38+ cocoaDictionary[key] = json.toJSONSerializationValue()
39+ }
40+ return cocoaDictionary
41+ case .string(let str):
42+ return str
43+ case .double(let num):
44+ return NSNumber(value: num)
45+ case .int(let int):
46+ return NSNumber(value: int)
47+ case .bool(let b):
48+ return NSNumber(value: b)
49+ case .null:
50+ return NSNull()
51+ }
52+
53+ }
54+}
parsers/test_Freddy_20161018/test_Freddy/JSONSubscripting.swiftnew file+613
@@ -0,0 +1,613 @@
1+//
2+// JSONSubscripting.swift
3+// Freddy
4+//
5+// Created by Zachary Waldowski on 8/15/15.
6+// Copyright © 2015 Big Nerd Ranch. All rights reserved.
7+//
8+
9+// MARK: JSONPathType
10+
11+/// A protocol used to define a path within an instance of `JSON` that leads to some desired value.
12+///
13+/// A custom type, such as a `RawRepresentable` enum, may be made to conform to `JSONPathType`
14+/// and used with the subscript APIs.
15+public protocol JSONPathType {
16+ /// Use `self` to key into a `dictionary`.
17+ ///
18+ /// Unlike Swift dictionaries, failing to find a value for a key should throw
19+ /// an error rather than convert to `nil`.
20+ ///
21+ /// Upon failure, implementers should throw an error from `JSON.Error`.
22+ func value(in dictionary: [String : JSON]) throws -> JSON
23+
24+ /// Use `self` to index into an `array`.
25+ ///
26+ /// Unlike Swift arrays, attempting to index outside the collection's bounds
27+ /// should throw an error rather than crash.
28+ ///
29+ /// Upon failure, implementers should throw an error from `JSON.Error`.
30+ func value(in array: [JSON]) throws -> JSON
31+}
32+
33+extension JSONPathType {
34+
35+ /// The default behavior for keying into a dictionary is to throw
36+ /// `JSON.Error.UnexpectedSubscript`.
37+ public func value(in dictionary: [String : JSON]) throws -> JSON {
38+ throw JSON.Error.unexpectedSubscript(type: Self.self)
39+ }
40+
41+ /// The default behavior for indexing into an array is to throw
42+ /// `JSON.Error.UnexpectedSubscript`.
43+ public func value(in array: [JSON]) throws -> JSON {
44+ throw JSON.Error.unexpectedSubscript(type: Self.self)
45+ }
46+
47+}
48+
49+extension String: JSONPathType {
50+
51+ /// A method used to retrieve a value from a given dictionary for a specific key.
52+ /// - parameter dictionary: A `Dictionary` with `String` keys and `JSON` values.
53+ /// - throws: `.KeyNotFound` with an associated value of `self`, where `self` is a `String`,
54+ /// should the key not be present within the `JSON`.
55+ /// - returns: The `JSON` value associated with the given key.
56+ public func value(in dictionary: [String : JSON]) throws -> JSON {
57+ guard let next = dictionary[self] else {
58+ throw JSON.Error.keyNotFound(key: self)
59+ }
60+ return next
61+ }
62+
63+}
64+
65+extension Int: JSONPathType {
66+
67+ /// A method used to retrieve a value from a given array for a specific index.
68+ /// - parameter array: An `Array` of `JSON`.
69+ /// - throws: `.IndexOutOfBounds` with an associated value of `self`, where `self` is an `Int`,
70+ /// should the index not be within the valid range for the array of `JSON`.
71+ /// - returns: The `JSON` value found at the given index.
72+ public func value(in array: [JSON]) throws -> JSON {
73+ guard case array.indices = self else {
74+ throw JSON.Error.indexOutOfBounds(index: self)
75+ }
76+ return array[self]
77+ }
78+
79+}
80+
81+// MARK: - Subscripting core
82+
83+private extension JSON {
84+
85+ enum SubscriptError: Swift.Error {
86+ case subscriptIntoNull(JSONPathType)
87+ }
88+
89+ func value(for pathFragment: JSONPathType, detectingNull: Bool) throws -> JSON {
90+ switch self {
91+ case .null where detectingNull:
92+ throw SubscriptError.subscriptIntoNull(pathFragment)
93+ case let .dictionary(dict):
94+ return try pathFragment.value(in: dict)
95+ case let .array(array):
96+ return try pathFragment.value(in: array)
97+ default:
98+ throw Error.unexpectedSubscript(type: type(of: pathFragment))
99+ }
100+ }
101+
102+ func value(at path: [JSONPathType], detectingNull: Bool = false) throws -> JSON {
103+ var result = self
104+ for pathFragment in path {
105+ result = try result.value(for: pathFragment, detectingNull: detectingNull)
106+ }
107+ return result
108+ }
109+
110+}
111+
112+// MARK: - Subscripting operator
113+
114+extension JSON {
115+
116+ public subscript(key: String) -> JSON? {
117+ return try? value(for: key, detectingNull: false)
118+ }
119+
120+ public subscript(index: Int) -> JSON? {
121+ return try? value(for: index, detectingNull: false)
122+ }
123+
124+}
125+
126+// MARK: - Simple member unpacking
127+
128+extension JSON {
129+
130+ /// Attempts to decode into the returning type from a path into JSON.
131+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`.
132+ /// - parameter type: If the context this method is called from does not
133+ /// make the return type clear, pass a type implementing `JSONDecodable`
134+ /// to disambiguate the type to decode with.
135+ /// - returns: An initialized member from the inner JSON.
136+ /// - throws: One of the following errors contained in `JSON.Error`:
137+ /// * `KeyNotFound`: A given `String` key does not exist inside a
138+ /// descendant `JSON` dictionary.
139+ /// * `IndexOutOfBounds`: A given `Int` index is outside the bounds of a
140+ /// descendant `JSON` array.
141+ /// * `UnexpectedSubscript`: A given subscript cannot be used with the
142+ /// corresponding `JSON` value.
143+ /// * `TypeNotConvertible`: The target value's type inside of
144+ /// the `JSON` instance does not match `Decoded`.
145+ public func decode<Decoded: JSONDecodable>(at path: JSONPathType..., type: Decoded.Type = Decoded.self) throws -> Decoded {
146+ return try Decoded(json: value(at: path))
147+ }
148+
149+ /// Retrieves a `Double` from a path into JSON.
150+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
151+ /// - returns: A floating-point `Double`
152+ /// - throws: One of the `JSON.Error` cases thrown by `decode(at:type:)`.
153+ /// - seealso: `JSON.decode(at:type:)`
154+ public func getDouble(at path: JSONPathType...) throws -> Double {
155+ return try Double(json: value(at: path))
156+ }
157+
158+ /// Retrieves an `Int` from a path into JSON.
159+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
160+ /// - returns: A numeric `Int`
161+ /// - throws: One of the `JSON.Error` cases thrown by `decode(at:type:)`.
162+ /// - seealso: `JSON.decode(at:type:)`
163+ public func getInt(at path: JSONPathType...) throws -> Int {
164+ return try Int(json: value(at: path))
165+ }
166+
167+ /// Retrieves a `String` from a path into JSON.
168+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
169+ /// - returns: A textual `String`
170+ /// - throws: One of the `JSON.Error` cases thrown by `decode(at:type:)`.
171+ /// - seealso: `JSON.decode(at:type:)`
172+ public func getString(at path: JSONPathType...) throws -> String {
173+ return try String(json: value(at: path))
174+ }
175+
176+ /// Retrieves a `Bool` from a path into JSON.
177+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
178+ /// - returns: A truthy `Bool`
179+ /// - throws: One of the `JSON.Error` cases thrown by `decode(at:type:)`.
180+ /// - seealso: `JSON.decode(at:type:)`
181+ public func getBool(at path: JSONPathType...) throws -> Bool {
182+ return try Bool(json: value(at: path))
183+ }
184+
185+ /// Retrieves a `[JSON]` from a path into JSON.
186+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
187+ /// - returns: An `Array` of `JSON` elements
188+ /// - throws: One of the `JSON.Error` cases thrown by `decode(at:type:)`.
189+ /// - seealso: `JSON.decode(at:type:)`
190+ public func getArray(at path: JSONPathType...) throws -> [JSON] {
191+ return try JSON.getArray(from: value(at: path))
192+ }
193+
194+ /// Attempts to decode many values from a descendant JSON array at a path
195+ /// into JSON.
196+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
197+ /// - parameter type: If the context this method is called from does not
198+ /// make the return type clear, pass a type implementing `JSONDecodable`
199+ /// to disambiguate the type to decode with.
200+ /// - returns: An `Array` of decoded elements
201+ /// - throws: One of the `JSON.Error` cases thrown by `decode(at:type:)`, or
202+ /// any error that arises from decoding the contained values.
203+ /// - seealso: `JSON.decode(at:type:)`
204+ public func decodedArray<Decoded: JSONDecodable>(at path: JSONPathType..., type: Decoded.Type = Decoded.self) throws -> [Decoded] {
205+ return try JSON.decodedArray(from: value(at: path))
206+ }
207+
208+ /// Retrieves a `[String: JSON]` from a path into JSON.
209+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
210+ /// - returns: An `Dictionary` of `String` mapping to `JSON` elements
211+ /// - throws: One of the `JSON.Error` cases thrown by `decode(at:type:)`.
212+ /// - seealso: `JSON.decode(at:type:)`
213+ public func getDictionary(at path: JSONPathType...) throws -> [String: JSON] {
214+ return try JSON.getDictionary(from: value(at: path))
215+ }
216+
217+ /// Attempts to decode many values from a descendant JSON object at a path
218+ /// into JSON.
219+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
220+ /// - parameter type: If the context this method is called from does not
221+ /// make the return type clear, pass a type implementing `JSONDecodable`
222+ /// to disambiguate the value type to decode with.
223+ /// - returns: A `Dictionary` of `String` keys and decoded values.
224+ /// - throws: One of the `JSON.Error` cases thrown by `decode(at:type:)` or
225+ /// any error that arises from decoding the contained values.
226+ /// - seealso: `JSON.decode(at:type:)`
227+ public func decodedDictionary<Decoded: JSONDecodable>(at path: JSONPathType..., type: Decoded.Type = Decoded.self) throws -> [String: Decoded] {
228+ return try JSON.decodedDictionary(from: value(at: path))
229+ }
230+
231+}
232+
233+// MARK: - NotFound-Or-Null-to-Optional unpacking
234+
235+extension JSON {
236+
237+ /// An `OptionSetType` used to represent the different options available for subscripting `JSON` with `null` values or missing keys.
238+ /// * `.NullBecomesNil` - Treat `null` values as `nil`.
239+ /// * `.MissingKeyBecomesNil` - Treat missing keys as `nil`.
240+ public struct SubscriptingOptions: OptionSet {
241+ public let rawValue: Int
242+ public init(rawValue: Int) {
243+ self.rawValue = rawValue
244+ }
245+
246+ /// Treat `null` values as `nil`.
247+ public static let NullBecomesNil = SubscriptingOptions(rawValue: 1 << 0)
248+ /// Treat missing keys as `nil`.
249+ public static let MissingKeyBecomesNil = SubscriptingOptions(rawValue: 1 << 1)
250+ }
251+
252+ fileprivate func mapOptional<Value>(at path: [JSONPathType], alongPath options: SubscriptingOptions, transform: (JSON) throws -> Value) throws -> Value? {
253+ let detectNull = options.contains(.NullBecomesNil)
254+ let detectNotFound = options.contains(.MissingKeyBecomesNil)
255+ var json: JSON?
256+ do {
257+ json = try value(at: path, detectingNull: detectNull)
258+ return try json.map(transform)
259+ } catch Error.indexOutOfBounds where detectNotFound {
260+ return nil
261+ } catch Error.keyNotFound where detectNotFound {
262+ return nil
263+ } catch Error.valueNotConvertible where detectNull && json == .null {
264+ return nil
265+ } catch SubscriptError.subscriptIntoNull where detectNull {
266+ return nil
267+ }
268+ }
269+}
270+
271+extension JSON {
272+
273+ /// Decodes a `JSON` instance if it is not `.Null`, throws otherwise.
274+ /// - parameter json: An instance of `JSON`.
275+ /// - returns: An instance of some type that conforms to `JSONDecodable`.
276+ /// - throws: `Error.ValueNotConvertible` if the `JSON` instance is `.Null`.
277+ private static func getDecoded<Decoded: JSONDecodable>(json: JSON) throws -> Decoded {
278+ guard json != .null else {
279+ throw Error.valueNotConvertible(value: json, to: Decoded.self)
280+ }
281+ return try Decoded.init(json: json)
282+ }
283+
284+ /// Optionally decodes into the returning type from a path into JSON.
285+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
286+ /// - parameter alongPath: Options that control what should be done with values that are `null` or keys that are missing.
287+ /// - parameter type: If the context this method is called from does not
288+ /// make the return type clear, pass a type implementing `JSONDecodable`
289+ /// to disambiguate the type to decode with.
290+ /// - returns: A decoded value from the inner JSON if found, or `nil`.
291+ /// - throws: One of the following errors contained in `JSON.Error`:
292+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
293+ /// `JSON` dictionary.
294+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
295+ /// descendant `JSON` array.
296+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
297+ /// corresponding `JSON` value.
298+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
299+ /// instance does not match the decoded value.
300+ /// * Any error that arises from decoding the value.
301+ public func decode<Decoded: JSONDecodable>(at path: JSONPathType..., alongPath options: SubscriptingOptions, type: Decoded.Type = Decoded.self) throws -> Decoded? {
302+ return try mapOptional(at: path, alongPath: options, transform: JSON.getDecoded)
303+ }
304+
305+ /// Optionally retrieves a `Double` from a path into JSON.
306+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`.
307+ /// - parameter alongPath: Options that control what should be done with values that are `null` or keys that are missing.
308+ /// - returns: A `Double` if a value could be found, otherwise `nil`.
309+ /// - throws: One of the following errors contained in `JSON.Error`:
310+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
311+ /// `JSON` dictionary.
312+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
313+ /// descendant `JSON` array.
314+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
315+ /// corresponding `JSON` value.
316+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
317+ /// instance does not match the decoded value.
318+ public func getDouble(at path: JSONPathType..., alongPath options: SubscriptingOptions) throws -> Double? {
319+ return try mapOptional(at: path, alongPath: options, transform: Double.init)
320+ }
321+
322+ /// Optionally retrieves a `Int` from a path into JSON.
323+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
324+ /// - parameter alongPath: Options that control what should be done with values that are `null` or keys that are missing.
325+ /// - returns: A numeric `Int` if a value could be found, otherwise `nil`.
326+ /// - throws: One of the following errors contained in `JSON.Error`:
327+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
328+ /// `JSON` dictionary.
329+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
330+ /// descendant `JSON` array.
331+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
332+ /// corresponding `JSON` value.
333+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
334+ /// instance does not match the decoded value.
335+ public func getInt(at path: JSONPathType..., alongPath options: SubscriptingOptions) throws -> Int? {
336+ return try mapOptional(at: path, alongPath: options, transform: Int.init)
337+ }
338+
339+ /// Optionally retrieves a `String` from a path into JSON.
340+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
341+ /// - parameter alongPath: Options that control what should be done with values that are `null` or keys that are missing.
342+ /// - returns: A text `String` if a value could be found, otherwise `nil`.
343+ /// - throws: One of the following errors contained in `JSON.Error`:
344+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
345+ /// `JSON` dictionary.
346+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
347+ /// descendant `JSON` array.
348+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
349+ /// corresponding `JSON` value.
350+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
351+ /// instance does not match the decoded value.
352+ public func getString(at path: JSONPathType..., alongPath options: SubscriptingOptions) throws -> String? {
353+ return try mapOptional(at: path, alongPath: options, transform: String.init)
354+ }
355+
356+ /// Optionally retrieves a `Bool` from a path into JSON.
357+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
358+ /// - parameter alongPath: Options that control what should be done with values that are `null` or keys that are missing.
359+ /// - returns: A truthy `Bool` if a value could be found, otherwise `nil`.
360+ /// - throws: One of the following errors contained in `JSON.Error`:
361+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
362+ /// `JSON` dictionary.
363+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
364+ /// descendant `JSON` array.
365+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
366+ /// corresponding `JSON` value.
367+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
368+ /// instance does not match the decoded value.
369+ public func getBool(at path: JSONPathType..., alongPath options: SubscriptingOptions) throws -> Bool? {
370+ return try mapOptional(at: path, alongPath: options, transform: Bool.init)
371+ }
372+
373+ /// Optionally retrieves a `[JSON]` from a path into the recieving structure.
374+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
375+ /// - parameter alongPath: Options that control what should be done with values that are `null` or keys that are missing.
376+ /// - returns: An `Array` of `JSON` elements if a value could be found,
377+ /// otherwise `nil`.
378+ /// - throws: One of the following errors contained in `JSON.Error`:
379+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
380+ /// `JSON` dictionary.
381+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
382+ /// descendant `JSON` array.
383+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
384+ /// corresponding `JSON` value.
385+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
386+ /// instance does not match the decoded value.
387+ public func getArray(at path: JSONPathType..., alongPath options: SubscriptingOptions) throws -> [JSON]? {
388+ return try mapOptional(at: path, alongPath: options, transform: JSON.getArray)
389+ }
390+
391+ /// Optionally decodes many values from a descendant array at a path into
392+ /// JSON.
393+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
394+ /// - parameter alongPath: Options that control what should be done with values that are `null` or keys that are missing.
395+ /// - parameter type: If the context this method is called from does not
396+ /// make the return type clear, pass a type implementing `JSONDecodable`
397+ /// to disambiguate the value type to decode with.
398+ /// - returns: An `Array` of decoded elements if found, otherwise `nil`.
399+ /// - throws: One of the following errors contained in `JSON.Error`:
400+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
401+ /// `JSON` dictionary.
402+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
403+ /// descendant `JSON` array.
404+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
405+ /// corresponding `JSON` value.
406+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
407+ /// instance does not match the decoded value.
408+ /// * Any error that arises from decoding the value.
409+ public func decodedArray<Decoded: JSONDecodable>(at path: JSONPathType..., alongPath options: SubscriptingOptions, type: Decoded.Type = Decoded.self) throws -> [Decoded]? {
410+ return try mapOptional(at: path, alongPath: options, transform: JSON.decodedArray)
411+ }
412+
413+ /// Optionally retrieves a `[String: JSON]` from a path into the recieving
414+ /// structure.
415+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
416+ /// - parameter alongPath: Options that control what should be done with values that are `null` or keys that are missing.
417+ /// - returns: A `Dictionary` of `String` mapping to `JSON` elements if a
418+ /// value could be found, otherwise `nil`.
419+ /// - throws: One of the following errors contained in `JSON.Error`:
420+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
421+ /// `JSON` dictionary.
422+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
423+ /// descendant `JSON` array.
424+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
425+ /// corresponding `JSON` value.
426+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
427+ /// instance does not match the decoded value.
428+ public func getDictionary(at path: JSONPathType..., alongPath options: SubscriptingOptions) throws -> [String: JSON]? {
429+ return try mapOptional(at: path, alongPath: options, transform: JSON.getDictionary)
430+ }
431+
432+ /// Optionally attempts to decode many values from a descendant object at a path
433+ /// into JSON.
434+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
435+ /// - parameter alongPath: Options that control what should be done with values that are `null` or keys that are missing.
436+ /// - parameter type: If the context this method is called from does not
437+ /// make the return type clear, pass a type implementing `JSONDecodable`
438+ /// to disambiguate the value type to decode with.
439+ /// - returns: A `Dictionary` of `String` mapping to decoded elements if a
440+ /// value could be found, otherwise `nil`.
441+ /// - throws: One of the following errors contained in `JSON.Error`:
442+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
443+ /// `JSON` dictionary.
444+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
445+ /// descendant `JSON` array.
446+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
447+ /// corresponding `JSON` value.
448+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
449+ /// instance does not match the decoded value.
450+ /// * Any error that arises from decoding the value.
451+ public func decodedDictionary<Decoded: JSONDecodable>(at path: JSONPathType..., alongPath options: SubscriptingOptions, type: Decoded.Type = Decoded.self) throws -> [String: Decoded]? {
452+ return try mapOptional(at: path, alongPath: options, transform: JSON.decodedDictionary)
453+ }
454+
455+}
456+
457+// MARK: - Missing-with-fallback unpacking
458+
459+extension JSON {
460+
461+ fileprivate func mapOptional<Value>(at path: [JSONPathType], fallback: () -> Value, transform: (JSON) throws -> Value) throws -> Value {
462+ return try mapOptional(at: path, alongPath: .MissingKeyBecomesNil, transform: transform) ?? fallback()
463+ }
464+
465+ /// Attempts to decode into the returning type from a path into
466+ /// JSON, or returns a fallback if not found.
467+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
468+ /// - parameter fallback: Value to use when one is missing at the subscript.
469+ /// - returns: An initialized member from the inner JSON.
470+ /// - throws: One of the following errors contained in `JSON.Error`:
471+ /// * `UnexpectedSubscript`: A given subscript cannot be used with the
472+ /// corresponding `JSON` value.
473+ /// * `TypeNotConvertible`: The target value's type inside of
474+ /// the `JSON` instance does not match `Decoded`.
475+ public func decode<Decoded: JSONDecodable>(at path: JSONPathType..., or fallback: @autoclosure() -> Decoded) throws -> Decoded {
476+ return try mapOptional(at: path, fallback: fallback, transform: Decoded.init)
477+ }
478+
479+ /// Retrieves a `Double` from a path into JSON or a fallback if not found.
480+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
481+ /// - parameter fallback: `Double` to use when one is missing at the subscript.
482+ /// - returns: A floating-point `Double`
483+ /// - throws: One of the `JSON.Error` cases thrown by calling `mapOptional(at:fallback:transform:)`.
484+ public func getDouble(at path: JSONPathType..., or fallback: @autoclosure() -> Double) throws -> Double {
485+ return try mapOptional(at: path, fallback: fallback, transform: Double.init)
486+ }
487+
488+ /// Retrieves an `Int` from a path into JSON or a fallback if not found.
489+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
490+ /// - parameter fallback: `Int` to use when one is missing at the subscript.
491+ /// - returns: A numeric `Int`
492+ /// - throws: One of the following errors contained in `JSON.Error`:
493+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
494+ /// `JSON` dictionary.
495+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
496+ /// descendant `JSON` array.
497+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
498+ /// corresponding `JSON` value.
499+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
500+ /// instance does not match the decoded value.
501+ public func getInt(at path: JSONPathType..., or fallback: @autoclosure() -> Int) throws -> Int {
502+ return try mapOptional(at: path, fallback: fallback, transform: Int.init)
503+ }
504+
505+ /// Retrieves a `String` from a path into JSON or a fallback if not found.
506+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
507+ /// - parameter fallback: `String` to use when one is missing at the subscript.
508+ /// - returns: A textual `String`
509+ /// - throws: One of the following errors contained in `JSON.Error`:
510+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
511+ /// `JSON` dictionary.
512+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
513+ /// descendant `JSON` array.
514+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
515+ /// corresponding `JSON` value.
516+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
517+ /// instance does not match the decoded value.
518+ public func getString(at path: JSONPathType..., or fallback: @autoclosure() -> String) throws -> String {
519+ return try mapOptional(at: path, fallback: fallback, transform: String.init)
520+ }
521+
522+ /// Retrieves a `Bool` from a path into JSON or a fallback if not found.
523+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
524+ /// - parameter fallback: `Bool` to use when one is missing at the subscript.
525+ /// - returns: A truthy `Bool`
526+ /// - throws: One of the following errors contained in `JSON.Error`:
527+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
528+ /// `JSON` dictionary.
529+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
530+ /// descendant `JSON` array.
531+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
532+ /// corresponding `JSON` value.
533+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
534+ /// instance does not match the decoded value.
535+ public func getBool(at path: JSONPathType..., or fallback: @autoclosure() -> Bool) throws -> Bool {
536+ return try mapOptional(at: path, fallback: fallback, transform: Bool.init)
537+ }
538+
539+ /// Retrieves a `[JSON]` from a path into JSON or a fallback if not found.
540+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
541+ /// - parameter fallback: `Array` to use when one is missing at the subscript.
542+ /// - returns: An `Array` of `JSON` elements
543+ /// - throws: One of the following errors contained in `JSON.Error`:
544+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
545+ /// `JSON` dictionary.
546+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
547+ /// descendant `JSON` array.
548+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
549+ /// corresponding `JSON` value.
550+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
551+ /// instance does not match the decoded value.
552+ public func getArray(at path: JSONPathType..., or fallback: @autoclosure() -> [JSON]) throws -> [JSON] {
553+ return try mapOptional(at: path, fallback: fallback, transform: JSON.getArray)
554+ }
555+
556+ /// Attempts to decodes many values from a desendant JSON array at a path
557+ /// into the recieving structure, returning a fallback if not found.
558+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
559+ /// - parameter fallback: `Array` to use when one is missing at the subscript.
560+ /// - returns: An `Array` of decoded elements
561+ /// - throws: One of the following errors contained in `JSON.Error`:
562+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
563+ /// `JSON` dictionary.
564+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
565+ /// descendant `JSON` array.
566+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
567+ /// corresponding `JSON` value.
568+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
569+ /// instance does not match the decoded value.
570+ /// * Any error that arises from decoding the value.
571+ public func decodedArray<Decoded: JSONDecodable>(at path: JSONPathType..., or fallback: @autoclosure() -> [Decoded]) throws -> [Decoded] {
572+ return try mapOptional(at: path, fallback: fallback, transform: JSON.decodedArray)
573+ }
574+
575+ /// Retrieves a `[String: JSON]` from a path into JSON or a fallback if not
576+ /// found.
577+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
578+ /// - parameter fallback: `Dictionary` to use when one is missing at the subscript.
579+ /// - returns: An `Dictionary` of `String` mapping to `JSON` elements
580+ /// - throws: One of the following errors contained in `JSON.Error`:
581+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
582+ /// `JSON` dictionary.
583+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
584+ /// descendant `JSON` array.
585+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
586+ /// corresponding `JSON` value.
587+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
588+ /// instance does not match the decoded value.
589+ public func getDictionary(at path: JSONPathType..., or fallback: @autoclosure() -> [String: JSON]) throws -> [String: JSON] {
590+ return try mapOptional(at: path, fallback: fallback, transform: JSON.getDictionary)
591+ }
592+
593+ /// Attempts to decode many values from a descendant JSON object at a path
594+ /// into the receiving structure, returning a fallback if not found.
595+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
596+ /// - parameter fallback: Value to use when one is missing at the subscript
597+ /// - returns: A `Dictionary` of `String` mapping to decoded elements.
598+ /// - throws: One of the following errors contained in `JSON.Error`:
599+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
600+ /// `JSON` dictionary.
601+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
602+ /// descendant `JSON` array.
603+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
604+ /// corresponding `JSON` value.
605+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
606+ /// instance does not match the decoded value.
607+ /// * Any error that arises from decoding the value.
608+ public func decodedDictionary<Decoded: JSONDecodable>(at path: JSONPathType..., or fallback: @autoclosure() -> [String: Decoded]) throws -> [String: Decoded] {
609+ return try mapOptional(at: path, fallback: fallback, transform: JSON.decodedDictionary)
610+ }
611+
612+
613+}
parsers/test_Freddy_20161018/test_Freddy/main.swiftnew file+40
@@ -0,0 +1,40 @@
1+//
2+// main.swift
3+// test_Freddy
4+//
5+// Created by nst on 10/08/16.
6+// Copyright © 2016 Nicolas Seriot. All rights reserved.
7+//
8+
9+import Foundation
10+
11+func main() {
12+
13+ guard ProcessInfo.processInfo.arguments.count == 2 else {
14+ let url = URL(fileURLWithPath: ProcessInfo.processInfo.arguments[0])
15+ let programName = url.lastPathComponent
16+ print("Usage: ./\(programName) file.json")
17+ exit(1)
18+ }
19+
20+ let path = ProcessInfo.processInfo.arguments[1]
21+ let url = NSURL.fileURL(withPath:path)
22+
23+ do {
24+ let data = try Data(contentsOf:url)
25+ do {
26+ let o = try JSONParser.parse(utf8: data)
27+ exit(0)
28+ } catch {
29+ exit(1)
30+ }
31+
32+ } catch let e {
33+ print("*** CANNOT READ DATA AT \(url)")
34+ print(e)
35+ exit(1)
36+ }
37+
38+}
39+
40+main()
parsers/test_Freddy_2_1_0/bin/test_Freddy_2_1_0new file

Binary file not shown.

parsers/test_Freddy_2_1_0/test_Freddy.xcodeproj/project.pbxprojnew file+300
@@ -0,0 +1,300 @@
1+// !$*UTF8*$!
2+{
3+ archiveVersion = 1;
4+ classes = {
5+ };
6+ objectVersion = 46;
7+ objects = {
8+
9+/* Begin PBXBuildFile section */
10+ 03D84ABB1D5B0A1000776402 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03D84ABA1D5B0A1000776402 /* main.swift */; };
11+ 03F8F7811D5B75600021630C /* JSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03F8F7781D5B75600021630C /* JSON.swift */; };
12+ 03F8F7821D5B75600021630C /* JSONDecodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03F8F7791D5B75600021630C /* JSONDecodable.swift */; };
13+ 03F8F7831D5B75600021630C /* JSONEncodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03F8F77A1D5B75600021630C /* JSONEncodable.swift */; };
14+ 03F8F7841D5B75600021630C /* JSONEncodingDetector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03F8F77B1D5B75600021630C /* JSONEncodingDetector.swift */; };
15+ 03F8F7851D5B75600021630C /* JSONLiteralConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03F8F77C1D5B75600021630C /* JSONLiteralConvertible.swift */; };
16+ 03F8F7861D5B75600021630C /* JSONParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03F8F77D1D5B75600021630C /* JSONParser.swift */; };
17+ 03F8F7871D5B75600021630C /* JSONParsing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03F8F77E1D5B75600021630C /* JSONParsing.swift */; };
18+ 03F8F7881D5B75600021630C /* JSONSerializing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03F8F77F1D5B75600021630C /* JSONSerializing.swift */; };
19+ 03F8F7891D5B75600021630C /* JSONSubscripting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03F8F7801D5B75600021630C /* JSONSubscripting.swift */; };
20+/* End PBXBuildFile section */
21+
22+/* Begin PBXCopyFilesBuildPhase section */
23+ 03D84AB51D5B0A1000776402 /* CopyFiles */ = {
24+ isa = PBXCopyFilesBuildPhase;
25+ buildActionMask = 2147483647;
26+ dstPath = /usr/share/man/man1;
27+ dstSubfolderSpec = 0;
28+ files = (
29+ );
30+ runOnlyForDeploymentPostprocessing = 1;
31+ };
32+/* End PBXCopyFilesBuildPhase section */
33+
34+/* Begin PBXFileReference section */
35+ 03D84AB71D5B0A1000776402 /* test_Freddy */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = test_Freddy; sourceTree = BUILT_PRODUCTS_DIR; };
36+ 03D84ABA1D5B0A1000776402 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
37+ 03F8F7781D5B75600021630C /* JSON.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = JSON.swift; path = test_Freddy/JSON.swift; sourceTree = "<group>"; };
38+ 03F8F7791D5B75600021630C /* JSONDecodable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = JSONDecodable.swift; path = test_Freddy/JSONDecodable.swift; sourceTree = "<group>"; };
39+ 03F8F77A1D5B75600021630C /* JSONEncodable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = JSONEncodable.swift; path = test_Freddy/JSONEncodable.swift; sourceTree = "<group>"; };
40+ 03F8F77B1D5B75600021630C /* JSONEncodingDetector.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = JSONEncodingDetector.swift; path = test_Freddy/JSONEncodingDetector.swift; sourceTree = "<group>"; };
41+ 03F8F77C1D5B75600021630C /* JSONLiteralConvertible.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = JSONLiteralConvertible.swift; path = test_Freddy/JSONLiteralConvertible.swift; sourceTree = "<group>"; };
42+ 03F8F77D1D5B75600021630C /* JSONParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = JSONParser.swift; path = test_Freddy/JSONParser.swift; sourceTree = "<group>"; };
43+ 03F8F77E1D5B75600021630C /* JSONParsing.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = JSONParsing.swift; path = test_Freddy/JSONParsing.swift; sourceTree = "<group>"; };
44+ 03F8F77F1D5B75600021630C /* JSONSerializing.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = JSONSerializing.swift; path = test_Freddy/JSONSerializing.swift; sourceTree = "<group>"; };
45+ 03F8F7801D5B75600021630C /* JSONSubscripting.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = JSONSubscripting.swift; path = test_Freddy/JSONSubscripting.swift; sourceTree = "<group>"; };
46+/* End PBXFileReference section */
47+
48+/* Begin PBXFrameworksBuildPhase section */
49+ 03D84AB41D5B0A1000776402 /* Frameworks */ = {
50+ isa = PBXFrameworksBuildPhase;
51+ buildActionMask = 2147483647;
52+ files = (
53+ );
54+ runOnlyForDeploymentPostprocessing = 0;
55+ };
56+/* End PBXFrameworksBuildPhase section */
57+
58+/* Begin PBXGroup section */
59+ 03D84AAE1D5B0A1000776402 = {
60+ isa = PBXGroup;
61+ children = (
62+ 03F8F7781D5B75600021630C /* JSON.swift */,
63+ 03F8F7791D5B75600021630C /* JSONDecodable.swift */,
64+ 03F8F77A1D5B75600021630C /* JSONEncodable.swift */,
65+ 03F8F77B1D5B75600021630C /* JSONEncodingDetector.swift */,
66+ 03F8F77C1D5B75600021630C /* JSONLiteralConvertible.swift */,
67+ 03F8F77D1D5B75600021630C /* JSONParser.swift */,
68+ 03F8F77E1D5B75600021630C /* JSONParsing.swift */,
69+ 03F8F77F1D5B75600021630C /* JSONSerializing.swift */,
70+ 03F8F7801D5B75600021630C /* JSONSubscripting.swift */,
71+ 03D84AB91D5B0A1000776402 /* test_Freddy */,
72+ 03D84AB81D5B0A1000776402 /* Products */,
73+ );
74+ sourceTree = "<group>";
75+ };
76+ 03D84AB81D5B0A1000776402 /* Products */ = {
77+ isa = PBXGroup;
78+ children = (
79+ 03D84AB71D5B0A1000776402 /* test_Freddy */,
80+ );
81+ name = Products;
82+ sourceTree = "<group>";
83+ };
84+ 03D84AB91D5B0A1000776402 /* test_Freddy */ = {
85+ isa = PBXGroup;
86+ children = (
87+ 03D84ABA1D5B0A1000776402 /* main.swift */,
88+ );
89+ path = test_Freddy;
90+ sourceTree = "<group>";
91+ };
92+/* End PBXGroup section */
93+
94+/* Begin PBXNativeTarget section */
95+ 03D84AB61D5B0A1000776402 /* test_Freddy */ = {
96+ isa = PBXNativeTarget;
97+ buildConfigurationList = 03D84ABE1D5B0A1000776402 /* Build configuration list for PBXNativeTarget "test_Freddy" */;
98+ buildPhases = (
99+ 03D84AB31D5B0A1000776402 /* Sources */,
100+ 03D84AB41D5B0A1000776402 /* Frameworks */,
101+ 03D84AB51D5B0A1000776402 /* CopyFiles */,
102+ );
103+ buildRules = (
104+ );
105+ dependencies = (
106+ );
107+ name = test_Freddy;
108+ productName = test_Freddy;
109+ productReference = 03D84AB71D5B0A1000776402 /* test_Freddy */;
110+ productType = "com.apple.product-type.tool";
111+ };
112+/* End PBXNativeTarget section */
113+
114+/* Begin PBXProject section */
115+ 03D84AAF1D5B0A1000776402 /* Project object */ = {
116+ isa = PBXProject;
117+ attributes = {
118+ LastSwiftUpdateCheck = 0800;
119+ LastUpgradeCheck = 0800;
120+ ORGANIZATIONNAME = "Nicolas Seriot";
121+ TargetAttributes = {
122+ 03D84AB61D5B0A1000776402 = {
123+ CreatedOnToolsVersion = 8.0;
124+ DevelopmentTeam = VBYRKYS73S;
125+ DevelopmentTeamName = "Nicolas Seriot";
126+ ProvisioningStyle = Automatic;
127+ };
128+ };
129+ };
130+ buildConfigurationList = 03D84AB21D5B0A1000776402 /* Build configuration list for PBXProject "test_Freddy" */;
131+ compatibilityVersion = "Xcode 3.2";
132+ developmentRegion = English;
133+ hasScannedForEncodings = 0;
134+ knownRegions = (
135+ en,
136+ );
137+ mainGroup = 03D84AAE1D5B0A1000776402;
138+ productRefGroup = 03D84AB81D5B0A1000776402 /* Products */;
139+ projectDirPath = "";
140+ projectRoot = "";
141+ targets = (
142+ 03D84AB61D5B0A1000776402 /* test_Freddy */,
143+ );
144+ };
145+/* End PBXProject section */
146+
147+/* Begin PBXSourcesBuildPhase section */
148+ 03D84AB31D5B0A1000776402 /* Sources */ = {
149+ isa = PBXSourcesBuildPhase;
150+ buildActionMask = 2147483647;
151+ files = (
152+ 03F8F7881D5B75600021630C /* JSONSerializing.swift in Sources */,
153+ 03F8F7821D5B75600021630C /* JSONDecodable.swift in Sources */,
154+ 03F8F7851D5B75600021630C /* JSONLiteralConvertible.swift in Sources */,
155+ 03F8F7871D5B75600021630C /* JSONParsing.swift in Sources */,
156+ 03F8F7861D5B75600021630C /* JSONParser.swift in Sources */,
157+ 03F8F7831D5B75600021630C /* JSONEncodable.swift in Sources */,
158+ 03D84ABB1D5B0A1000776402 /* main.swift in Sources */,
159+ 03F8F7811D5B75600021630C /* JSON.swift in Sources */,
160+ 03F8F7891D5B75600021630C /* JSONSubscripting.swift in Sources */,
161+ 03F8F7841D5B75600021630C /* JSONEncodingDetector.swift in Sources */,
162+ );
163+ runOnlyForDeploymentPostprocessing = 0;
164+ };
165+/* End PBXSourcesBuildPhase section */
166+
167+/* Begin XCBuildConfiguration section */
168+ 03D84ABC1D5B0A1000776402 /* Debug */ = {
169+ isa = XCBuildConfiguration;
170+ buildSettings = {
171+ ALWAYS_SEARCH_USER_PATHS = NO;
172+ CLANG_ANALYZER_NONNULL = YES;
173+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
174+ CLANG_CXX_LIBRARY = "libc++";
175+ CLANG_ENABLE_MODULES = YES;
176+ CLANG_ENABLE_OBJC_ARC = YES;
177+ CLANG_WARN_BOOL_CONVERSION = YES;
178+ CLANG_WARN_CONSTANT_CONVERSION = YES;
179+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
180+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
181+ CLANG_WARN_EMPTY_BODY = YES;
182+ CLANG_WARN_ENUM_CONVERSION = YES;
183+ CLANG_WARN_INT_CONVERSION = YES;
184+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
185+ CLANG_WARN_UNREACHABLE_CODE = YES;
186+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
187+ CODE_SIGN_IDENTITY = "-";
188+ COPY_PHASE_STRIP = NO;
189+ DEBUG_INFORMATION_FORMAT = dwarf;
190+ ENABLE_STRICT_OBJC_MSGSEND = YES;
191+ ENABLE_TESTABILITY = YES;
192+ GCC_C_LANGUAGE_STANDARD = gnu99;
193+ GCC_DYNAMIC_NO_PIC = NO;
194+ GCC_NO_COMMON_BLOCKS = YES;
195+ GCC_OPTIMIZATION_LEVEL = 0;
196+ GCC_PREPROCESSOR_DEFINITIONS = (
197+ "DEBUG=1",
198+ "$(inherited)",
199+ );
200+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
201+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
202+ GCC_WARN_UNDECLARED_SELECTOR = YES;
203+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
204+ GCC_WARN_UNUSED_FUNCTION = YES;
205+ GCC_WARN_UNUSED_VARIABLE = YES;
206+ MACOSX_DEPLOYMENT_TARGET = 10.11;
207+ MTL_ENABLE_DEBUG_INFO = YES;
208+ ONLY_ACTIVE_ARCH = YES;
209+ SDKROOT = macosx;
210+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
211+ };
212+ name = Debug;
213+ };
214+ 03D84ABD1D5B0A1000776402 /* Release */ = {
215+ isa = XCBuildConfiguration;
216+ buildSettings = {
217+ ALWAYS_SEARCH_USER_PATHS = NO;
218+ CLANG_ANALYZER_NONNULL = YES;
219+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
220+ CLANG_CXX_LIBRARY = "libc++";
221+ CLANG_ENABLE_MODULES = YES;
222+ CLANG_ENABLE_OBJC_ARC = YES;
223+ CLANG_WARN_BOOL_CONVERSION = YES;
224+ CLANG_WARN_CONSTANT_CONVERSION = YES;
225+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
226+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
227+ CLANG_WARN_EMPTY_BODY = YES;
228+ CLANG_WARN_ENUM_CONVERSION = YES;
229+ CLANG_WARN_INT_CONVERSION = YES;
230+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
231+ CLANG_WARN_UNREACHABLE_CODE = YES;
232+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
233+ CODE_SIGN_IDENTITY = "-";
234+ COPY_PHASE_STRIP = NO;
235+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
236+ ENABLE_NS_ASSERTIONS = NO;
237+ ENABLE_STRICT_OBJC_MSGSEND = YES;
238+ GCC_C_LANGUAGE_STANDARD = gnu99;
239+ GCC_NO_COMMON_BLOCKS = YES;
240+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
241+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
242+ GCC_WARN_UNDECLARED_SELECTOR = YES;
243+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
244+ GCC_WARN_UNUSED_FUNCTION = YES;
245+ GCC_WARN_UNUSED_VARIABLE = YES;
246+ MACOSX_DEPLOYMENT_TARGET = 10.11;
247+ MTL_ENABLE_DEBUG_INFO = NO;
248+ SDKROOT = macosx;
249+ };
250+ name = Release;
251+ };
252+ 03D84ABF1D5B0A1000776402 /* Debug */ = {
253+ isa = XCBuildConfiguration;
254+ buildSettings = {
255+ FRAMEWORK_SEARCH_PATHS = (
256+ "$(inherited)",
257+ "$(PROJECT_DIR)",
258+ );
259+ PRODUCT_NAME = "$(TARGET_NAME)";
260+ SWIFT_VERSION = 2.3;
261+ };
262+ name = Debug;
263+ };
264+ 03D84AC01D5B0A1000776402 /* Release */ = {
265+ isa = XCBuildConfiguration;
266+ buildSettings = {
267+ FRAMEWORK_SEARCH_PATHS = (
268+ "$(inherited)",
269+ "$(PROJECT_DIR)",
270+ );
271+ PRODUCT_NAME = "$(TARGET_NAME)";
272+ SWIFT_VERSION = 2.3;
273+ };
274+ name = Release;
275+ };
276+/* End XCBuildConfiguration section */
277+
278+/* Begin XCConfigurationList section */
279+ 03D84AB21D5B0A1000776402 /* Build configuration list for PBXProject "test_Freddy" */ = {
280+ isa = XCConfigurationList;
281+ buildConfigurations = (
282+ 03D84ABC1D5B0A1000776402 /* Debug */,
283+ 03D84ABD1D5B0A1000776402 /* Release */,
284+ );
285+ defaultConfigurationIsVisible = 0;
286+ defaultConfigurationName = Release;
287+ };
288+ 03D84ABE1D5B0A1000776402 /* Build configuration list for PBXNativeTarget "test_Freddy" */ = {
289+ isa = XCConfigurationList;
290+ buildConfigurations = (
291+ 03D84ABF1D5B0A1000776402 /* Debug */,
292+ 03D84AC01D5B0A1000776402 /* Release */,
293+ );
294+ defaultConfigurationIsVisible = 0;
295+ defaultConfigurationName = Release;
296+ };
297+/* End XCConfigurationList section */
298+ };
299+ rootObject = 03D84AAF1D5B0A1000776402 /* Project object */;
300+}
parsers/test_Freddy_2_1_0/test_Freddy.xcodeproj/project.xcworkspace/contents.xcworkspacedatanew file+7
@@ -0,0 +1,7 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<Workspace
3+ version = "1.0">
4+ <FileRef
5+ location = "self:test_Freddy.xcodeproj">
6+ </FileRef>
7+</Workspace>
parsers/test_Freddy_2_1_0/test_Freddy.xcodeproj/project.xcworkspace/xcshareddata/test_Freddy.xcscmblueprintnew file+30
@@ -0,0 +1,30 @@
1+{
2+ "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "ED13D74FC1ED9BC322EA1859E5AD7D001676FA6A",
3+ "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : {
4+
5+ },
6+ "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : {
7+ "6ADA245F937D8ED6D99F5A7865E19F5267A169E2" : 0,
8+ "ED13D74FC1ED9BC322EA1859E5AD7D001676FA6A" : 0
9+ },
10+ "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "7B3DFA55-F9BF-41D8-8FD5-204D3162EB03",
11+ "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : {
12+ "6ADA245F937D8ED6D99F5A7865E19F5267A169E2" : "dropbox\/JSON\/test_Freddy\/Vendor\/Freddy\/",
13+ "ED13D74FC1ED9BC322EA1859E5AD7D001676FA6A" : "dropbox\/"
14+ },
15+ "DVTSourceControlWorkspaceBlueprintNameKey" : "test_Freddy",
16+ "DVTSourceControlWorkspaceBlueprintVersion" : 204,
17+ "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "JSON\/test_Freddy\/test_Freddy.xcodeproj",
18+ "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [
19+ {
20+ "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/bignerdranch\/Freddy.git",
21+ "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
22+ "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "6ADA245F937D8ED6D99F5A7865E19F5267A169E2"
23+ },
24+ {
25+ "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "\/Users\/nst\/Dropbox\/dropbox.git",
26+ "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
27+ "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "ED13D74FC1ED9BC322EA1859E5AD7D001676FA6A"
28+ }
29+ ]
30+}
parsers/test_Freddy_2_1_0/test_Freddy.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstatenew file

Binary file not shown.

parsers/test_Freddy_2_1_0/test_Freddy.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test_Freddy.xcschemenew file+91
@@ -0,0 +1,91 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<Scheme
3+ LastUpgradeVersion = "0800"
4+ version = "1.3">
5+ <BuildAction
6+ parallelizeBuildables = "YES"
7+ buildImplicitDependencies = "YES">
8+ <BuildActionEntries>
9+ <BuildActionEntry
10+ buildForTesting = "YES"
11+ buildForRunning = "YES"
12+ buildForProfiling = "YES"
13+ buildForArchiving = "YES"
14+ buildForAnalyzing = "YES">
15+ <BuildableReference
16+ BuildableIdentifier = "primary"
17+ BlueprintIdentifier = "03D84AB61D5B0A1000776402"
18+ BuildableName = "test_Freddy"
19+ BlueprintName = "test_Freddy"
20+ ReferencedContainer = "container:test_Freddy.xcodeproj">
21+ </BuildableReference>
22+ </BuildActionEntry>
23+ </BuildActionEntries>
24+ </BuildAction>
25+ <TestAction
26+ buildConfiguration = "Debug"
27+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
28+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
29+ shouldUseLaunchSchemeArgsEnv = "YES">
30+ <Testables>
31+ </Testables>
32+ <MacroExpansion>
33+ <BuildableReference
34+ BuildableIdentifier = "primary"
35+ BlueprintIdentifier = "03D84AB61D5B0A1000776402"
36+ BuildableName = "test_Freddy"
37+ BlueprintName = "test_Freddy"
38+ ReferencedContainer = "container:test_Freddy.xcodeproj">
39+ </BuildableReference>
40+ </MacroExpansion>
41+ <AdditionalOptions>
42+ </AdditionalOptions>
43+ </TestAction>
44+ <LaunchAction
45+ buildConfiguration = "Debug"
46+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
47+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
48+ launchStyle = "0"
49+ useCustomWorkingDirectory = "NO"
50+ ignoresPersistentStateOnLaunch = "NO"
51+ debugDocumentVersioning = "YES"
52+ debugServiceExtension = "internal"
53+ allowLocationSimulation = "YES">
54+ <BuildableProductRunnable
55+ runnableDebuggingMode = "0">
56+ <BuildableReference
57+ BuildableIdentifier = "primary"
58+ BlueprintIdentifier = "03D84AB61D5B0A1000776402"
59+ BuildableName = "test_Freddy"
60+ BlueprintName = "test_Freddy"
61+ ReferencedContainer = "container:test_Freddy.xcodeproj">
62+ </BuildableReference>
63+ </BuildableProductRunnable>
64+ <AdditionalOptions>
65+ </AdditionalOptions>
66+ </LaunchAction>
67+ <ProfileAction
68+ buildConfiguration = "Release"
69+ shouldUseLaunchSchemeArgsEnv = "YES"
70+ savedToolIdentifier = ""
71+ useCustomWorkingDirectory = "NO"
72+ debugDocumentVersioning = "YES">
73+ <BuildableProductRunnable
74+ runnableDebuggingMode = "0">
75+ <BuildableReference
76+ BuildableIdentifier = "primary"
77+ BlueprintIdentifier = "03D84AB61D5B0A1000776402"
78+ BuildableName = "test_Freddy"
79+ BlueprintName = "test_Freddy"
80+ ReferencedContainer = "container:test_Freddy.xcodeproj">
81+ </BuildableReference>
82+ </BuildableProductRunnable>
83+ </ProfileAction>
84+ <AnalyzeAction
85+ buildConfiguration = "Debug">
86+ </AnalyzeAction>
87+ <ArchiveAction
88+ buildConfiguration = "Release"
89+ revealArchiveInOrganizer = "YES">
90+ </ArchiveAction>
91+</Scheme>
parsers/test_Freddy_2_1_0/test_Freddy.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plistnew file+22
@@ -0,0 +1,22 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+<plist version="1.0">
4+<dict>
5+ <key>SchemeUserState</key>
6+ <dict>
7+ <key>test_Freddy.xcscheme</key>
8+ <dict>
9+ <key>orderHint</key>
10+ <integer>0</integer>
11+ </dict>
12+ </dict>
13+ <key>SuppressBuildableAutocreation</key>
14+ <dict>
15+ <key>03D84AB61D5B0A1000776402</key>
16+ <dict>
17+ <key>primary</key>
18+ <true/>
19+ </dict>
20+ </dict>
21+</dict>
22+</plist>
parsers/test_Freddy_2_1_0/test_Freddy/JSON.swiftnew file+95
@@ -0,0 +1,95 @@
1+//
2+// JSON.swift
3+// Freddy
4+//
5+// Created by Matthew D. Mathias on 3/17/15.
6+// Copyright © 2015 Big Nerd Ranch. Licensed under MIT.
7+//
8+
9+/// An enum to describe the structure of JSON.
10+public enum JSON {
11+ /// A case for denoting an array with an associated value of `[JSON]`
12+ case Array([JSON])
13+ /// A case for denoting a dictionary with an associated value of `[Swift.String: JSON]`
14+ case Dictionary([Swift.String: JSON])
15+ /// A case for denoting a double with an associated value of `Swift.Double`.
16+ case Double(Swift.Double)
17+ /// A case for denoting an integer with an associated value of `Swift.Int`.
18+ case Int(Swift.Int)
19+ /// A case for denoting a string with an associated value of `Swift.String`.
20+ case String(Swift.String)
21+ /// A case for denoting a boolean with an associated value of `Swift.Bool`.
22+ case Bool(Swift.Bool)
23+ /// A case for denoting null.
24+ case Null
25+}
26+
27+// MARK: - Errors
28+
29+extension JSON {
30+
31+ /// An enum to encapsulate errors that may arise in working with `JSON`.
32+ public enum Error: ErrorType {
33+ /// The `index` is out of bounds for a JSON array
34+ case IndexOutOfBounds(index: Swift.Int)
35+
36+ /// The `key` was not found in the JSON dictionary
37+ case KeyNotFound(key: Swift.String)
38+
39+ /// The JSON is not subscriptable with `type`
40+ case UnexpectedSubscript(type: JSONPathType.Type)
41+
42+ /// Unexpected JSON `value` was found that is not convertible `to` type
43+ case ValueNotConvertible(value: JSON, to: Any.Type)
44+ }
45+
46+}
47+
48+// MARK: - Test Equality
49+
50+/// Return `true` if `lhs` is equal to `rhs`.
51+public func ==(lhs: JSON, rhs: JSON) -> Bool {
52+ switch (lhs, rhs) {
53+ case (.Array(let arrL), .Array(let arrR)):
54+ return arrL == arrR
55+ case (.Dictionary(let dictL), .Dictionary(let dictR)):
56+ return dictL == dictR
57+ case (.String(let strL), .String(let strR)):
58+ return strL == strR
59+ case (.Double(let dubL), .Double(let dubR)):
60+ return dubL == dubR
61+ case (.Double(let dubL), .Int(let intR)):
62+ return dubL == Double(intR)
63+ case (.Int(let intL), .Int(let intR)):
64+ return intL == intR
65+ case (.Int(let intL), .Double(let dubR)):
66+ return Double(intL) == dubR
67+ case (.Bool(let bL), .Bool(let bR)):
68+ return bL == bR
69+ case (.Null, .Null):
70+ return true
71+ default:
72+ return false
73+ }
74+}
75+
76+extension JSON: Equatable {}
77+
78+// MARK: - Printing
79+
80+extension JSON: CustomStringConvertible {
81+
82+ /// A textual representation of `self`.
83+ public var description: Swift.String {
84+ switch self {
85+ case .Array(let arr): return Swift.String(arr)
86+ case .Dictionary(let dict): return Swift.String(dict)
87+ case .String(let string): return string
88+ case .Double(let double): return Swift.String(double)
89+ case .Int(let int): return Swift.String(int)
90+ case .Bool(let bool): return Swift.String(bool)
91+ case .Null: return "null"
92+ }
93+ }
94+
95+}
parsers/test_Freddy_2_1_0/test_Freddy/JSONDecodable.swiftnew file+151
@@ -0,0 +1,151 @@
1+//
2+// JSONDecodable.swift
3+// Freddy
4+//
5+// Created by Matthew D. Mathias on 3/24/15.
6+// Copyright © 2015 Big Nerd Ranch. Licensed under MIT.
7+//
8+
9+/// A protocol to provide functionality for creating a model object with a `JSON`
10+/// value.
11+public protocol JSONDecodable {
12+
13+ /// Creates an instance of the model with a `JSON` instance.
14+ /// - parameter json: An instance of a `JSON` value from which to
15+ /// construct an instance of the implementing type.
16+ /// - throws: Any `JSON.Error` for errors derived from inspecting the
17+ /// `JSON` value, or any other error involved in decoding.
18+ init(json: JSON) throws
19+
20+}
21+
22+extension Double: JSONDecodable {
23+
24+ /// An initializer to create an instance of `Double` from a `JSON` value.
25+ /// - parameter json: An instance of `JSON`.
26+ /// - throws: The initializer will throw an instance of `JSON.Error` if
27+ /// an instance of `Double` cannot be created from the `JSON` value that was
28+ /// passed to this initializer.
29+ public init(json: JSON) throws {
30+ switch json {
31+ case let .Double(double):
32+ self = double
33+ case let .Int(int):
34+ self = Swift.Double(int)
35+ default:
36+ throw JSON.Error.ValueNotConvertible(value: json, to: Swift.Double)
37+ }
38+ }
39+
40+}
41+
42+extension Int: JSONDecodable {
43+
44+ /// An initializer to create an instance of `Int` from a `JSON` value.
45+ /// - parameter json: An instance of `JSON`.
46+ /// - throws: The initializer will throw an instance of `JSON.Error` if
47+ /// an instance of `Int` cannot be created from the `JSON` value that was
48+ /// passed to this initializer.
49+ public init(json: JSON) throws {
50+ switch json {
51+ case let .Double(double) where double <= Double(Swift.Int.max):
52+ self = Swift.Int(double)
53+ case let .Int(int):
54+ self = int
55+ default:
56+ throw JSON.Error.ValueNotConvertible(value: json, to: Swift.Int)
57+ }
58+ }
59+
60+}
61+
62+extension String: JSONDecodable {
63+
64+ /// An initializer to create an instance of `String` from a `JSON` value.
65+ /// - parameter json: An instance of `JSON`.
66+ /// - throws: The initializer will throw an instance of `JSON.Error` if
67+ /// an instance of `String` cannot be created from the `JSON` value that was
68+ /// passed to this initializer.
69+ public init(json: JSON) throws {
70+ guard case let .String(string) = json else {
71+ throw JSON.Error.ValueNotConvertible(value: json, to: Swift.String)
72+ }
73+ self = string
74+ }
75+
76+}
77+
78+extension Bool: JSONDecodable {
79+
80+ /// An initializer to create an instance of `Bool` from a `JSON` value.
81+ /// - parameter json: An instance of `JSON`.
82+ /// - throws: The initializer will throw an instance of `JSON.Error` if
83+ /// an instance of `Bool` cannot be created from the `JSON` value that was
84+ /// passed to this initializer.
85+ public init(json: JSON) throws {
86+ guard case let .Bool(bool) = json else {
87+ throw JSON.Error.ValueNotConvertible(value: json, to: Swift.Bool)
88+ }
89+ self = bool
90+ }
91+
92+}
93+
94+extension RawRepresentable where RawValue: JSONDecodable {
95+
96+ /// An initializer to create an instance of `RawRepresentable` from a `JSON` value.
97+ /// - parameter json: An instance of `JSON`.
98+ /// - throws: The initializer will throw an instance of `JSON.Error` if
99+ /// an instance of `RawRepresentable` cannot be created from the `JSON` value that was
100+ /// passed to this initializer.
101+ public init(json: JSON) throws {
102+ let raw = try json.decode(type: RawValue.self)
103+ guard let value = Self(rawValue: raw) else {
104+ throw JSON.Error.ValueNotConvertible(value: json, to: Self.self)
105+ }
106+ self = value
107+ }
108+}
109+
110+internal extension JSON {
111+
112+ /// Retrieves a `[JSON]` from the JSON.
113+ /// - returns: An `Array` of `JSON` elements
114+ /// - throws: Any of the `JSON.Error` cases thrown by `decode(type:)`.
115+ /// - seealso: `JSON.decode(_:type:)`
116+ static func getArray(json: JSON) throws -> [JSON] {
117+ // Ideally should be expressed as a conditional protocol implementation on Swift.Array.
118+ guard case let .Array(array) = json else {
119+ throw Error.ValueNotConvertible(value: json, to: Swift.Array<JSON>)
120+ }
121+ return array
122+ }
123+
124+ /// Retrieves a `[String: JSON]` from the JSON.
125+ /// - returns: An `Dictionary` of `String` mapping to `JSON` elements
126+ /// - throws: Any of the `JSON.Error` cases thrown by `decode(type:)`.
127+ /// - seealso: `JSON.decode(_:type:)`
128+ static func getDictionary(json: JSON) throws -> [Swift.String: JSON] {
129+ // Ideally should be expressed as a conditional protocol implementation on Swift.Dictionary.
130+ guard case let .Dictionary(dictionary) = json else {
131+ throw Error.ValueNotConvertible(value: json, to: Swift.Dictionary<Swift.String, JSON>)
132+ }
133+ return dictionary
134+ }
135+
136+ /// Attempts to decode many values from a descendant JSON array at a path
137+ /// into JSON.
138+ /// - parameter type: If the context this method is called from does not
139+ /// make the return type clear, pass a type implementing `JSONDecodable`
140+ /// to disambiguate the type to decode with.
141+ /// - returns: An `Array` of decoded elements
142+ /// - throws: Any of the `JSON.Error` cases thrown by `decode(type:)`, as
143+ /// well as any error that arises from decoding the contained values.
144+ /// - seealso: `JSON.decode(_:type:)`
145+ static func getArrayOf<Decoded: JSONDecodable>(json: JSON) throws -> [Decoded] {
146+ // Ideally should be expressed as a conditional protocol implementation on Swift.Dictionary.
147+ // This implementation also doesn't do the `type = Type.self` trick.
148+ return try getArray(json).map(Decoded.init)
149+ }
150+
151+}
parsers/test_Freddy_2_1_0/test_Freddy/JSONEncodable.swiftnew file+83
@@ -0,0 +1,83 @@
1+//
2+// JSONEncodable.swift
3+// Freddy
4+//
5+// Created by Matthew Mathias on 1/4/16.
6+// Copyright © 2016 Big Nerd Ranch. All rights reserved.
7+//
8+
9+import Foundation
10+
11+/// A protocol to facilitate encoding and decoding of `JSON`.
12+public protocol JSONEncodable {
13+ /// Converts an instance of a conforming type to `JSON`.
14+ /// - returns: An instance of `JSON`.
15+ /// - Note: If conforming to `JSONEncodable` with a custom type of your own, you should return an instance of
16+ /// `JSON.Dictionary`.
17+ func toJSON() -> JSON
18+}
19+
20+extension Array where Element: JSONEncodable {
21+ /// Converts an instance of `Array` whose elements conform to `JSONEncodable` to `JSON`.
22+ /// - returns: An instance of `JSON` where the enum case is `.Array`.
23+ public func toJSON() -> JSON {
24+ let arrayOfJSON = self.map { $0.toJSON() }
25+ return .Array(arrayOfJSON)
26+ }
27+}
28+
29+extension Dictionary where Value: JSONEncodable {
30+ /// Converts an instance of `Dictionary` whose values conform to `JSONEncodable` to `JSON`. The keys in the resulting
31+ /// `JSON.Dictionary` will be of type `String`.
32+ /// - returns: An instance of `JSON` where the enum case is `.Dictionary`.
33+ public func toJSON() -> JSON {
34+ var jsonDictionary = [String: JSON]()
35+
36+ for (k, v) in self {
37+ let key = String(k)
38+ jsonDictionary[key] = v.toJSON()
39+ }
40+
41+ return .Dictionary(jsonDictionary)
42+ }
43+}
44+
45+extension Int: JSONEncodable {
46+ /// Converts an instance of a conforming type to `JSON`.
47+ /// - returns: An instance of `JSON` where the enum case is `.Int`.
48+ public func toJSON() -> JSON {
49+ return .Int(self)
50+ }
51+}
52+
53+extension Double: JSONEncodable {
54+ /// Converts an instance of a conforming type to `JSON`.
55+ /// - returns: An instance of `JSON` where the enum case is `.Double`.
56+ public func toJSON() -> JSON {
57+ return .Double(self)
58+ }
59+}
60+
61+extension String: JSONEncodable {
62+ /// Converts an instance of a conforming type to `JSON`.
63+ /// - returns: An instance of `JSON` where the enum case is `.String`.
64+ public func toJSON() -> JSON {
65+ return .String(self)
66+ }
67+}
68+
69+extension Bool: JSONEncodable {
70+ /// Converts an instance of a conforming type to `JSON`.
71+ /// - returns: An instance of `JSON` where the enum case is `.Bool`.
72+ public func toJSON() -> JSON {
73+ return .Bool(self)
74+ }
75+}
76+
77+extension RawRepresentable where RawValue: JSONEncodable {
78+ /// Converts an instance of a conforming type to `JSON`.
79+ /// - returns: An instance of `JSON` where the enum case is whatever the underlying `RawValue` converts to.
80+ public func toJSON() -> JSON {
81+ return rawValue.toJSON()
82+ }
83+}
parsers/test_Freddy_2_1_0/test_Freddy/JSONEncodingDetector.swiftnew file+110
@@ -0,0 +1,110 @@
1+//
2+// JSONEncodingDetector.swift
3+// Freddy
4+//
5+// Created by Robert Edwards on 1/27/16.
6+// Copyright © 2016 Big Nerd Ranch. All rights reserved.
7+//
8+
9+/// Struct for attempting to detect the Unicode encoding used with the data supplied to the JSONParser
10+public struct JSONEncodingDetector {
11+
12+ //// The Unicode encodings looked for during detection
13+ public enum Encoding {
14+ //// UTF-8
15+ case UTF8
16+ //// UTF-16 Little Endian
17+ case UTF16LE
18+ //// UTF-16 Big Endian
19+ case UTF16BE
20+ //// UTF-32 Little Endian
21+ case UTF32LE
22+ //// UTF-32 Big Endian
23+ case UTF32BE
24+ }
25+
26+ //// The Unicode encodings supported by JSONParser.swift
27+ public static let supportedEncodings: [Encoding] = [.UTF8]
28+
29+ typealias ByteStreamPrefixInformation = (encoding: Encoding, byteOrderMarkLength: Int)
30+
31+ //// Attempts to detect the Unicode encoding used for a given set of data.
32+ ////
33+ //// This function initially looks for a Byte Order Mark in the following form:
34+ ////
35+ //// Bytes | Encoding Form
36+ //// --------------|----------------
37+ //// 00 00 FE FF | UTF-32, big-endian
38+ //// FF FE 00 00 | UTF-32, little-endian
39+ //// FE FF | UTF-16, big-endian
40+ //// FF FE | UTF-16, little-endian
41+ //// EF BB BF | UTF-8
42+ ////
43+ //// If a BOM is not found then we detect using the following approach described in
44+ //// the JSON RFC http://www.ietf.org/rfc/rfc4627.txt:
45+ ////
46+ //// Since the first two characters of a JSON text will always be ASCII
47+ //// characters [RFC0020], it is possible to determine whether an octet
48+ //// stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking
49+ //// at the pattern of nulls in the first four octets.
50+ ////
51+ //// 00 00 00 xx UTF-32BE
52+ //// 00 xx 00 xx UTF-16BE
53+ //// xx 00 00 00 UTF-32LE
54+ //// xx 00 xx 00 UTF-16LE
55+ //// xx xx xx xx UTF-8
56+ ////
57+ //// - parameter header: The front Slice of data being read and evaluated.
58+ //// - returns: A tuple containing the detected Unicode encoding and the lenght of the byte order mark.
59+ static func detectEncoding(header: Slice<UnsafeBufferPointer<UInt8>>) -> ByteStreamPrefixInformation {
60+
61+ guard let prefix = prefixFromHeader(header) else {
62+ return (.UTF8, 0)
63+ }
64+
65+ if let prefixInfo = JSONEncodingDetector.encodingFromBOM(prefix) {
66+ return prefixInfo
67+ } else {
68+ switch prefix {
69+ case(0, 0, 0?, _):
70+ return (.UTF32BE, 0)
71+ case(_, 0, 0?, 0?):
72+ return (.UTF32LE, 0)
73+ case (0, _, 0?, _), (0, _, _, _):
74+ return (.UTF16BE, 0)
75+ case (_, 0, _, 0?), (_, 0, _, _):
76+ return (.UTF16LE, 0)
77+ default:
78+ return (.UTF8, 0)
79+ }
80+ }
81+ }
82+
83+ private typealias EncodingBytePrefix = (UInt8, UInt8, UInt8?, UInt8?)
84+
85+ private static func prefixFromHeader(header: Slice<UnsafeBufferPointer<UInt8>>) -> EncodingBytePrefix? {
86+ if header.count >= 4 {
87+ return(header[0], header[1], header[2], header[3])
88+ } else if header.count >= 2 {
89+ return (header[0], header[1], nil, nil)
90+ }
91+ return nil
92+ }
93+
94+ private static func encodingFromBOM(prefix: EncodingBytePrefix) -> ByteStreamPrefixInformation? {
95+ switch prefix {
96+ case(0xFE, 0xFF, _, _):
97+ return (.UTF16BE, 2)
98+ case(0x00, 0x00, 0xFE?, 0xFF?):
99+ return (.UTF32BE, 4)
100+ case(0xEF, 0xBB, 0xBF?, _):
101+ return (.UTF8, 3)
102+ case(0xFF, 0xFE, 0?, 0?):
103+ return (.UTF32LE, 4)
104+ case(0xFF, 0xFE, _, _):
105+ return (.UTF16LE, 2)
106+ default:
107+ return nil
108+ }
109+ }
110+}
parsers/test_Freddy_2_1_0/test_Freddy/JSONLiteralConvertible.swiftnew file+130
@@ -0,0 +1,130 @@
1+//
2+// JSONLiteralConvertible.swift
3+// Freddy
4+//
5+// Created by Zachary Waldowski on 5/11/15.
6+// Copyright © 2015 Big Nerd Ranch. Licensed under MIT.
7+//
8+
9+// MARK: - ArrayLiteralConvertible
10+
11+extension JSON: ArrayLiteralConvertible {
12+
13+ /// Create an instance by copying each element of the `collection` into a
14+ /// new `Array`.
15+ public init<Collection: CollectionType where Collection.Generator.Element == JSON>(_ collection: Collection) {
16+ self = .Array(Swift.Array(collection))
17+ }
18+
19+ /// Create an instance initialized with `elements`.
20+ public init(arrayLiteral elements: JSON...) {
21+ self.init(elements)
22+ }
23+
24+}
25+
26+// MARK: - DictionaryLiteralConvertible
27+
28+extension JSON: DictionaryLiteralConvertible {
29+
30+ /// Create an instance by copying each key/value pair of the `pairs` into
31+ /// a new `Dictionary`.
32+ public init<Dictionary: SequenceType where Dictionary.Generator.Element == (Swift.String, JSON)>(_ pairs: Dictionary) {
33+ var dictionary = Swift.Dictionary<Swift.String, JSON>(minimumCapacity: pairs.underestimateCount())
34+ for (key, value) in pairs {
35+ dictionary[key] = value
36+ }
37+ self = .Dictionary(dictionary)
38+ }
39+
40+ /// Create an instance initialized with `pairs`.
41+ public init(dictionaryLiteral pairs: (Swift.String, JSON)...) {
42+ self.init(pairs)
43+ }
44+
45+}
46+
47+// MARK: - FloatLiteralConvertible
48+
49+extension JSON: FloatLiteralConvertible {
50+
51+ /// Create an instance initialized to `Double` `value`.
52+ public init(_ value: Swift.Double) {
53+ self = .Double(value)
54+ }
55+
56+ /// Create a literal instance initialized to `value`.
57+ public init(floatLiteral value: Swift.Double) {
58+ self.init(value)
59+ }
60+
61+}
62+
63+// MARK: - IntegerLiteralConvertible
64+
65+extension JSON: IntegerLiteralConvertible {
66+
67+ /// Create an instance initialized to `Int` by `value`.
68+ public init(_ value: Swift.Int) {
69+ self = .Int(value)
70+ }
71+
72+ /// Create a literal instance initialized to `value`.
73+ public init(integerLiteral value: Swift.Int) {
74+ self.init(value)
75+ }
76+
77+}
78+
79+// MARK: - StringLiteralConvertible
80+
81+extension JSON: StringLiteralConvertible {
82+
83+ /// Create an instance initialized to `String` by `text`.
84+ public init(_ text: Swift.String) {
85+ self = .String(text)
86+ }
87+
88+ /// Create a literal instance initialized to `value`.
89+ public init(stringLiteral value: StringLiteralType) {
90+ self.init(value)
91+ }
92+
93+ /// Create a literal instance initialized to `value`.
94+ public init(extendedGraphemeClusterLiteral value: StringLiteralType) {
95+ self.init(value)
96+ }
97+
98+ /// Create a literal instance initialized to `value`.
99+ public init(unicodeScalarLiteral value: StringLiteralType) {
100+ self.init(value)
101+ }
102+
103+}
104+
105+// MARK: - BooleanLiteralConvertible
106+
107+extension JSON: BooleanLiteralConvertible {
108+
109+ /// Create an instance initialized to `Bool` by `value`.
110+ public init(_ value: Swift.Bool) {
111+ self = .Bool(value)
112+ }
113+
114+ /// Create a literal instance initialized to `value`.
115+ public init(booleanLiteral value: Swift.Bool) {
116+ self.init(value)
117+ }
118+
119+}
120+
121+// MARK: - NilLiteralConvertible
122+
123+extension JSON: NilLiteralConvertible {
124+
125+ /// Create an instance initialized with `nil`.
126+ public init(nilLiteral: ()) {
127+ self = .Null
128+ }
129+
130+}
parsers/test_Freddy_2_1_0/test_Freddy/JSONParser.swiftnew file+903
@@ -0,0 +1,903 @@
1+//
2+// JSONParser.swift
3+// Freddy
4+//
5+// Created by John Gallagher on 4/18/15.
6+// Copyright © 2015 Big Nerd Ranch. Licensed under MIT.
7+//
8+
9+import Foundation
10+
11+private struct Literal {
12+ static let BACKSLASH = UInt8(ascii: "\\")
13+ static let BACKSPACE = UInt8(ascii: "\u{0008}")
14+ static let COLON = UInt8(ascii: ":")
15+ static let COMMA = UInt8(ascii: ",")
16+ static let DOUBLE_QUOTE = UInt8(ascii: "\"")
17+ static let FORMFEED = UInt8(ascii: "\u{000c}")
18+ static let LEFT_BRACE = UInt8(ascii: "{")
19+ static let LEFT_BRACKET = UInt8(ascii: "[")
20+ static let MINUS = UInt8(ascii: "-")
21+ static let NEWLINE = UInt8(ascii: "\n")
22+ static let PERIOD = UInt8(ascii: ".")
23+ static let PLUS = UInt8(ascii: "+")
24+ static let RETURN = UInt8(ascii: "\r")
25+ static let RIGHT_BRACE = UInt8(ascii: "}")
26+ static let RIGHT_BRACKET = UInt8(ascii: "]")
27+ static let SLASH = UInt8(ascii: "/")
28+ static let SPACE = UInt8(ascii: " ")
29+ static let TAB = UInt8(ascii: "\t")
30+
31+ static let a = UInt8(ascii: "a")
32+ static let b = UInt8(ascii: "b")
33+ static let c = UInt8(ascii: "c")
34+ static let d = UInt8(ascii: "d")
35+ static let e = UInt8(ascii: "e")
36+ static let f = UInt8(ascii: "f")
37+ static let l = UInt8(ascii: "l")
38+ static let n = UInt8(ascii: "n")
39+ static let r = UInt8(ascii: "r")
40+ static let s = UInt8(ascii: "s")
41+ static let t = UInt8(ascii: "t")
42+ static let u = UInt8(ascii: "u")
43+
44+ static let A = UInt8(ascii: "A")
45+ static let B = UInt8(ascii: "B")
46+ static let C = UInt8(ascii: "C")
47+ static let D = UInt8(ascii: "D")
48+ static let E = UInt8(ascii: "E")
49+ static let F = UInt8(ascii: "F")
50+
51+ static let zero = UInt8(ascii: "0")
52+ static let one = UInt8(ascii: "1")
53+ static let two = UInt8(ascii: "2")
54+ static let three = UInt8(ascii: "3")
55+ static let four = UInt8(ascii: "4")
56+ static let five = UInt8(ascii: "5")
57+ static let six = UInt8(ascii: "6")
58+ static let seven = UInt8(ascii: "7")
59+ static let eight = UInt8(ascii: "8")
60+ static let nine = UInt8(ascii: "9")
61+}
62+
63+private let ParserMaximumDepth = 512
64+
65+
66+/// A pure Swift JSON parser. This parser is much faster than the
67+/// `NSJSONSerialization`-based parser (due to the overhead of having to
68+/// dynamically cast the Objective-C objects to determine their type); however,
69+/// it is much newer and has restrictions that the `NSJSONSerialization` parser
70+/// does not. Two restrictions in particular are that it requires UTF-8 data as
71+/// input and it does not allow trailing commas in arrays or dictionaries.
72+public struct JSONParser {
73+
74+ private enum Sign: Int {
75+ case Positive = 1
76+ case Negative = -1
77+ }
78+
79+ private let input: UnsafeBufferPointer<UInt8>
80+ private let owner: Any?
81+ private var loc = 0
82+ private var depth = 0
83+
84+ private init<T>(buffer: UnsafeBufferPointer<UInt8>, owner: T) {
85+ self.input = buffer
86+ self.owner = owner
87+ }
88+
89+ /// Decode the root element of the `JSON` stream. This may be any fragment
90+ /// or a structural element, per RFC 7159.
91+ ///
92+ /// The beginning bytes are used to determine the stream's encoding.
93+ /// `JSONParser` currently only supports UTF-8 encoding, with or without
94+ /// a byte-order mark.
95+ ///
96+ /// - throws: `JSONParser.Error` for any decoding failures, including a
97+ /// source location if needed.
98+ public mutating func parse() throws -> JSON {
99+ try guardAgainstUnsupportedEncodings()
100+ let value = try parseValue()
101+ skipWhitespace()
102+ guard loc == input.count else {
103+ throw Error.EndOfStreamGarbage(offset: loc)
104+ }
105+ return value
106+ }
107+
108+ private mutating func parseValue() throws -> JSON {
109+ guard depth <= ParserMaximumDepth else {
110+ throw Error.ExceededNestingLimit(offset: loc)
111+ }
112+
113+ guard input.count > 0 else {
114+ throw Error.EndOfStreamUnexpected
115+ }
116+
117+ advancing: while loc < input.count {
118+ do {
119+ switch input[loc] {
120+ case Literal.LEFT_BRACKET:
121+ depth += 1
122+ defer { depth -= 1 }
123+ return try decodeArray()
124+
125+ case Literal.LEFT_BRACE:
126+ depth += 1
127+ defer { depth -= 1 }
128+ return try decodeObject()
129+
130+ case Literal.DOUBLE_QUOTE:
131+ return try decodeString()
132+
133+ case Literal.f:
134+ return try decodeFalse()
135+
136+ case Literal.n:
137+ return try decodeNull()
138+
139+ case Literal.t:
140+ return try decodeTrue()
141+
142+ case Literal.MINUS:
143+ return try decodeIntegralValue(NumberParser(loc: loc, input: input, state: .LeadingMinus))
144+
145+ case Literal.zero:
146+ return try decodeIntegralValue(NumberParser(loc: loc, input: input, state: .LeadingZero))
147+
148+ case Literal.one...Literal.nine:
149+ return try decodeIntegralValue(NumberParser(loc: loc, input: input, state: .PreDecimalDigits))
150+
151+ case Literal.SPACE, Literal.TAB, Literal.RETURN, Literal.NEWLINE:
152+ loc = loc.successor()
153+
154+ default:
155+ break advancing
156+ }
157+ } catch let InternalError.NumberOverflow(offset: start) {
158+ return try decodeNumberAsString(start)
159+ }
160+ }
161+
162+ throw Error.ValueInvalid(offset: loc, character: UnicodeScalar(input[loc]))
163+ }
164+
165+ private mutating func skipWhitespace() {
166+ while loc < input.count {
167+ switch input[loc] {
168+ case Literal.SPACE, Literal.TAB, Literal.RETURN, Literal.NEWLINE:
169+ loc = loc.successor()
170+
171+ default:
172+ return
173+ }
174+ }
175+ }
176+
177+ private mutating func guardAgainstUnsupportedEncodings() throws {
178+ let header = input.prefix(4)
179+ let encodingPrefixInformation = JSONEncodingDetector.detectEncoding(header)
180+ guard JSONEncodingDetector.supportedEncodings.contains(encodingPrefixInformation.encoding) else {
181+ throw Error.InvalidUnicodeStreamEncoding(detectedEncoding: encodingPrefixInformation.encoding)
182+ }
183+ loc = loc.advancedBy(encodingPrefixInformation.byteOrderMarkLength)
184+ }
185+
186+ private mutating func decodeNull() throws -> JSON {
187+ guard loc.advancedBy(3, limit: input.count) != input.count else {
188+ throw Error.LiteralNilMisspelled(offset: loc)
189+ }
190+
191+ if input[loc+1] != Literal.u
192+ || input[loc+2] != Literal.l
193+ || input[loc+3] != Literal.l {
194+ throw Error.LiteralNilMisspelled(offset: loc)
195+ }
196+
197+ loc += 4
198+ return .Null
199+ }
200+
201+ private mutating func decodeTrue() throws -> JSON {
202+ guard loc.advancedBy(3, limit: input.count) != input.count else {
203+ throw Error.LiteralTrueMisspelled(offset: loc)
204+ }
205+
206+ if input[loc+1] != Literal.r
207+ || input[loc+2] != Literal.u
208+ || input[loc+3] != Literal.e {
209+ throw Error.LiteralTrueMisspelled(offset: loc)
210+ }
211+
212+ loc += 4
213+ return .Bool(true)
214+ }
215+
216+ private mutating func decodeFalse() throws -> JSON {
217+ guard loc.advancedBy(4, limit: input.count) != input.count else {
218+ throw Error.LiteralFalseMisspelled(offset: loc)
219+ }
220+
221+ if input[loc+1] != Literal.a
222+ || input[loc+2] != Literal.l
223+ || input[loc+3] != Literal.s
224+ || input[loc+4] != Literal.e {
225+ throw Error.LiteralFalseMisspelled(offset: loc)
226+ }
227+
228+ loc += 5
229+ return .Bool(false)
230+ }
231+
232+ private var stringDecodingBuffer = [UInt8]()
233+ private mutating func decodeString() throws -> JSON {
234+ let start = loc
235+ loc = loc.successor()
236+ stringDecodingBuffer.removeAll(keepCapacity: true)
237+ while loc < input.count {
238+ switch input[loc] {
239+ case Literal.BACKSLASH:
240+ loc = loc.successor()
241+ switch input[loc] {
242+ case Literal.DOUBLE_QUOTE: stringDecodingBuffer.append(Literal.DOUBLE_QUOTE)
243+ case Literal.BACKSLASH: stringDecodingBuffer.append(Literal.BACKSLASH)
244+ case Literal.SLASH: stringDecodingBuffer.append(Literal.SLASH)
245+ case Literal.b: stringDecodingBuffer.append(Literal.BACKSPACE)
246+ case Literal.f: stringDecodingBuffer.append(Literal.FORMFEED)
247+ case Literal.r: stringDecodingBuffer.append(Literal.RETURN)
248+ case Literal.t: stringDecodingBuffer.append(Literal.TAB)
249+ case Literal.n: stringDecodingBuffer.append(Literal.NEWLINE)
250+ case Literal.u:
251+ loc = loc.successor()
252+ try readUnicodeEscape(start: loc - 2)
253+
254+ // readUnicodeEscape() advances loc on its own, so we'll `continue` now
255+ // to skip the typical "advance past this character" for all the other escapes
256+ continue
257+
258+ default:
259+ throw Error.ControlCharacterUnrecognized(offset: loc)
260+ }
261+ loc = loc.successor()
262+
263+ case Literal.DOUBLE_QUOTE:
264+ loc = loc.successor()
265+ stringDecodingBuffer.append(0)
266+
267+ guard let string = (stringDecodingBuffer.withUnsafeBufferPointer {
268+ String.fromCString(UnsafePointer($0.baseAddress))
269+ }) else {
270+ throw Error.UnicodeEscapeInvalid(offset: start)
271+ }
272+
273+ return .String(string)
274+
275+ case let other:
276+ stringDecodingBuffer.append(other)
277+ loc = loc.successor()
278+ }
279+ }
280+
281+ throw Error.EndOfStreamUnexpected
282+ }
283+
284+ private mutating func readCodeUnit() -> UInt16? {
285+ guard loc + 4 <= input.count else {
286+ return nil
287+ }
288+ var codeUnit: UInt16 = 0
289+ for c in input[loc..<loc+4] {
290+ let nibble: UInt16
291+
292+ switch c {
293+ case Literal.zero...Literal.nine:
294+ nibble = UInt16(c - Literal.zero)
295+
296+ case Literal.a...Literal.f:
297+ nibble = 10 + UInt16(c - Literal.a)
298+
299+ case Literal.A...Literal.F:
300+ nibble = 10 + UInt16(c - Literal.A)
301+
302+ default:
303+ return nil
304+ }
305+ codeUnit = (codeUnit << 4) | nibble
306+ }
307+ loc += 4
308+ return codeUnit
309+ }
310+
311+ private mutating func readUnicodeEscape(start start: Int) throws {
312+ guard let codeUnit = readCodeUnit() else {
313+ throw Error.UnicodeEscapeInvalid(offset: start)
314+ }
315+
316+ let codeUnits: [UInt16]
317+
318+ if UTF16.isLeadSurrogate(codeUnit) {
319+ // First half of a UTF16 surrogate pair - we must parse another code unit and combine them
320+
321+ // First confirm and skip over that we have another "\u"
322+ guard loc + 6 <= input.count && input[loc] == Literal.BACKSLASH && input[loc+1] == Literal.u else {
323+ throw Error.UnicodeEscapeInvalid(offset: start)
324+ }
325+ loc += 2
326+
327+ // Ensure the second code unit is valid for the surrogate pair
328+ guard let secondCodeUnit = readCodeUnit() where UTF16.isTrailSurrogate(secondCodeUnit) else {
329+ throw Error.UnicodeEscapeInvalid(offset: start)
330+ }
331+
332+ codeUnits = [codeUnit, secondCodeUnit]
333+ } else {
334+ codeUnits = [codeUnit]
335+ }
336+
337+ let transcodeHadError = transcode(UTF16.self, UTF8.self, codeUnits.generate(), { self.stringDecodingBuffer.append($0) }, stopOnError: true)
338+
339+ if transcodeHadError {
340+ throw Error.UnicodeEscapeInvalid(offset: start)
341+ }
342+ }
343+
344+ private mutating func decodeArray() throws -> JSON {
345+ let start = loc
346+ loc = loc.successor()
347+ var items = [JSON]()
348+
349+ while loc < input.count {
350+ skipWhitespace()
351+
352+ if loc < input.count && input[loc] == Literal.RIGHT_BRACKET {
353+ loc = loc.successor()
354+ return .Array(items)
355+ }
356+
357+ if !items.isEmpty {
358+ guard loc < input.count && input[loc] == Literal.COMMA else {
359+ throw Error.CollectionMissingSeparator(offset: start)
360+ }
361+ loc = loc.successor()
362+ }
363+
364+ items.append(try parseValue())
365+ }
366+
367+ throw Error.EndOfStreamUnexpected
368+ }
369+
370+ // Decoding objects can be recursive, so we have to keep more than one
371+ // buffer around for building up key/value pairs (to reduce allocations
372+ // when parsing large JSON documents).
373+ //
374+ // Rough estimate of the difference between this and using a fresh
375+ // [(String,JSON)] for the `pairs` variable in decodeObject() below is
376+ // about 12% on an iPhone 5.
377+ private struct DecodeObjectBuffers {
378+ var buffers = [[(String,JSON)]]()
379+
380+ mutating func getBuffer() -> [(String,JSON)] {
381+ if !buffers.isEmpty {
382+ var buffer = buffers.removeLast()
383+ buffer.removeAll(keepCapacity: true)
384+ return buffer
385+ }
386+ return [(String,JSON)]()
387+ }
388+
389+ mutating func putBuffer(buffer: [(String,JSON)]) {
390+ buffers.append(buffer)
391+ }
392+ }
393+
394+ private var decodeObjectBuffers = DecodeObjectBuffers()
395+
396+ private mutating func decodeObject() throws -> JSON {
397+ let start = loc
398+ loc = loc.successor()
399+ var pairs = decodeObjectBuffers.getBuffer()
400+
401+ while loc < input.count {
402+ skipWhitespace()
403+
404+ if loc < input.count && input[loc] == Literal.RIGHT_BRACE {
405+ loc = loc.successor()
406+ var obj = [String:JSON](minimumCapacity: pairs.count)
407+ for (k, v) in pairs {
408+ obj[k] = v
409+ }
410+ decodeObjectBuffers.putBuffer(pairs)
411+ return .Dictionary(obj)
412+ }
413+
414+ if !pairs.isEmpty {
415+ guard loc < input.count && input[loc] == Literal.COMMA else {
416+ throw Error.CollectionMissingSeparator(offset: start)
417+ }
418+ loc = loc.successor()
419+
420+ skipWhitespace()
421+ }
422+
423+ guard loc < input.count && input[loc] == Literal.DOUBLE_QUOTE else {
424+ throw Error.DictionaryMissingKey(offset: start)
425+ }
426+
427+ let key = try decodeString().string()
428+ skipWhitespace()
429+
430+ guard loc < input.count && input[loc] == Literal.COLON else {
431+ throw Error.CollectionMissingSeparator(offset: start)
432+ }
433+ loc = loc.successor()
434+
435+ pairs.append((key, try parseValue()))
436+ }
437+
438+ throw Error.EndOfStreamUnexpected
439+ }
440+
441+ private mutating func decodeIntegralValue(parser: NumberParser) throws -> JSON {
442+ var sign = Sign.Positive
443+ var parser = parser
444+ var value = 0
445+
446+ // This would be more natural as `while true { ... }` with a meaningful .Done case,
447+ // but that causes compile time explosion in Swift 2.2. :-|
448+ while parser.state != .Done {
449+ switch parser.state {
450+ case .LeadingMinus:
451+ sign = .Negative
452+ try parser.parseNegative()
453+
454+ case .LeadingZero:
455+ parser.parseLeadingZero()
456+
457+ case .PreDecimalDigits:
458+ try parser.parsePreDecimalDigits { c in
459+ guard case let (exponent, false) = Int.multiplyWithOverflow(10, value) else {
460+ throw InternalError.NumberOverflow(offset: parser.start)
461+ }
462+
463+ guard case let (newValue, false) = Int.addWithOverflow(exponent, Int(c - Literal.zero)) else {
464+ throw InternalError.NumberOverflow(offset: parser.start)
465+ }
466+
467+ value = newValue
468+ }
469+
470+ case .Decimal, .Exponent:
471+ return try detectingFloatingPointErrors(parser.start) {
472+ try decodeFloatingPointValue(parser, sign: sign, value: Double(value))
473+ }
474+
475+ case .PostDecimalDigits, .ExponentSign, .ExponentDigits:
476+ assertionFailure("Invalid internal state while parsing number")
477+
478+ case .Done:
479+ fatalError("impossible condition")
480+ }
481+ }
482+
483+ guard case let (signedValue, false) = Int.multiplyWithOverflow(sign.rawValue, value) else {
484+ throw InternalError.NumberOverflow(offset: parser.start)
485+ }
486+
487+ loc = parser.loc
488+ return .Int(signedValue)
489+ }
490+
491+ private mutating func decodeFloatingPointValue(parser: NumberParser, sign: Sign, value: Double) throws -> JSON {
492+ var parser = parser
493+ var value = value
494+ var exponentSign = Sign.Positive
495+ var exponent = Double(0)
496+ var position = 0.1
497+
498+ // This would be more natural as `while true { ... }` with a meaningful .Done case,
499+ // but that causes compile time explosion in Swift 2.2. :-|
500+ while parser.state != .Done {
501+ switch parser.state {
502+ case .LeadingMinus, .LeadingZero, .PreDecimalDigits:
503+ assertionFailure("Invalid internal state while parsing number")
504+
505+ case .Decimal:
506+ try parser.parseDecimal()
507+
508+ case .PostDecimalDigits:
509+ parser.parsePostDecimalDigits { c in
510+ value += position * Double(c - Literal.zero)
511+ position /= 10
512+ }
513+
514+ case .Exponent:
515+ exponentSign = try parser.parseExponent()
516+
517+ case .ExponentSign:
518+ try parser.parseExponentSign()
519+
520+ case .ExponentDigits:
521+ parser.parseExponentDigits { c in
522+ exponent = exponent * 10 + Double(c - Literal.zero)
523+ }
524+
525+ case .Done:
526+ fatalError("impossible condition")
527+ }
528+ }
529+
530+ loc = parser.loc
531+ return .Double(Double(sign.rawValue) * value * pow(10, Double(exponentSign.rawValue) * exponent))
532+ }
533+
534+ private mutating func decodeNumberAsString(start: Int) throws -> JSON {
535+ var parser: NumberParser = {
536+ let state: NumberParser.State
537+ switch input[start] {
538+ case Literal.MINUS: state = .LeadingMinus
539+ case Literal.zero: state = .LeadingZero
540+ case Literal.one...Literal.nine: state = .PreDecimalDigits
541+ default:
542+ fatalError("Internal error: decodeNumber called on not-a-number")
543+ }
544+ return NumberParser(loc: start, input: input, state: state)
545+ }()
546+
547+ stringDecodingBuffer.removeAll(keepCapacity: true)
548+
549+ while true {
550+ switch parser.state {
551+ case .LeadingMinus:
552+ try parser.parseNegative()
553+ stringDecodingBuffer.append(Literal.MINUS)
554+
555+ case .LeadingZero:
556+ parser.parseLeadingZero()
557+ stringDecodingBuffer.append(Literal.zero)
558+
559+ case .PreDecimalDigits:
560+ parser.parsePreDecimalDigits { stringDecodingBuffer.append($0) }
561+
562+ case .Decimal:
563+ try parser.parseDecimal()
564+ stringDecodingBuffer.append(Literal.PERIOD)
565+
566+ case .PostDecimalDigits:
567+ parser.parsePostDecimalDigits { stringDecodingBuffer.append($0) }
568+
569+ case .Exponent:
570+ stringDecodingBuffer.append(input[parser.loc])
571+ _ = try parser.parseExponent()
572+
573+ case .ExponentSign:
574+ stringDecodingBuffer.append(input[parser.loc])
575+ try parser.parseExponentSign()
576+
577+ case .ExponentDigits:
578+ parser.parseExponentDigits { stringDecodingBuffer.append($0) }
579+
580+ case .Done:
581+ stringDecodingBuffer.append(0)
582+ guard let string = (stringDecodingBuffer.withUnsafeBufferPointer {
583+ String.fromCString(UnsafePointer($0.baseAddress))
584+ }) else {
585+ // Should never fail - any problems with the number string should
586+ // result in thrown errors above
587+ fatalError("Internal error: Invalid numeric string")
588+ }
589+
590+ loc = parser.loc
591+ return .String(string)
592+ }
593+ }
594+ }
595+
596+ private func detectingFloatingPointErrors<T>(loc: Int, @noescape _ f: () throws -> T) throws -> T {
597+ let flags = FE_UNDERFLOW | FE_OVERFLOW
598+ feclearexcept(flags)
599+ let value = try f()
600+ guard fetestexcept(flags) == 0 else {
601+ throw InternalError.NumberOverflow(offset: loc)
602+ }
603+ return value
604+ }
605+}
606+
607+private struct NumberParser {
608+ enum State {
609+ case LeadingMinus
610+ case LeadingZero
611+ case PreDecimalDigits
612+ case Decimal
613+ case PostDecimalDigits
614+ case Exponent
615+ case ExponentSign
616+ case ExponentDigits
617+ case Done
618+ }
619+
620+ let start: Int
621+ var loc = 0
622+ var state: State
623+ let input: UnsafeBufferPointer<UInt8>
624+
625+ init(loc: Int, input: UnsafeBufferPointer<UInt8>, state: State) {
626+ assert(loc < input.count, "Invalid input to NumberParser")
627+ self.start = loc
628+ self.loc = loc
629+ self.input = input
630+ self.state = state
631+ }
632+
633+ mutating func parseNegative() throws {
634+ assert(state == .LeadingMinus, "Unexpected state entering parseNegative")
635+
636+ loc = loc.successor()
637+ guard loc < input.count else {
638+ throw JSONParser.Error.EndOfStreamUnexpected
639+ }
640+
641+ switch input[loc] {
642+ case Literal.zero:
643+ state = .LeadingZero
644+
645+ case Literal.one...Literal.nine:
646+ state = .PreDecimalDigits
647+
648+ default:
649+ throw JSONParser.Error.NumberSymbolMissingDigits(offset: start)
650+ }
651+ }
652+
653+ mutating func parseLeadingZero() {
654+ assert(state == .LeadingZero, "Unexpected state entering parseLeadingZero")
655+
656+ loc = loc.successor()
657+ guard loc < input.count else {
658+ state = .Done
659+ return
660+ }
661+
662+ guard input[loc] == Literal.PERIOD else {
663+ state = .Done
664+ return
665+ }
666+
667+ state = .Decimal
668+ }
669+
670+ mutating func parsePreDecimalDigits(@noescape f: (UInt8) throws -> Void) rethrows {
671+ assert(state == .PreDecimalDigits, "Unexpected state entering parsePreDecimalDigits")
672+ advancing: while loc < input.count {
673+ let c = input[loc]
674+ switch c {
675+ case Literal.zero...Literal.nine:
676+ try f(c)
677+ loc = loc.successor()
678+
679+ case Literal.PERIOD:
680+ state = .Decimal
681+ return
682+
683+ case Literal.e, Literal.E:
684+ state = .Exponent
685+ return
686+
687+ default:
688+ break advancing
689+ }
690+ }
691+
692+ state = .Done
693+ }
694+
695+ mutating func parseDecimal() throws {
696+ assert(state == .Decimal, "Unexpected state entering parseDecimal")
697+ loc = loc.successor()
698+ guard loc < input.count else {
699+ throw JSONParser.Error.EndOfStreamUnexpected
700+ }
701+
702+ switch input[loc] {
703+ case Literal.zero...Literal.nine:
704+ state = .PostDecimalDigits
705+
706+ default:
707+ throw JSONParser.Error.NumberMissingFractionalDigits(offset: start)
708+ }
709+ }
710+
711+ mutating func parsePostDecimalDigits(@noescape f: (UInt8) throws -> Void) rethrows {
712+ assert(state == .PostDecimalDigits, "Unexpected state entering parsePostDecimalDigits")
713+
714+ advancing: while loc < input.count {
715+ let c = input[loc]
716+ switch c {
717+ case Literal.zero...Literal.nine:
718+ try f(c)
719+ loc = loc.successor()
720+
721+ case Literal.e, Literal.E:
722+ state = .Exponent
723+ return
724+
725+ default:
726+ break advancing
727+ }
728+ }
729+
730+ state = .Done
731+ }
732+
733+ mutating func parseExponent() throws -> JSONParser.Sign {
734+ assert(state == .Exponent, "Unexpected state entering parseExponent")
735+
736+ loc = loc.successor()
737+ guard loc < input.count else {
738+ throw JSONParser.Error.EndOfStreamUnexpected
739+ }
740+
741+ switch input[loc] {
742+ case Literal.zero...Literal.nine:
743+ state = .ExponentDigits
744+
745+ case Literal.PLUS:
746+ state = .ExponentSign
747+
748+ case Literal.MINUS:
749+ state = .ExponentSign
750+ return .Negative
751+
752+ default:
753+ throw JSONParser.Error.NumberSymbolMissingDigits(offset: start)
754+ }
755+
756+ return .Positive
757+ }
758+
759+ mutating func parseExponentSign() throws {
760+ assert(state == .ExponentSign, "Unexpected state entering parseExponentSign")
761+ loc = loc.successor()
762+ guard loc < input.count else {
763+ throw JSONParser.Error.EndOfStreamUnexpected
764+ }
765+
766+ switch input[loc] {
767+ case Literal.zero...Literal.nine:
768+ state = .ExponentDigits
769+
770+ default:
771+ throw JSONParser.Error.NumberSymbolMissingDigits(offset: start)
772+ }
773+ }
774+
775+ mutating func parseExponentDigits(@noescape f: (UInt8) throws -> Void) rethrows {
776+ assert(state == .ExponentDigits, "Unexpected state entering parseExponentDigits")
777+ advancing: while loc < input.count {
778+ let c = input[loc]
779+ switch c {
780+ case Literal.zero...Literal.nine:
781+ try f(c)
782+ loc = loc.successor()
783+
784+ default:
785+ break advancing
786+ }
787+ }
788+
789+ state = .Done
790+ }
791+}
792+
793+public extension JSONParser {
794+
795+ /// Creates a `JSONParser` ready to parse UTF-8 encoded `NSData`.
796+ ///
797+ /// If the data is mutable, it is copied before parsing. The data's lifetime
798+ /// is extended for the duration of parsing.
799+ init(utf8Data inData: NSData) {
800+ let data = inData.copy() as! NSData
801+ let buffer = UnsafeBufferPointer(start: UnsafePointer<UInt8>(data.bytes), count: data.length)
802+ self.init(buffer: buffer, owner: data)
803+ }
804+
805+ /// Creates a `JSONParser` from the code units represented by the `string`.
806+ ///
807+ /// The synthesized string is lifetime-extended for the duration of parsing.
808+ init(string: String) {
809+ let codePoints = string.nulTerminatedUTF8
810+ let buffer = codePoints.withUnsafeBufferPointer { nulTerminatedBuffer in
811+ // don't want to include the nul termination in the buffer - trim it off
812+ UnsafeBufferPointer(start: nulTerminatedBuffer.baseAddress, count: nulTerminatedBuffer.count - 1)
813+ }
814+ self.init(buffer: buffer, owner: codePoints)
815+ }
816+
817+}
818+
819+extension JSONParser: JSONParserType {
820+
821+ /// Creates an instance of `JSON` from UTF-8 encoded `NSData`.
822+ /// - parameter data: An instance of `NSData` to parse `JSON` from.
823+ /// - throws: Any `JSONParser.Error` that arises during decoding.
824+ /// - seealso: JSONParser.parse()
825+ public static func createJSONFromData(data: NSData) throws -> JSON {
826+ var parser = JSONParser(utf8Data: data)
827+ return try parser.parse()
828+ }
829+
830+}
831+
832+// MARK: - Errors
833+
834+extension JSONParser {
835+
836+ /// Enumeration describing possible errors that occur while parsing a JSON
837+ /// document. Most errors include an associated `offset`, representing the
838+ /// offset into the UTF-8 characters making up the document where the error
839+ /// occurred.
840+ public enum Error: ErrorType {
841+ /// The parser ran out of data prematurely. This usually means a value
842+ /// was not escaped, such as a string literal not ending with a double
843+ /// quote.
844+ case EndOfStreamUnexpected
845+
846+ /// Unexpected non-whitespace data was left around `offset` after
847+ /// parsing all valid JSON.
848+ case EndOfStreamGarbage(offset: Int)
849+
850+ /// Too many nested objects or arrays occured at the literal started
851+ /// around `offset`.
852+ case ExceededNestingLimit(offset: Int)
853+
854+ /// A `character` was not a valid start of a value around `offset`.
855+ case ValueInvalid(offset: Int, character: UnicodeScalar)
856+
857+ /// Badly-formed Unicode escape sequence at `offset`. A Unicode escape
858+ /// uses the text "\u" followed by 4 hex digits, such as "\uF09F\uA684"
859+ /// to represent U+1F984, "UNICORN FACE".
860+ case UnicodeEscapeInvalid(offset: Int)
861+
862+ /// Badly-formed control character around `offset`. JSON supports
863+ /// backslash-escaped double quotes, slashes, whitespace control codes,
864+ /// and Unicode escape sequences.
865+ case ControlCharacterUnrecognized(offset: Int)
866+
867+ /// Invalid token, expected `null` around `offset`
868+ case LiteralNilMisspelled(offset: Int)
869+
870+ /// Invalid token, expected `true` around `offset`
871+ case LiteralTrueMisspelled(offset: Int)
872+
873+ /// Invalid token, expected `false` around `offset`
874+ case LiteralFalseMisspelled(offset: Int)
875+
876+ /// Badly-formed collection at given `offset`, expected `,` or `:`
877+ case CollectionMissingSeparator(offset: Int)
878+
879+ /// While parsing an object literal, a value was found without a key
880+ /// around `offset`. The start of a string literal was expected.
881+ case DictionaryMissingKey(offset: Int)
882+
883+ /// Badly-formed number with no digits around `offset`. After a decimal
884+ /// point, a number must include some number of digits.
885+ case NumberMissingFractionalDigits(offset: Int)
886+
887+ /// Badly-formed number with symbols ("-" or "e") but no following
888+ /// digits around `offset`.
889+ case NumberSymbolMissingDigits(offset: Int)
890+
891+ /// Supplied data is encoded in an unsupported format.
892+ case InvalidUnicodeStreamEncoding(detectedEncoding: JSONEncodingDetector.Encoding)
893+ }
894+
895+ private enum InternalError: ErrorType {
896+ /// Attempted to parse an integer outside the range of [Int.min, Int.max]
897+ /// or a double outside the range of representable doubles. Note that
898+ /// for doubles, this could be an overflow or an underflow - we don't
899+ /// get enough information from Swift here to know which it is. The number
900+ /// causing the overflow/underflow began at `offset`.
901+ case NumberOverflow(offset: Int)
902+ }
903+}
parsers/test_Freddy_2_1_0/test_Freddy/JSONParsing.swiftnew file+126
@@ -0,0 +1,126 @@
1+//
2+// JSONParsing.swift
3+// Freddy
4+//
5+// Created by Matthew D. Mathias on 3/17/15.
6+// Copyright © 2015 Big Nerd Ranch. All rights reserved.
7+//
8+
9+import Foundation
10+
11+// MARK: - Deserialize JSON
12+
13+/// Protocol describing a backend parser that can produce `JSON` from `NSData`.
14+public protocol JSONParserType {
15+
16+ /// Creates an instance of `JSON` from `NSData`.
17+ /// - parameter data: An instance of `NSData` to use to create `JSON`.
18+ /// - throws: An error that may arise from calling `JSONObjectWithData(_:options:)` on `NSJSONSerialization` with the given data.
19+ /// - returns: An instance of `JSON`.
20+ static func createJSONFromData(data: NSData) throws -> JSON
21+
22+}
23+
24+extension JSON {
25+
26+ /// Create `JSON` from UTF-8 `data`. By default, parses using the
27+ /// Swift-native `JSONParser` backend.
28+ public init(data: NSData, usingParser parser: JSONParserType.Type = JSONParser.self) throws {
29+ self = try parser.createJSONFromData(data)
30+ }
31+
32+ /// Create `JSON` from UTF-8 `string`.
33+ public init(jsonString: Swift.String, usingParser parser: JSONParserType.Type = JSONParser.self) throws {
34+ self = try parser.createJSONFromData((jsonString as NSString).dataUsingEncoding(NSUTF8StringEncoding) ?? NSData())
35+ }
36+}
37+
38+// MARK: - NSJSONSerialization
39+
40+extension NSJSONSerialization: JSONParserType {
41+
42+ // MARK: Decode NSData
43+
44+ /// Use the built-in, Objective-C based JSON parser to create `JSON`.
45+ /// - parameter data: An instance of `NSData`.
46+ /// - returns: An instance of `JSON`.
47+ /// - throws: An error that may arise if the `NSData` cannot be parsed into an object.
48+ public static func createJSONFromData(data: NSData) throws -> JSON {
49+ return makeJSON(try NSJSONSerialization.JSONObjectWithData(data, options: []))
50+ }
51+
52+ // MARK: Make JSON
53+
54+ /// Makes a `JSON` object by matching its argument to a case in the `JSON` enum.
55+ /// - parameter object: The instance of `AnyObject` returned from serializing the JSON.
56+ /// - returns: An instance of `JSON` matching the JSON given to the function.
57+ private static func makeJSON(object: AnyObject) -> JSON {
58+ switch object {
59+ case let n as NSNumber:
60+ let numberType = CFNumberGetType(n)
61+ switch numberType {
62+ case .CharType:
63+ return .Bool(n.boolValue)
64+
65+ case .ShortType, .IntType, .LongType, .CFIndexType, .NSIntegerType, .SInt8Type, .SInt16Type, .SInt32Type:
66+ return .Int(n.integerValue)
67+
68+ case .SInt64Type, .LongLongType /* overflows 32-bit Int */:
69+ #if /* 32-bit arch */ arch(arm) || arch(i386)
70+ // Why double, when the Freddy parser would bump to String?
71+ //
72+ // Returning Double avoids making the type depend on whether you're running
73+ // 32-bit or 64-bit code when using the NSJSONSerialization parser.
74+ // NSJSONSerialization appears to bump numbers larger than Int.max to Double on
75+ // 64-bit platforms but use .SInt64Type on 32-bit platforms.
76+ // If we returned a String here, you'd get a String value on 32-bit,
77+ // but a Double value on 64-bit. Instead, we return Double.
78+ //
79+ // This means that, if you switch parsers,
80+ // you'll have to switch from .double to .string for pulling out
81+ // overflowing values, but if you stick with a single parser,
82+ // you at least won't have architecture-dependent lookups!
83+ return .Double(n.doubleValue)
84+ #else
85+ return .Int(n.integerValue)
86+ #endif
87+
88+ case .Float32Type, .Float64Type, .FloatType, .DoubleType, .CGFloatType:
89+ return .Double(n.doubleValue)
90+ }
91+
92+ case let arr as [AnyObject]:
93+ return makeJSONArray(arr)
94+
95+ case let dict as [Swift.String: AnyObject]:
96+ return makeJSONDictionary(dict)
97+
98+ case let s as Swift.String:
99+ return .String(s)
100+
101+ default:
102+ return .Null
103+ }
104+ }
105+
106+ // MARK: Make a JSON Array
107+
108+ /// Makes a `JSON` array from the object passed in.
109+ /// - parameter jsonArray: The array to transform into a `JSON`.
110+ /// - returns: An instance of `JSON` matching the array.
111+ private static func makeJSONArray(jsonArray: [AnyObject]) -> JSON {
112+ return .Array(jsonArray.map(makeJSON))
113+ }
114+
115+ // MARK: Make a JSON Dictionary
116+
117+ /// Makes a `JSON` dictionary from the Cocoa dictionary passed in.
118+ /// - parameter jsonDict: The dictionary to transform into `JSON`.
119+ /// - returns: An instance of `JSON` matching the dictionary.
120+ private static func makeJSONDictionary(jsonDict: [Swift.String: AnyObject]) -> JSON {
121+ return JSON(jsonDict.lazy.map { (key, value) in
122+ (key, makeJSON(value))
123+ })
124+ }
125+
126+}
parsers/test_Freddy_2_1_0/test_Freddy/JSONSerializing.swiftnew file+43
@@ -0,0 +1,43 @@
1+// Copyright (C) 2016 Big Nerd Ranch, Inc. Licensed under the MIT license WITHOUT ANY WARRANTY.
2+
3+import Foundation
4+
5+// MARK: - Serialize JSON
6+
7+extension JSON {
8+
9+ /// Attempt to serialize `JSON` into an `NSData`.
10+ /// - returns: A byte-stream containing the `JSON` ready for wire transfer.
11+ /// - throws: Errors that arise from `NSJSONSerialization`.
12+ /// - see: Foundation.NSJSONSerialization
13+ public func serialize() throws -> NSData {
14+ let obj: AnyObject = toNSJSONSerializationObject()
15+ return try NSJSONSerialization.dataWithJSONObject(obj, options: [])
16+ }
17+
18+ /// A function to help with the serialization of `JSON`.
19+ /// - returns: An `AnyObject` suitable for `NSJSONSerialization`'s use.
20+ private func toNSJSONSerializationObject() -> AnyObject {
21+ switch self {
22+ case .Array(let jsonArray):
23+ return jsonArray.map { $0.toNSJSONSerializationObject() }
24+ case .Dictionary(let jsonDictionary):
25+ var cocoaDictionary = Swift.Dictionary<Swift.String, AnyObject>(minimumCapacity: jsonDictionary.count)
26+ for (key, json) in jsonDictionary {
27+ cocoaDictionary[key] = json.toNSJSONSerializationObject()
28+ }
29+ return cocoaDictionary
30+ case .String(let str):
31+ return str
32+ case .Double(let num):
33+ return num
34+ case .Int(let int):
35+ return int
36+ case .Bool(let b):
37+ return b
38+ case .Null:
39+ return NSNull()
40+ }
41+
42+ }
43+}
parsers/test_Freddy_2_1_0/test_Freddy/JSONSubscripting.swiftnew file+643
@@ -0,0 +1,643 @@
1+//
2+// JSONSubscripting.swift
3+// Freddy
4+//
5+// Created by Zachary Waldowski on 8/15/15.
6+// Copyright © 2015 Big Nerd Ranch. All rights reserved.
7+//
8+
9+// MARK: JSONPathType
10+
11+/// A protocol used to define a path within an instance of `JSON` that leads to some desired value.
12+///
13+/// A custom type, such as a `RawRepresentable` enum, may be made to conform to `JSONPathType`
14+/// and used with the subscript APIs.
15+public protocol JSONPathType {
16+ /// Use `self` to key into a `dictionary`.
17+ ///
18+ /// Unlike Swift dictionaries, failing to find a value for a key should throw
19+ /// an error rather than convert to `nil`.
20+ ///
21+ /// Upon failure, implementers should throw an error from `JSON.Error`.
22+ func valueInDictionary(dictionary: [Swift.String : JSON]) throws -> JSON
23+
24+ /// Use `self` to index into an `array`.
25+ ///
26+ /// Unlike Swift array, attempting to index outside the collection's bounds
27+ /// should throw an error rather than crash.
28+ ///
29+ /// Upon failure, implementers should throw an error from `JSON.Error`.
30+ func valueInArray(array: [JSON]) throws -> JSON
31+}
32+
33+extension JSONPathType {
34+
35+ /// The default behavior for keying into a dictionary is to throw
36+ /// `JSON.Error.UnexpectedSubscript`.
37+ public func valueInDictionary(dictionary: [Swift.String : JSON]) throws -> JSON {
38+ throw JSON.Error.UnexpectedSubscript(type: Self.self)
39+ }
40+
41+ /// The default behavior for indexing into an array is to throw
42+ /// `JSON.Error.UnexpectedSubscript`.
43+ public func valueInArray(array: [JSON]) throws -> JSON {
44+ throw JSON.Error.UnexpectedSubscript(type: Self.self)
45+ }
46+
47+}
48+
49+extension String: JSONPathType {
50+
51+ /// A method used to retrieve a value from a given dictionary for a specific key.
52+ /// - throws: `.KeyNotFound` with an associated value of `self`, where `self` is a `String`,
53+ /// should the key not be present within the `JSON`.
54+ /// - returns: The `JSON` value associated with the given key.
55+ public func valueInDictionary(dictionary: [Swift.String : JSON]) throws -> JSON {
56+ guard let next = dictionary[self] else {
57+ throw JSON.Error.KeyNotFound(key: self)
58+ }
59+ return next
60+ }
61+
62+}
63+
64+extension Int: JSONPathType {
65+
66+ /// A method used to retrieve a value from a given array for a specific index.
67+ /// - throws: `.IndexOutOfBounds` with an associated value of `self`, where `self` is an `Int`,
68+ /// should the index not be within the valid range for the array of `JSON`.
69+ /// - returns: The `JSON` value found at the given index.
70+ public func valueInArray(array: [JSON]) throws -> JSON {
71+ guard case array.indices = self else {
72+ throw JSON.Error.IndexOutOfBounds(index: self)
73+ }
74+ return array[self]
75+ }
76+
77+}
78+
79+// MARK: - Subscripting core
80+
81+private extension JSON {
82+
83+ enum SubscriptError: ErrorType {
84+ case SubscriptIntoNull(JSONPathType)
85+ }
86+
87+ func valueForPathFragment(fragment: JSONPathType, detectNull: Swift.Bool) throws -> JSON {
88+ switch self {
89+ case .Null where detectNull:
90+ throw SubscriptError.SubscriptIntoNull(fragment)
91+ case let .Dictionary(dict):
92+ return try fragment.valueInDictionary(dict)
93+ case let .Array(array):
94+ return try fragment.valueInArray(array)
95+ default:
96+ throw Error.UnexpectedSubscript(type: fragment.dynamicType)
97+ }
98+ }
99+
100+ func valueAtPath(path: [JSONPathType], detectNull: Swift.Bool = false) throws -> JSON {
101+ var result = self
102+ for fragment in path {
103+ result = try result.valueForPathFragment(fragment, detectNull: detectNull)
104+ }
105+ return result
106+ }
107+
108+}
109+
110+// MARK: - Subscripting operator
111+
112+extension JSON {
113+
114+ public subscript(key: Swift.String) -> JSON? {
115+ return try? valueForPathFragment(key, detectNull: false)
116+ }
117+
118+ public subscript(index: Swift.Int) -> JSON? {
119+ return try? valueForPathFragment(index, detectNull: false)
120+ }
121+
122+}
123+
124+// MARK: - Simple member unpacking
125+
126+extension JSON {
127+
128+ /// Attempts to decode into the returning type from a path into JSON.
129+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`.
130+ /// - parameter type: If the context this method is called from does not
131+ /// make the return type clear, pass a type implementing `JSONDecodable`
132+ /// to disambiguate the type to decode with.
133+ /// - returns: An initialized member from the inner JSON.
134+ /// - throws: One of the following errors contained in `JSON.Error`:
135+ /// * `KeyNotFound`: A given `String` key does not exist inside a
136+ /// descendant `JSON` dictionary.
137+ /// * `IndexOutOfBounds`: A given `Int` index is outside the bounds of a
138+ /// descendant `JSON` array.
139+ /// * `UnexpectedSubscript`: A given subscript cannot be used with the
140+ /// corresponding `JSON` value.
141+ /// * `TypeNotConvertible`: The target value's type inside of
142+ /// the `JSON` instance does not match `Decoded`.
143+ public func decode<Decoded: JSONDecodable>(path: JSONPathType..., type: Decoded.Type = Decoded.self) throws -> Decoded {
144+ return try Decoded(json: valueAtPath(path))
145+ }
146+
147+ /// Retrieves a `Double` from a path into JSON.
148+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
149+ /// - returns: A floating-point `Double`
150+ /// - throws: One of the `JSON.Error` cases thrown by `decode(_:type:)`.
151+ /// - seealso: `JSON.decode(_:type:)`
152+ public func double(path: JSONPathType...) throws -> Swift.Double {
153+ return try Swift.Double(json: valueAtPath(path))
154+ }
155+
156+ /// Retrieves an `Int` from a path into JSON.
157+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
158+ /// - returns: A numeric `Int`
159+ /// - throws: One of the `JSON.Error` cases thrown by `decode(_:type:)`.
160+ /// - seealso: `JSON.decode(_:type:)`
161+ public func int(path: JSONPathType...) throws -> Swift.Int {
162+ return try Swift.Int(json: valueAtPath(path))
163+ }
164+
165+ /// Retrieves a `String` from a path into JSON.
166+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
167+ /// - returns: A textual `String`
168+ /// - throws: One of the `JSON.Error` cases thrown by `decode(_:type:)`.
169+ /// - seealso: `JSON.decode(_:type:)`
170+ public func string(path: JSONPathType...) throws -> Swift.String {
171+ return try Swift.String(json: valueAtPath(path))
172+ }
173+
174+ /// Retrieves a `Bool` from a path into JSON.
175+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
176+ /// - returns: A truthy `Bool`
177+ /// - throws: One of the `JSON.Error` cases thrown by `decode(_:type:)`.
178+ /// - seealso: `JSON.decode(_:type:)`
179+ public func bool(path: JSONPathType...) throws -> Swift.Bool {
180+ return try Swift.Bool(json: valueAtPath(path))
181+ }
182+
183+ /// Retrieves a `[JSON]` from a path into JSON.
184+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
185+ /// - returns: An `Array` of `JSON` elements
186+ /// - throws: One of the `JSON.Error` cases thrown by `decode(_:type:)`.
187+ /// - seealso: `JSON.decode(_:type:)`
188+ public func array(path: JSONPathType...) throws -> [JSON] {
189+ return try JSON.getArray(valueAtPath(path))
190+ }
191+
192+ /// Attempts to decodes many values from a desendant JSON array at a path
193+ /// into JSON.
194+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
195+ /// - parameter type: If the context this method is called from does not
196+ /// make the return type clear, pass a type implementing `JSONDecodable`
197+ /// to disambiguate the type to decode with.
198+ /// - returns: An `Array` of decoded elements
199+ /// - throws: One of the `JSON.Error` cases thrown by `decode(_:type:)`, or
200+ /// any error that arises from decoding the contained values.
201+ /// - seealso: `JSON.decode(_:type:)`
202+ public func arrayOf<Decoded: JSONDecodable>(path: JSONPathType..., type: Decoded.Type = Decoded.self) throws -> [Decoded] {
203+ return try JSON.getArrayOf(valueAtPath(path))
204+ }
205+
206+ /// Retrieves a `[String: JSON]` from a path into JSON.
207+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
208+ /// - returns: An `Dictionary` of `String` mapping to `JSON` elements
209+ /// - throws: One of the `JSON.Error` cases thrown by `decode(_:type:)`.
210+ /// - seealso: `JSON.decode(_:type:)`
211+ public func dictionary(path: JSONPathType...) throws -> [Swift.String: JSON] {
212+ return try JSON.getDictionary(valueAtPath(path))
213+ }
214+
215+}
216+
217+// MARK: - NotFound-Or-Null-to-Optional unpacking
218+
219+extension JSON {
220+
221+ /// An `OptionSetType` used to represent the different options available for subscripting `JSON` with `null` values or missing keys.
222+ /// * `.NullBecomesNil` - Treat `null` values as `nil`.
223+ /// * `.MissingKeyBecomesNil` - Treat missing keys as `nil`.
224+ public struct SubscriptingOptions: OptionSetType {
225+ public let rawValue: Swift.Int
226+ public init(rawValue: Swift.Int) {
227+ self.rawValue = rawValue
228+ }
229+
230+ /// Treat `null` values as `nil`.
231+ public static let NullBecomesNil = SubscriptingOptions(rawValue: 1 << 0)
232+ /// Treat missing keys as `nil`.
233+ public static let MissingKeyBecomesNil = SubscriptingOptions(rawValue: 1 << 1)
234+ }
235+
236+ private func mapOptionalAtPath<Value>(path: [JSONPathType], alongPath: SubscriptingOptions, @noescape transform: JSON throws -> Value) throws -> Value? {
237+ let detectNull = alongPath.contains(.NullBecomesNil)
238+ let detectNotFound = alongPath.contains(.MissingKeyBecomesNil)
239+ var json: JSON?
240+ do {
241+ json = try valueAtPath(path, detectNull: detectNull)
242+ return try json.map(transform)
243+ } catch Error.IndexOutOfBounds where detectNotFound {
244+ return nil
245+ } catch Error.KeyNotFound where detectNotFound {
246+ return nil
247+ } catch Error.ValueNotConvertible where detectNull && json == .Null {
248+ return nil
249+ } catch SubscriptError.SubscriptIntoNull where detectNull {
250+ return nil
251+ }
252+ }
253+}
254+
255+extension JSON {
256+
257+ /// Optionally decodes into the returning type from a path into JSON.
258+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
259+ /// - parameter alongPath: Options that control what should be done with values that are `null` or keys that are missing.
260+ /// - parameter type: If the context this method is called from does not
261+ /// make the return type clear, pass a type implementing `JSONDecodable`
262+ /// to disambiguate the type to decode with.
263+ /// - returns: A decoded value from the inner JSON if found, or `nil`.
264+ /// - throws: One of the following errors contained in `JSON.Error`:
265+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
266+ /// `JSON` dictionary.
267+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
268+ /// descendant `JSON` array.
269+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
270+ /// corresponding `JSON` value.
271+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
272+ /// instance does not match the decoded value.
273+ /// * Any error that arises from decoding the value.
274+ public func decode<Decoded: JSONDecodable>(path: JSONPathType..., alongPath options: SubscriptingOptions, type: Decoded.Type = Decoded.self) throws -> Decoded? {
275+ return try mapOptionalAtPath(path, alongPath: options, transform: Decoded.init)
276+ }
277+
278+ /// Optionally retrieves a `Double` from a path into JSON.
279+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`.
280+ /// - parameter alongPath: Options that control what should be done with values that are `null` or keys that are missing.
281+ /// - returns: A `Double` if a value could be found, otherwise `nil`.
282+ /// - throws: One of the following errors contained in `JSON.Error`:
283+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
284+ /// `JSON` dictionary.
285+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
286+ /// descendant `JSON` array.
287+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
288+ /// corresponding `JSON` value.
289+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
290+ /// instance does not match the decoded value.
291+ public func double(path: JSONPathType..., alongPath options: SubscriptingOptions) throws -> Swift.Double? {
292+ return try mapOptionalAtPath(path, alongPath: options, transform: Swift.Double.init)
293+ }
294+
295+ /// Optionally retrieves a `Int` from a path into JSON.
296+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
297+ /// - parameter alongPath: Options that control what should be done with values that are `null` or keys that are missing.
298+ /// - returns: A numeric `Int` if a value could be found, otherwise `nil`.
299+ /// - throws: One of the following errors contained in `JSON.Error`:
300+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
301+ /// `JSON` dictionary.
302+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
303+ /// descendant `JSON` array.
304+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
305+ /// corresponding `JSON` value.
306+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
307+ /// instance does not match the decoded value.
308+ public func int(path: JSONPathType..., alongPath options: SubscriptingOptions) throws -> Swift.Int? {
309+ return try mapOptionalAtPath(path, alongPath: options, transform: Swift.Int.init)
310+ }
311+
312+ /// Optionally retrieves a `String` from a path into JSON.
313+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
314+ /// - parameter alongPath: Options that control what should be done with values that are `null` or keys that are missing.
315+ /// - returns: A text `String` if a value could be found, otherwise `nil`.
316+ /// - throws: One of the following errors contained in `JSON.Error`:
317+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
318+ /// `JSON` dictionary.
319+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
320+ /// descendant `JSON` array.
321+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
322+ /// corresponding `JSON` value.
323+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
324+ /// instance does not match the decoded value.
325+ public func string(path: JSONPathType..., alongPath options: SubscriptingOptions) throws -> Swift.String? {
326+ return try mapOptionalAtPath(path, alongPath: options, transform: Swift.String.init)
327+ }
328+
329+ /// Optionally retrieves a `Bool` from a path into JSON.
330+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
331+ /// - parameter alongPath: Options that control what should be done with values that are `null` or keys that are missing.
332+ /// - returns: A truthy `Bool` if a value could be found, otherwise `nil`.
333+ /// - throws: One of the following errors contained in `JSON.Error`:
334+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
335+ /// `JSON` dictionary.
336+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
337+ /// descendant `JSON` array.
338+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
339+ /// corresponding `JSON` value.
340+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
341+ /// instance does not match the decoded value.
342+ public func bool(path: JSONPathType..., alongPath options: SubscriptingOptions) throws -> Swift.Bool? {
343+ return try mapOptionalAtPath(path, alongPath: options, transform: Swift.Bool.init)
344+ }
345+
346+ /// Optionally retrieves a `[JSON]` from a path into the recieving structure.
347+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
348+ /// - parameter alongPath: Options that control what should be done with values that are `null` or keys that are missing.
349+ /// - returns: An `Array` of `JSON` elements if a value could be found,
350+ /// otherwise `nil`.
351+ /// - throws: One of the following errors contained in `JSON.Error`:
352+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
353+ /// `JSON` dictionary.
354+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
355+ /// descendant `JSON` array.
356+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
357+ /// corresponding `JSON` value.
358+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
359+ /// instance does not match the decoded value.
360+ public func array(path: JSONPathType..., alongPath options: SubscriptingOptions) throws -> [JSON]? {
361+ return try mapOptionalAtPath(path, alongPath: options, transform: JSON.getArray)
362+ }
363+
364+ /// Optionally decodes many values from a descendant array at a path into
365+ /// JSON.
366+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
367+ /// - parameter alongPath: Options that control what should be done with values that are `null` or keys that are missing.
368+ /// - returns: An `Array` of decoded elements if found, otherwise `nil`.
369+ /// - throws: One of the following errors contained in `JSON.Error`:
370+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
371+ /// `JSON` dictionary.
372+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
373+ /// descendant `JSON` array.
374+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
375+ /// corresponding `JSON` value.
376+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
377+ /// instance does not match the decoded value.
378+ /// * Any error that arises from decoding the value.
379+ public func arrayOf<Decoded: JSONDecodable>(path: JSONPathType..., alongPath options: SubscriptingOptions, type: Decoded.Type = Decoded.self) throws -> [Decoded]? {
380+ return try mapOptionalAtPath(path, alongPath: options, transform: JSON.getArrayOf)
381+ }
382+
383+ /// Optionally retrieves a `[String: JSON]` from a path into the recieving
384+ /// structure.
385+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
386+ /// - parameter alongPath: Options that control what should be done with values that are `null` or keys that are missing.
387+ /// - returns: A `Dictionary` of `String` mapping to `JSON` elements if a
388+ /// value could be found, otherwise `nil`.
389+ /// - throws: One of the following errors contained in `JSON.Error`:
390+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
391+ /// `JSON` dictionary.
392+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
393+ /// descendant `JSON` array.
394+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
395+ /// corresponding `JSON` value.
396+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
397+ /// instance does not match the decoded value.
398+ public func dictionary(path: JSONPathType..., alongPath options: SubscriptingOptions) throws -> [Swift.String: JSON]? {
399+ return try mapOptionalAtPath(path, alongPath: options, transform: JSON.getDictionary)
400+ }
401+
402+}
403+
404+// MARK: - Missing-with-fallback unpacking
405+
406+extension JSON {
407+
408+ private func mapOptionalAtPath<Value>(path: [JSONPathType], @noescape fallback: () -> Value, @noescape transform: JSON throws -> Value) throws -> Value {
409+ return try mapOptionalAtPath(path, alongPath: .MissingKeyBecomesNil, transform: transform) ?? fallback()
410+ }
411+
412+ /// Attempts to decode into the returning type from a path into
413+ /// JSON, or returns a fallback if not found.
414+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
415+ /// - parameter fallback: Value to use when one is missing at the subscript.
416+ /// - returns: An initialized member from the inner JSON.
417+ /// - throws: One of the following errors contained in `JSON.Error`:
418+ /// * `UnexpectedSubscript`: A given subscript cannot be used with the
419+ /// corresponding `JSON` value.
420+ /// * `TypeNotConvertible`: The target value's type inside of
421+ /// the `JSON` instance does not match `Decoded`.
422+ public func decode<Decoded: JSONDecodable>(path: JSONPathType..., @autoclosure or fallback: () -> Decoded) throws -> Decoded {
423+ return try mapOptionalAtPath(path, fallback: fallback, transform: Decoded.init)
424+ }
425+
426+ /// Retrieves a `Double` from a path into JSON or a fallback if not found.
427+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
428+ /// - parameter fallback: Array to use when one is missing at the subscript.
429+ /// - returns: A floating-point `Double`
430+ /// - throws: One of the `JSON.Error` cases thrown by calling `mapOptionalAtPath(_:fallback:transform:)`.
431+ /// - seealso: `optionalAtPath(_:ifNotFound)`.
432+ public func double(path: JSONPathType..., @autoclosure or fallback: () -> Swift.Double) throws -> Swift.Double {
433+ return try mapOptionalAtPath(path, fallback: fallback, transform: Swift.Double.init)
434+ }
435+
436+ /// Retrieves an `Int` from a path into JSON or a fallback if not found.
437+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
438+ /// - parameter fallback: Array to use when one is missing at the subscript.
439+ /// - returns: A numeric `Int`
440+ /// - throws: One of the following errors contained in `JSON.Error`:
441+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
442+ /// `JSON` dictionary.
443+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
444+ /// descendant `JSON` array.
445+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
446+ /// corresponding `JSON` value.
447+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
448+ /// instance does not match the decoded value.
449+ public func int(path: JSONPathType..., @autoclosure or fallback: () -> Swift.Int) throws -> Swift.Int {
450+ return try mapOptionalAtPath(path, fallback: fallback, transform: Swift.Int.init)
451+ }
452+
453+ /// Retrieves a `String` from a path into JSON or a fallback if not found.
454+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
455+ /// - parameter fallback: Array to use when one is missing at the subscript.
456+ /// - returns: A textual `String`
457+ /// - throws: One of the following errors contained in `JSON.Error`:
458+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
459+ /// `JSON` dictionary.
460+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
461+ /// descendant `JSON` array.
462+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
463+ /// corresponding `JSON` value.
464+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
465+ /// instance does not match the decoded value.
466+ public func string(path: JSONPathType..., @autoclosure or fallback: () -> Swift.String) throws -> Swift.String {
467+ return try mapOptionalAtPath(path, fallback: fallback, transform: Swift.String.init)
468+ }
469+
470+ /// Retrieves a `Bool` from a path into JSON or a fallback if not found.
471+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
472+ /// - parameter fallback: Array to use when one is missing at the subscript.
473+ /// - returns: A truthy `Bool`
474+ /// - throws: One of the following errors contained in `JSON.Error`:
475+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
476+ /// `JSON` dictionary.
477+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
478+ /// descendant `JSON` array.
479+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
480+ /// corresponding `JSON` value.
481+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
482+ /// instance does not match the decoded value.
483+ public func bool(path: JSONPathType..., @autoclosure or fallback: () -> Swift.Bool) throws -> Swift.Bool {
484+ return try mapOptionalAtPath(path, fallback: fallback, transform: Swift.Bool.init)
485+ }
486+
487+ /// Retrieves a `[JSON]` from a path into JSON or a fallback if not found.
488+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
489+ /// - parameter fallback: Array to use when one is missing at the subscript.
490+ /// - returns: An `Array` of `JSON` elements
491+ /// - throws: One of the following errors contained in `JSON.Error`:
492+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
493+ /// `JSON` dictionary.
494+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
495+ /// descendant `JSON` array.
496+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
497+ /// corresponding `JSON` value.
498+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
499+ /// instance does not match the decoded value.
500+ public func array(path: JSONPathType..., @autoclosure or fallback: () -> [JSON]) throws -> [JSON] {
501+ return try mapOptionalAtPath(path, fallback: fallback, transform: JSON.getArray)
502+ }
503+
504+ /// Attempts to decodes many values from a desendant JSON array at a path
505+ /// into the recieving structure, returning a fallback if not found.
506+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
507+ /// - parameter fallback: Array to use when one is missing at the subscript.
508+ /// - returns: An `Array` of decoded elements
509+ /// - throws: One of the following errors contained in `JSON.Error`:
510+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
511+ /// `JSON` dictionary.
512+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
513+ /// descendant `JSON` array.
514+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
515+ /// corresponding `JSON` value.
516+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
517+ /// instance does not match the decoded value.
518+ /// * Any error that arises from decoding the value.
519+ public func arrayOf<Decoded: JSONDecodable>(path: JSONPathType..., @autoclosure or fallback: () -> [Decoded]) throws -> [Decoded] {
520+ return try mapOptionalAtPath(path, fallback: fallback, transform: JSON.getArrayOf)
521+ }
522+
523+ /// Retrieves a `[String: JSON]` from a path into JSON or a fallback if not
524+ /// found.
525+ /// - parameter path: 0 or more `String` or `Int` that subscript the `JSON`
526+ /// - parameter fallback: Value to use when one is missing at the subscript
527+ /// - returns: An `Dictionary` of `String` mapping to `JSON` elements
528+ /// - throws: One of the following errors contained in `JSON.Error`:
529+ /// * `KeyNotFound`: A key `path` does not exist inside a descendant
530+ /// `JSON` dictionary.
531+ /// * `IndexOutOfBounds`: An index `path` is outside the bounds of a
532+ /// descendant `JSON` array.
533+ /// * `UnexpectedSubscript`: A `path` item cannot be used with the
534+ /// corresponding `JSON` value.
535+ /// * `TypeNotConvertible`: The target value's type inside of the `JSON`
536+ /// instance does not match the decoded value.
537+ public func dictionary(path: JSONPathType..., @autoclosure or fallback: () -> [Swift.String: JSON]) throws -> [Swift.String: JSON] {
538+ return try mapOptionalAtPath(path, fallback: fallback, transform: JSON.getDictionary)
539+ }
540+
541+}
542+
543+// MARK: - Deprecated methods
544+
545+extension JSON {
546+
547+ @available(*, deprecated, message="Use 'decode(_:alongPath:type:)' with options '[.MissingKeyBecomesNil]'")
548+ public func decode<Decoded: JSONDecodable>(path: JSONPathType..., ifNotFound: Swift.Bool, type: Decoded.Type = Decoded.self) throws -> Decoded? {
549+ let options: SubscriptingOptions = ifNotFound ? [.MissingKeyBecomesNil] : []
550+ return try mapOptionalAtPath(path, alongPath: options, transform: Decoded.init)
551+ }
552+
553+ @available(*, deprecated, message="Use 'decode(_:alongPath:type:)' with options '[.NullBecomesNil]'")
554+ public func decode<Decoded: JSONDecodable>(path: JSONPathType..., ifNull: Swift.Bool, type: Decoded.Type = Decoded.self) throws -> Decoded? {
555+ let options: SubscriptingOptions = ifNull ? [.NullBecomesNil] : []
556+ return try mapOptionalAtPath(path, alongPath: options, transform: Decoded.init)
557+ }
558+
559+ @available(*, deprecated, message="Use 'double(_:alongPath:)' with options '[.MissingKeyBecomesNil]'")
560+ public func double(path: JSONPathType..., ifNotFound: Swift.Bool) throws -> Swift.Double? {
561+ let options: SubscriptingOptions = ifNotFound ? [.MissingKeyBecomesNil] : []
562+ return try mapOptionalAtPath(path, alongPath: options, transform: Swift.Double.init)
563+ }
564+
565+ @available(*, deprecated, message="Use 'double(_:alongPath:)' with options '[.NullBecomesNil]'")
566+ public func double(path: JSONPathType..., ifNull: Swift.Bool) throws -> Swift.Double? {
567+ let options: SubscriptingOptions = ifNull ? [.NullBecomesNil] : []
568+ return try mapOptionalAtPath(path, alongPath: options, transform: Swift.Double.init)
569+ }
570+
571+ @available(*, deprecated, message="Use 'int(_:alongPath:)' with options '[.MissingKeyBecomesNil]'")
572+ public func int(path: JSONPathType..., ifNotFound: Swift.Bool) throws -> Swift.Int? {
573+ let options: SubscriptingOptions = ifNotFound ? [.MissingKeyBecomesNil] : []
574+ return try mapOptionalAtPath(path, alongPath: options, transform: Swift.Int.init)
575+ }
576+
577+ @available(*, deprecated, message="Use 'int(_:alongPath:)' with options '[.NullBecomesNil]'")
578+ public func int(path: JSONPathType..., ifNull: Swift.Bool) throws -> Swift.Int? {
579+ let options: SubscriptingOptions = ifNull ? [.NullBecomesNil] : []
580+ return try mapOptionalAtPath(path, alongPath: options, transform: Swift.Int.init)
581+ }
582+
583+ @available(*, deprecated, message="Use 'string(_:alongPath:)' with options '[.MissingKeyBecomesNil]'")
584+ public func string(path: JSONPathType..., ifNotFound: Swift.Bool) throws -> Swift.String? {
585+ let options: SubscriptingOptions = ifNotFound ? [.MissingKeyBecomesNil] : []
586+ return try mapOptionalAtPath(path, alongPath: options, transform: Swift.String.init)
587+ }
588+
589+ @available(*, deprecated, message="Use 'string(_:alongPath:)' with options '[.NullBecomesNil]'")
590+ public func string(path: JSONPathType..., ifNull: Swift.Bool) throws -> Swift.String? {
591+ let options: SubscriptingOptions = ifNull ? [.NullBecomesNil] : []
592+ return try mapOptionalAtPath(path, alongPath: options, transform: Swift.String.init)
593+ }
594+
595+ @available(*, deprecated, message="Use 'bool(_:alongPath:)' with options '[.MissingKeyBecomesNil]'")
596+ public func bool(path: JSONPathType..., ifNotFound: Swift.Bool) throws -> Swift.Bool? {
597+ let options: SubscriptingOptions = ifNotFound ? [.MissingKeyBecomesNil] : []
598+ return try mapOptionalAtPath(path, alongPath: options, transform: Swift.Bool.init)
599+ }
600+
601+ @available(*, deprecated, message="Use 'bool(_:alongPath:)' with options '[.NullBecomesNil]'")
602+ public func bool(path: JSONPathType..., ifNull: Swift.Bool) throws -> Swift.Bool? {
603+ let options: SubscriptingOptions = ifNull ? [.NullBecomesNil] : []
604+ return try mapOptionalAtPath(path, alongPath: options, transform: Swift.Bool.init)
605+ }
606+
607+ @available(*, deprecated, message="Use 'array(_:alongPath:)' with options '[.MissingKeyBecomesNil]'")
608+ public func array(path: JSONPathType..., ifNotFound: Swift.Bool) throws -> [JSON]? {
609+ let options: SubscriptingOptions = ifNotFound ? [.MissingKeyBecomesNil] : []
610+ return try mapOptionalAtPath(path, alongPath: options, transform: JSON.getArray)
611+ }
612+
613+ @available(*, deprecated, message="Use 'array(_:alongPath:)' with options '[.NullBecomesNil]'")
614+ public func array(path: JSONPathType..., ifNull: Swift.Bool) throws -> [JSON]? {
615+ let options: SubscriptingOptions = ifNull ? [.NullBecomesNil] : []
616+ return try mapOptionalAtPath(path, alongPath: options, transform: JSON.getArray)
617+ }
618+
619+ @available(*, deprecated, message="Use 'arrayOf(_:alongPath:)' with options '[.MissingKeyBecomesNil]'")
620+ public func arrayOf<Decoded: JSONDecodable>(path: JSONPathType..., ifNotFound: Swift.Bool) throws -> [Decoded]? {
621+ let options: SubscriptingOptions = ifNotFound ? [.MissingKeyBecomesNil] : []
622+ return try mapOptionalAtPath(path, alongPath: options, transform: JSON.getArrayOf)
623+ }
624+
625+ @available(*, deprecated, message="Use 'arrayOf(_:alongPath:)' with options '[.NullBecomesNil]'")
626+ public func arrayOf<Decoded: JSONDecodable>(path: JSONPathType..., ifNull: Swift.Bool) throws -> [Decoded]? {
627+ let options: SubscriptingOptions = ifNull ? [.NullBecomesNil] : []
628+ return try mapOptionalAtPath(path, alongPath: options, transform: JSON.getArrayOf)
629+ }
630+
631+ @available(*, deprecated, message="Use 'dictionary(_:alongPath:)' with options '[.MissingKeyBecomesNil]'")
632+ public func dictionary(path: JSONPathType..., ifNotFound: Swift.Bool) throws -> [Swift.String: JSON]? {
633+ let options: SubscriptingOptions = ifNotFound ? [.MissingKeyBecomesNil] : []
634+ return try mapOptionalAtPath(path, alongPath: options, transform: JSON.getDictionary)
635+ }
636+
637+ @available(*, deprecated, message="Use 'dictionary(_:alongPath:)' with options '[.NullBecomesNil]'")
638+ public func dictionary(path: JSONPathType..., ifNull: Swift.Bool) throws -> [Swift.String: JSON]? {
639+ let options: SubscriptingOptions = ifNull ? [.NullBecomesNil] : []
640+ return try mapOptionalAtPath(path, alongPath: options, transform: JSON.getDictionary)
641+ }
642+
643+}
parsers/test_Freddy_2_1_0/test_Freddy/main.swiftnew file+37
@@ -0,0 +1,37 @@
1+//
2+// main.swift
3+// test_Freddy
4+//
5+// Created by nst on 10/08/16.
6+// Copyright © 2016 Nicolas Seriot. All rights reserved.
7+//
8+
9+import Foundation
10+
11+func main() {
12+
13+ guard Process.arguments.count == 2 else {
14+ let url = NSURL(fileURLWithPath: Process.arguments[0])
15+ guard let programName = url.lastPathComponent else { exit(1) }
16+ print("Usage: ./\(programName) file.json")
17+ exit(1)
18+ }
19+
20+ let path = Process.arguments[1]
21+ let url = NSURL.fileURLWithPath(path)
22+
23+ guard let data = NSData(contentsOfURL:url) else {
24+ print("*** CANNOT READ DATA AT \(url)")
25+ return
26+ }
27+
28+ var p = JSONParser(utf8Data: data)
29+ do {
30+ try p.parse()
31+ exit(0)
32+ } catch {
33+ exit(1)
34+ }
35+}
36+
37+main()
parsers/test_JSONKit/JSONKit.hnew file+251
@@ -0,0 +1,251 @@
1+//
2+// JSONKit.h
3+// http://github.com/johnezang/JSONKit
4+// Dual licensed under either the terms of the BSD License, or alternatively
5+// under the terms of the Apache License, Version 2.0, as specified below.
6+//
7+
8+/*
9+ Copyright (c) 2011, John Engelhart
10+
11+ All rights reserved.
12+
13+ Redistribution and use in source and binary forms, with or without
14+ modification, are permitted provided that the following conditions are met:
15+
16+ * Redistributions of source code must retain the above copyright
17+ notice, this list of conditions and the following disclaimer.
18+
19+ * Redistributions in binary form must reproduce the above copyright
20+ notice, this list of conditions and the following disclaimer in the
21+ documentation and/or other materials provided with the distribution.
22+
23+ * Neither the name of the Zang Industries nor the names of its
24+ contributors may be used to endorse or promote products derived from
25+ this software without specific prior written permission.
26+
27+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
33+ TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
34+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
35+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
36+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
37+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38+*/
39+
40+/*
41+ Copyright 2011 John Engelhart
42+
43+ Licensed under the Apache License, Version 2.0 (the "License");
44+ you may not use this file except in compliance with the License.
45+ You may obtain a copy of the License at
46+
47+ http://www.apache.org/licenses/LICENSE-2.0
48+
49+ Unless required by applicable law or agreed to in writing, software
50+ distributed under the License is distributed on an "AS IS" BASIS,
51+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
52+ See the License for the specific language governing permissions and
53+ limitations under the License.
54+*/
55+
56+#include <stddef.h>
57+#include <stdint.h>
58+#include <limits.h>
59+#include <TargetConditionals.h>
60+#include <AvailabilityMacros.h>
61+
62+#ifdef __OBJC__
63+#import <Foundation/NSArray.h>
64+#import <Foundation/NSData.h>
65+#import <Foundation/NSDictionary.h>
66+#import <Foundation/NSError.h>
67+#import <Foundation/NSObjCRuntime.h>
68+#import <Foundation/NSString.h>
69+#endif // __OBJC__
70+
71+#ifdef __cplusplus
72+extern "C" {
73+#endif
74+
75+
76+// For Mac OS X < 10.5.
77+#ifndef NSINTEGER_DEFINED
78+#define NSINTEGER_DEFINED
79+#if defined(__LP64__) || defined(NS_BUILD_32_LIKE_64)
80+typedef long NSInteger;
81+typedef unsigned long NSUInteger;
82+#define NSIntegerMin LONG_MIN
83+#define NSIntegerMax LONG_MAX
84+#define NSUIntegerMax ULONG_MAX
85+#else // defined(__LP64__) || defined(NS_BUILD_32_LIKE_64)
86+typedef int NSInteger;
87+typedef unsigned int NSUInteger;
88+#define NSIntegerMin INT_MIN
89+#define NSIntegerMax INT_MAX
90+#define NSUIntegerMax UINT_MAX
91+#endif // defined(__LP64__) || defined(NS_BUILD_32_LIKE_64)
92+#endif // NSINTEGER_DEFINED
93+
94+
95+#ifndef _JSONKIT_H_
96+#define _JSONKIT_H_
97+
98+#if defined(__GNUC__) && (__GNUC__ >= 4) && defined(__APPLE_CC__) && (__APPLE_CC__ >= 5465)
99+#define JK_DEPRECATED_ATTRIBUTE __attribute__((deprecated))
100+#else
101+#define JK_DEPRECATED_ATTRIBUTE
102+#endif
103+
104+#define JSONKIT_VERSION_MAJOR 1
105+#define JSONKIT_VERSION_MINOR 4
106+
107+typedef NSUInteger JKFlags;
108+
109+/*
110+ JKParseOptionComments : Allow C style // and /_* ... *_/ (without a _, obviously) comments in JSON.
111+ JKParseOptionUnicodeNewlines : Allow Unicode recommended (?:\r\n|[\n\v\f\r\x85\p{Zl}\p{Zp}]) newlines.
112+ JKParseOptionLooseUnicode : Normally the decoder will stop with an error at any malformed Unicode.
113+ This option allows JSON with malformed Unicode to be parsed without reporting an error.
114+ Any malformed Unicode is replaced with \uFFFD, or "REPLACEMENT CHARACTER".
115+ */
116+
117+enum {
118+ JKParseOptionNone = 0,
119+ JKParseOptionStrict = 0,
120+ JKParseOptionComments = (1 << 0),
121+ JKParseOptionUnicodeNewlines = (1 << 1),
122+ JKParseOptionLooseUnicode = (1 << 2),
123+ JKParseOptionPermitTextAfterValidJSON = (1 << 3),
124+ JKParseOptionValidFlags = (JKParseOptionComments | JKParseOptionUnicodeNewlines | JKParseOptionLooseUnicode | JKParseOptionPermitTextAfterValidJSON),
125+};
126+typedef JKFlags JKParseOptionFlags;
127+
128+enum {
129+ JKSerializeOptionNone = 0,
130+ JKSerializeOptionPretty = (1 << 0),
131+ JKSerializeOptionEscapeUnicode = (1 << 1),
132+ JKSerializeOptionEscapeForwardSlashes = (1 << 4),
133+ JKSerializeOptionValidFlags = (JKSerializeOptionPretty | JKSerializeOptionEscapeUnicode | JKSerializeOptionEscapeForwardSlashes),
134+};
135+typedef JKFlags JKSerializeOptionFlags;
136+
137+#ifdef __OBJC__
138+
139+typedef struct JKParseState JKParseState; // Opaque internal, private type.
140+
141+// As a general rule of thumb, if you use a method that doesn't accept a JKParseOptionFlags argument, it defaults to JKParseOptionStrict
142+
143+@interface JSONDecoder : NSObject {
144+ JKParseState *parseState;
145+}
146++ (id)decoder;
147++ (id)decoderWithParseOptions:(JKParseOptionFlags)parseOptionFlags;
148+- (id)initWithParseOptions:(JKParseOptionFlags)parseOptionFlags;
149+- (void)clearCache;
150+
151+// The parse... methods were deprecated in v1.4 in favor of the v1.4 objectWith... methods.
152+- (id)parseUTF8String:(const unsigned char *)string length:(size_t)length JK_DEPRECATED_ATTRIBUTE; // Deprecated in JSONKit v1.4. Use objectWithUTF8String:length: instead.
153+- (id)parseUTF8String:(const unsigned char *)string length:(size_t)length error:(NSError **)error JK_DEPRECATED_ATTRIBUTE; // Deprecated in JSONKit v1.4. Use objectWithUTF8String:length:error: instead.
154+// The NSData MUST be UTF8 encoded JSON.
155+- (id)parseJSONData:(NSData *)jsonData JK_DEPRECATED_ATTRIBUTE; // Deprecated in JSONKit v1.4. Use objectWithData: instead.
156+- (id)parseJSONData:(NSData *)jsonData error:(NSError **)error JK_DEPRECATED_ATTRIBUTE; // Deprecated in JSONKit v1.4. Use objectWithData:error: instead.
157+
158+// Methods that return immutable collection objects.
159+- (id)objectWithUTF8String:(const unsigned char *)string length:(NSUInteger)length;
160+- (id)objectWithUTF8String:(const unsigned char *)string length:(NSUInteger)length error:(NSError **)error;
161+// The NSData MUST be UTF8 encoded JSON.
162+- (id)objectWithData:(NSData *)jsonData;
163+- (id)objectWithData:(NSData *)jsonData error:(NSError **)error;
164+
165+// Methods that return mutable collection objects.
166+- (id)mutableObjectWithUTF8String:(const unsigned char *)string length:(NSUInteger)length;
167+- (id)mutableObjectWithUTF8String:(const unsigned char *)string length:(NSUInteger)length error:(NSError **)error;
168+// The NSData MUST be UTF8 encoded JSON.
169+- (id)mutableObjectWithData:(NSData *)jsonData;
170+- (id)mutableObjectWithData:(NSData *)jsonData error:(NSError **)error;
171+
172+@end
173+
174+////////////
175+#pragma mark Deserializing methods
176+////////////
177+
178+@interface NSString (JSONKitDeserializing)
179+- (id)objectFromJSONString;
180+- (id)objectFromJSONStringWithParseOptions:(JKParseOptionFlags)parseOptionFlags;
181+- (id)objectFromJSONStringWithParseOptions:(JKParseOptionFlags)parseOptionFlags error:(NSError **)error;
182+- (id)mutableObjectFromJSONString;
183+- (id)mutableObjectFromJSONStringWithParseOptions:(JKParseOptionFlags)parseOptionFlags;
184+- (id)mutableObjectFromJSONStringWithParseOptions:(JKParseOptionFlags)parseOptionFlags error:(NSError **)error;
185+@end
186+
187+@interface NSData (JSONKitDeserializing)
188+// The NSData MUST be UTF8 encoded JSON.
189+- (id)objectFromJSONData;
190+- (id)objectFromJSONDataWithParseOptions:(JKParseOptionFlags)parseOptionFlags;
191+- (id)objectFromJSONDataWithParseOptions:(JKParseOptionFlags)parseOptionFlags error:(NSError **)error;
192+- (id)mutableObjectFromJSONData;
193+- (id)mutableObjectFromJSONDataWithParseOptions:(JKParseOptionFlags)parseOptionFlags;
194+- (id)mutableObjectFromJSONDataWithParseOptions:(JKParseOptionFlags)parseOptionFlags error:(NSError **)error;
195+@end
196+
197+////////////
198+#pragma mark Serializing methods
199+////////////
200+
201+@interface NSString (JSONKitSerializing)
202+// Convenience methods for those that need to serialize the receiving NSString (i.e., instead of having to serialize a NSArray with a single NSString, you can "serialize to JSON" just the NSString).
203+// Normally, a string that is serialized to JSON has quotation marks surrounding it, which you may or may not want when serializing a single string, and can be controlled with includeQuotes:
204+// includeQuotes:YES `a "test"...` -> `"a \"test\"..."`
205+// includeQuotes:NO `a "test"...` -> `a \"test\"...`
206+- (NSData *)JSONData; // Invokes JSONDataWithOptions:JKSerializeOptionNone includeQuotes:YES
207+- (NSData *)JSONDataWithOptions:(JKSerializeOptionFlags)serializeOptions includeQuotes:(BOOL)includeQuotes error:(NSError **)error;
208+- (NSString *)JSONString; // Invokes JSONStringWithOptions:JKSerializeOptionNone includeQuotes:YES
209+- (NSString *)JSONStringWithOptions:(JKSerializeOptionFlags)serializeOptions includeQuotes:(BOOL)includeQuotes error:(NSError **)error;
210+@end
211+
212+@interface NSArray (JSONKitSerializing)
213+- (NSData *)JSONData;
214+- (NSData *)JSONDataWithOptions:(JKSerializeOptionFlags)serializeOptions error:(NSError **)error;
215+- (NSData *)JSONDataWithOptions:(JKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingDelegate:(id)delegate selector:(SEL)selector error:(NSError **)error;
216+- (NSString *)JSONString;
217+- (NSString *)JSONStringWithOptions:(JKSerializeOptionFlags)serializeOptions error:(NSError **)error;
218+- (NSString *)JSONStringWithOptions:(JKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingDelegate:(id)delegate selector:(SEL)selector error:(NSError **)error;
219+@end
220+
221+@interface NSDictionary (JSONKitSerializing)
222+- (NSData *)JSONData;
223+- (NSData *)JSONDataWithOptions:(JKSerializeOptionFlags)serializeOptions error:(NSError **)error;
224+- (NSData *)JSONDataWithOptions:(JKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingDelegate:(id)delegate selector:(SEL)selector error:(NSError **)error;
225+- (NSString *)JSONString;
226+- (NSString *)JSONStringWithOptions:(JKSerializeOptionFlags)serializeOptions error:(NSError **)error;
227+- (NSString *)JSONStringWithOptions:(JKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingDelegate:(id)delegate selector:(SEL)selector error:(NSError **)error;
228+@end
229+
230+#ifdef __BLOCKS__
231+
232+@interface NSArray (JSONKitSerializingBlockAdditions)
233+- (NSData *)JSONDataWithOptions:(JKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingBlock:(id(^)(id object))block error:(NSError **)error;
234+- (NSString *)JSONStringWithOptions:(JKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingBlock:(id(^)(id object))block error:(NSError **)error;
235+@end
236+
237+@interface NSDictionary (JSONKitSerializingBlockAdditions)
238+- (NSData *)JSONDataWithOptions:(JKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingBlock:(id(^)(id object))block error:(NSError **)error;
239+- (NSString *)JSONStringWithOptions:(JKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingBlock:(id(^)(id object))block error:(NSError **)error;
240+@end
241+
242+#endif
243+
244+
245+#endif // __OBJC__
246+
247+#endif // _JSONKIT_H_
248+
249+#ifdef __cplusplus
250+} // extern "C"
251+#endif
parsers/test_JSONKit/JSONKit.mnew file+3065
@@ -0,0 +1,3065 @@
1+//
2+// JSONKit.m
3+// http://github.com/johnezang/JSONKit
4+// Dual licensed under either the terms of the BSD License, or alternatively
5+// under the terms of the Apache License, Version 2.0, as specified below.
6+//
7+
8+/*
9+ Copyright (c) 2011, John Engelhart
10+
11+ All rights reserved.
12+
13+ Redistribution and use in source and binary forms, with or without
14+ modification, are permitted provided that the following conditions are met:
15+
16+ * Redistributions of source code must retain the above copyright
17+ notice, this list of conditions and the following disclaimer.
18+
19+ * Redistributions in binary form must reproduce the above copyright
20+ notice, this list of conditions and the following disclaimer in the
21+ documentation and/or other materials provided with the distribution.
22+
23+ * Neither the name of the Zang Industries nor the names of its
24+ contributors may be used to endorse or promote products derived from
25+ this software without specific prior written permission.
26+
27+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
33+ TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
34+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
35+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
36+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
37+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38+*/
39+
40+/*
41+ Copyright 2011 John Engelhart
42+
43+ Licensed under the Apache License, Version 2.0 (the "License");
44+ you may not use this file except in compliance with the License.
45+ You may obtain a copy of the License at
46+
47+ http://www.apache.org/licenses/LICENSE-2.0
48+
49+ Unless required by applicable law or agreed to in writing, software
50+ distributed under the License is distributed on an "AS IS" BASIS,
51+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
52+ See the License for the specific language governing permissions and
53+ limitations under the License.
54+*/
55+
56+
57+/*
58+ Acknowledgments:
59+
60+ The bulk of the UTF8 / UTF32 conversion and verification comes
61+ from ConvertUTF.[hc]. It has been modified from the original sources.
62+
63+ The original sources were obtained from http://www.unicode.org/.
64+ However, the web site no longer seems to host the files. Instead,
65+ the Unicode FAQ http://www.unicode.org/faq//utf_bom.html#gen4
66+ points to International Components for Unicode (ICU)
67+ http://site.icu-project.org/ as an example of how to write a UTF
68+ converter.
69+
70+ The decision to use the ConvertUTF.[ch] code was made to leverage
71+ "proven" code. Hopefully the local modifications are bug free.
72+
73+ The code in isValidCodePoint() is derived from the ICU code in
74+ utf.h for the macros U_IS_UNICODE_NONCHAR and U_IS_UNICODE_CHAR.
75+
76+ From the original ConvertUTF.[ch]:
77+
78+ * Copyright 2001-2004 Unicode, Inc.
79+ *
80+ * Disclaimer
81+ *
82+ * This source code is provided as is by Unicode, Inc. No claims are
83+ * made as to fitness for any particular purpose. No warranties of any
84+ * kind are expressed or implied. The recipient agrees to determine
85+ * applicability of information provided. If this file has been
86+ * purchased on magnetic or optical media from Unicode, Inc., the
87+ * sole remedy for any claim will be exchange of defective media
88+ * within 90 days of receipt.
89+ *
90+ * Limitations on Rights to Redistribute This Code
91+ *
92+ * Unicode, Inc. hereby grants the right to freely use the information
93+ * supplied in this file in the creation of products supporting the
94+ * Unicode Standard, and to make copies of this file in any form
95+ * for internal or external distribution as long as this notice
96+ * remains attached.
97+
98+*/
99+
100+#include <stdio.h>
101+#include <stdlib.h>
102+#include <stdint.h>
103+#include <string.h>
104+#include <assert.h>
105+#include <sys/errno.h>
106+#include <math.h>
107+#include <limits.h>
108+#include <objc/runtime.h>
109+
110+#import "JSONKit.h"
111+
112+//#include <CoreFoundation/CoreFoundation.h>
113+#include <CoreFoundation/CFString.h>
114+#include <CoreFoundation/CFArray.h>
115+#include <CoreFoundation/CFDictionary.h>
116+#include <CoreFoundation/CFNumber.h>
117+
118+//#import <Foundation/Foundation.h>
119+#import <Foundation/NSArray.h>
120+#import <Foundation/NSAutoreleasePool.h>
121+#import <Foundation/NSData.h>
122+#import <Foundation/NSDictionary.h>
123+#import <Foundation/NSException.h>
124+#import <Foundation/NSNull.h>
125+#import <Foundation/NSObjCRuntime.h>
126+
127+#ifndef __has_feature
128+#define __has_feature(x) 0
129+#endif
130+
131+#ifdef JK_ENABLE_CF_TRANSFER_OWNERSHIP_CALLBACKS
132+#warning As of JSONKit v1.4, JK_ENABLE_CF_TRANSFER_OWNERSHIP_CALLBACKS is no longer required. It is no longer a valid option.
133+#endif
134+
135+#ifdef __OBJC_GC__
136+#error JSONKit does not support Objective-C Garbage Collection
137+#endif
138+
139+#if __has_feature(objc_arc)
140+#error JSONKit does not support Objective-C Automatic Reference Counting (ARC)
141+#endif
142+
143+// The following checks are really nothing more than sanity checks.
144+// JSONKit technically has a few problems from a "strictly C99 conforming" standpoint, though they are of the pedantic nitpicking variety.
145+// In practice, though, for the compilers and architectures we can reasonably expect this code to be compiled for, these pedantic nitpicks aren't really a problem.
146+// Since we're limited as to what we can do with pre-processor #if checks, these checks are not nearly as through as they should be.
147+
148+#if (UINT_MAX != 0xffffffffU) || (INT_MIN != (-0x7fffffff-1)) || (ULLONG_MAX != 0xffffffffffffffffULL) || (LLONG_MIN != (-0x7fffffffffffffffLL-1LL))
149+#error JSONKit requires the C 'int' and 'long long' types to be 32 and 64 bits respectively.
150+#endif
151+
152+#if !defined(__LP64__) && ((UINT_MAX != ULONG_MAX) || (INT_MAX != LONG_MAX) || (INT_MIN != LONG_MIN) || (WORD_BIT != LONG_BIT))
153+#error JSONKit requires the C 'int' and 'long' types to be the same on 32-bit architectures.
154+#endif
155+
156+// Cocoa / Foundation uses NS*Integer as the type for a lot of arguments. We make sure that NS*Integer is something we are expecting and is reasonably compatible with size_t / ssize_t
157+
158+#if (NSUIntegerMax != ULONG_MAX) || (NSIntegerMax != LONG_MAX) || (NSIntegerMin != LONG_MIN)
159+#error JSONKit requires NSInteger and NSUInteger to be the same size as the C 'long' type.
160+#endif
161+
162+#if (NSUIntegerMax != SIZE_MAX) || (NSIntegerMax != SSIZE_MAX)
163+#error JSONKit requires NSInteger and NSUInteger to be the same size as the C 'size_t' type.
164+#endif
165+
166+
167+// For DJB hash.
168+#define JK_HASH_INIT (1402737925UL)
169+
170+// Use __builtin_clz() instead of trailingBytesForUTF8[] table lookup.
171+#define JK_FAST_TRAILING_BYTES
172+
173+// JK_CACHE_SLOTS must be a power of 2. Default size is 1024 slots.
174+#define JK_CACHE_SLOTS_BITS (10)
175+#define JK_CACHE_SLOTS (1UL << JK_CACHE_SLOTS_BITS)
176+// JK_CACHE_PROBES is the number of probe attempts.
177+#define JK_CACHE_PROBES (4UL)
178+// JK_INIT_CACHE_AGE must be < (1 << AGE) - 1, where AGE is sizeof(typeof(AGE)) * 8.
179+#define JK_INIT_CACHE_AGE (0)
180+
181+// JK_TOKENBUFFER_SIZE is the default stack size for the temporary buffer used to hold "non-simple" strings (i.e., contains \ escapes)
182+#define JK_TOKENBUFFER_SIZE (1024UL * 2UL)
183+
184+// JK_STACK_OBJS is the default number of spaces reserved on the stack for temporarily storing pointers to Obj-C objects before they can be transferred to a NSArray / NSDictionary.
185+#define JK_STACK_OBJS (1024UL * 1UL)
186+
187+#define JK_JSONBUFFER_SIZE (1024UL * 4UL)
188+#define JK_UTF8BUFFER_SIZE (1024UL * 16UL)
189+
190+#define JK_ENCODE_CACHE_SLOTS (1024UL)
191+
192+
193+#if defined (__GNUC__) && (__GNUC__ >= 4)
194+#define JK_ATTRIBUTES(attr, ...) __attribute__((attr, ##__VA_ARGS__))
195+#define JK_EXPECTED(cond, expect) __builtin_expect((long)(cond), (expect))
196+#define JK_EXPECT_T(cond) JK_EXPECTED(cond, 1U)
197+#define JK_EXPECT_F(cond) JK_EXPECTED(cond, 0U)
198+#define JK_PREFETCH(ptr) __builtin_prefetch(ptr)
199+#else // defined (__GNUC__) && (__GNUC__ >= 4)
200+#define JK_ATTRIBUTES(attr, ...)
201+#define JK_EXPECTED(cond, expect) (cond)
202+#define JK_EXPECT_T(cond) (cond)
203+#define JK_EXPECT_F(cond) (cond)
204+#define JK_PREFETCH(ptr)
205+#endif // defined (__GNUC__) && (__GNUC__ >= 4)
206+
207+#define JK_STATIC_INLINE static __inline__ JK_ATTRIBUTES(always_inline)
208+#define JK_ALIGNED(arg) JK_ATTRIBUTES(aligned(arg))
209+#define JK_UNUSED_ARG JK_ATTRIBUTES(unused)
210+#define JK_WARN_UNUSED JK_ATTRIBUTES(warn_unused_result)
211+#define JK_WARN_UNUSED_CONST JK_ATTRIBUTES(warn_unused_result, const)
212+#define JK_WARN_UNUSED_PURE JK_ATTRIBUTES(warn_unused_result, pure)
213+#define JK_WARN_UNUSED_SENTINEL JK_ATTRIBUTES(warn_unused_result, sentinel)
214+#define JK_NONNULL_ARGS(arg, ...) JK_ATTRIBUTES(nonnull(arg, ##__VA_ARGS__))
215+#define JK_WARN_UNUSED_NONNULL_ARGS(arg, ...) JK_ATTRIBUTES(warn_unused_result, nonnull(arg, ##__VA_ARGS__))
216+#define JK_WARN_UNUSED_CONST_NONNULL_ARGS(arg, ...) JK_ATTRIBUTES(warn_unused_result, const, nonnull(arg, ##__VA_ARGS__))
217+#define JK_WARN_UNUSED_PURE_NONNULL_ARGS(arg, ...) JK_ATTRIBUTES(warn_unused_result, pure, nonnull(arg, ##__VA_ARGS__))
218+
219+#if defined (__GNUC__) && (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 3)
220+#define JK_ALLOC_SIZE_NON_NULL_ARGS_WARN_UNUSED(as, nn, ...) JK_ATTRIBUTES(warn_unused_result, nonnull(nn, ##__VA_ARGS__), alloc_size(as))
221+#else // defined (__GNUC__) && (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 3)
222+#define JK_ALLOC_SIZE_NON_NULL_ARGS_WARN_UNUSED(as, nn, ...) JK_ATTRIBUTES(warn_unused_result, nonnull(nn, ##__VA_ARGS__))
223+#endif // defined (__GNUC__) && (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 3)
224+
225+
226+@class JKArray, JKDictionaryEnumerator, JKDictionary;
227+
228+enum {
229+ JSONNumberStateStart = 0,
230+ JSONNumberStateFinished = 1,
231+ JSONNumberStateError = 2,
232+ JSONNumberStateWholeNumberStart = 3,
233+ JSONNumberStateWholeNumberMinus = 4,
234+ JSONNumberStateWholeNumberZero = 5,
235+ JSONNumberStateWholeNumber = 6,
236+ JSONNumberStatePeriod = 7,
237+ JSONNumberStateFractionalNumberStart = 8,
238+ JSONNumberStateFractionalNumber = 9,
239+ JSONNumberStateExponentStart = 10,
240+ JSONNumberStateExponentPlusMinus = 11,
241+ JSONNumberStateExponent = 12,
242+};
243+
244+enum {
245+ JSONStringStateStart = 0,
246+ JSONStringStateParsing = 1,
247+ JSONStringStateFinished = 2,
248+ JSONStringStateError = 3,
249+ JSONStringStateEscape = 4,
250+ JSONStringStateEscapedUnicode1 = 5,
251+ JSONStringStateEscapedUnicode2 = 6,
252+ JSONStringStateEscapedUnicode3 = 7,
253+ JSONStringStateEscapedUnicode4 = 8,
254+ JSONStringStateEscapedUnicodeSurrogate1 = 9,
255+ JSONStringStateEscapedUnicodeSurrogate2 = 10,
256+ JSONStringStateEscapedUnicodeSurrogate3 = 11,
257+ JSONStringStateEscapedUnicodeSurrogate4 = 12,
258+ JSONStringStateEscapedNeedEscapeForSurrogate = 13,
259+ JSONStringStateEscapedNeedEscapedUForSurrogate = 14,
260+};
261+
262+enum {
263+ JKParseAcceptValue = (1 << 0),
264+ JKParseAcceptComma = (1 << 1),
265+ JKParseAcceptEnd = (1 << 2),
266+ JKParseAcceptValueOrEnd = (JKParseAcceptValue | JKParseAcceptEnd),
267+ JKParseAcceptCommaOrEnd = (JKParseAcceptComma | JKParseAcceptEnd),
268+};
269+
270+enum {
271+ JKClassUnknown = 0,
272+ JKClassString = 1,
273+ JKClassNumber = 2,
274+ JKClassArray = 3,
275+ JKClassDictionary = 4,
276+ JKClassNull = 5,
277+};
278+
279+enum {
280+ JKManagedBufferOnStack = 1,
281+ JKManagedBufferOnHeap = 2,
282+ JKManagedBufferLocationMask = (0x3),
283+ JKManagedBufferLocationShift = (0),
284+
285+ JKManagedBufferMustFree = (1 << 2),
286+};
287+typedef JKFlags JKManagedBufferFlags;
288+
289+enum {
290+ JKObjectStackOnStack = 1,
291+ JKObjectStackOnHeap = 2,
292+ JKObjectStackLocationMask = (0x3),
293+ JKObjectStackLocationShift = (0),
294+
295+ JKObjectStackMustFree = (1 << 2),
296+};
297+typedef JKFlags JKObjectStackFlags;
298+
299+enum {
300+ JKTokenTypeInvalid = 0,
301+ JKTokenTypeNumber = 1,
302+ JKTokenTypeString = 2,
303+ JKTokenTypeObjectBegin = 3,
304+ JKTokenTypeObjectEnd = 4,
305+ JKTokenTypeArrayBegin = 5,
306+ JKTokenTypeArrayEnd = 6,
307+ JKTokenTypeSeparator = 7,
308+ JKTokenTypeComma = 8,
309+ JKTokenTypeTrue = 9,
310+ JKTokenTypeFalse = 10,
311+ JKTokenTypeNull = 11,
312+ JKTokenTypeWhiteSpace = 12,
313+};
314+typedef NSUInteger JKTokenType;
315+
316+// These are prime numbers to assist with hash slot probing.
317+enum {
318+ JKValueTypeNone = 0,
319+ JKValueTypeString = 5,
320+ JKValueTypeLongLong = 7,
321+ JKValueTypeUnsignedLongLong = 11,
322+ JKValueTypeDouble = 13,
323+};
324+typedef NSUInteger JKValueType;
325+
326+enum {
327+ JKEncodeOptionAsData = 1,
328+ JKEncodeOptionAsString = 2,
329+ JKEncodeOptionAsTypeMask = 0x7,
330+ JKEncodeOptionCollectionObj = (1 << 3),
331+ JKEncodeOptionStringObj = (1 << 4),
332+ JKEncodeOptionStringObjTrimQuotes = (1 << 5),
333+
334+};
335+typedef NSUInteger JKEncodeOptionType;
336+
337+typedef NSUInteger JKHash;
338+
339+typedef struct JKTokenCacheItem JKTokenCacheItem;
340+typedef struct JKTokenCache JKTokenCache;
341+typedef struct JKTokenValue JKTokenValue;
342+typedef struct JKParseToken JKParseToken;
343+typedef struct JKPtrRange JKPtrRange;
344+typedef struct JKObjectStack JKObjectStack;
345+typedef struct JKBuffer JKBuffer;
346+typedef struct JKConstBuffer JKConstBuffer;
347+typedef struct JKConstPtrRange JKConstPtrRange;
348+typedef struct JKRange JKRange;
349+typedef struct JKManagedBuffer JKManagedBuffer;
350+typedef struct JKFastClassLookup JKFastClassLookup;
351+typedef struct JKEncodeCache JKEncodeCache;
352+typedef struct JKEncodeState JKEncodeState;
353+typedef struct JKObjCImpCache JKObjCImpCache;
354+typedef struct JKHashTableEntry JKHashTableEntry;
355+
356+typedef id (*NSNumberAllocImp)(id receiver, SEL selector);
357+typedef id (*NSNumberInitWithUnsignedLongLongImp)(id receiver, SEL selector, unsigned long long value);
358+typedef id (*JKClassFormatterIMP)(id receiver, SEL selector, id object);
359+#ifdef __BLOCKS__
360+typedef id (^JKClassFormatterBlock)(id formatObject);
361+#endif
362+
363+
364+struct JKPtrRange {
365+ unsigned char *ptr;
366+ size_t length;
367+};
368+
369+struct JKConstPtrRange {
370+ const unsigned char *ptr;
371+ size_t length;
372+};
373+
374+struct JKRange {
375+ size_t location, length;
376+};
377+
378+struct JKManagedBuffer {
379+ JKPtrRange bytes;
380+ JKManagedBufferFlags flags;
381+ size_t roundSizeUpToMultipleOf;
382+};
383+
384+struct JKObjectStack {
385+ void **objects, **keys;
386+ CFHashCode *cfHashes;
387+ size_t count, index, roundSizeUpToMultipleOf;
388+ JKObjectStackFlags flags;
389+};
390+
391+struct JKBuffer {
392+ JKPtrRange bytes;
393+};
394+
395+struct JKConstBuffer {
396+ JKConstPtrRange bytes;
397+};
398+
399+struct JKTokenValue {
400+ JKConstPtrRange ptrRange;
401+ JKValueType type;
402+ JKHash hash;
403+ union {
404+ long long longLongValue;
405+ unsigned long long unsignedLongLongValue;
406+ double doubleValue;
407+ } number;
408+ JKTokenCacheItem *cacheItem;
409+};
410+
411+struct JKParseToken {
412+ JKConstPtrRange tokenPtrRange;
413+ JKTokenType type;
414+ JKTokenValue value;
415+ JKManagedBuffer tokenBuffer;
416+};
417+
418+struct JKTokenCacheItem {
419+ void *object;
420+ JKHash hash;
421+ CFHashCode cfHash;
422+ size_t size;
423+ unsigned char *bytes;
424+ JKValueType type;
425+};
426+
427+struct JKTokenCache {
428+ JKTokenCacheItem *items;
429+ size_t count;
430+ unsigned int prng_lfsr;
431+ unsigned char age[JK_CACHE_SLOTS];
432+};
433+
434+struct JKObjCImpCache {
435+ Class NSNumberClass;
436+ NSNumberAllocImp NSNumberAlloc;
437+ NSNumberInitWithUnsignedLongLongImp NSNumberInitWithUnsignedLongLong;
438+};
439+
440+struct JKParseState {
441+ JKParseOptionFlags parseOptionFlags;
442+ JKConstBuffer stringBuffer;
443+ size_t atIndex, lineNumber, lineStartIndex;
444+ size_t prev_atIndex, prev_lineNumber, prev_lineStartIndex;
445+ JKParseToken token;
446+ JKObjectStack objectStack;
447+ JKTokenCache cache;
448+ JKObjCImpCache objCImpCache;
449+ NSError *error;
450+ int errorIsPrev;
451+ BOOL mutableCollections;
452+};
453+
454+struct JKFastClassLookup {
455+ void *stringClass;
456+ void *numberClass;
457+ void *arrayClass;
458+ void *dictionaryClass;
459+ void *nullClass;
460+};
461+
462+struct JKEncodeCache {
463+ id object;
464+ size_t offset;
465+ size_t length;
466+};
467+
468+struct JKEncodeState {
469+ JKManagedBuffer utf8ConversionBuffer;
470+ JKManagedBuffer stringBuffer;
471+ size_t atIndex;
472+ JKFastClassLookup fastClassLookup;
473+ JKEncodeCache cache[JK_ENCODE_CACHE_SLOTS];
474+ JKSerializeOptionFlags serializeOptionFlags;
475+ JKEncodeOptionType encodeOption;
476+ size_t depth;
477+ NSError *error;
478+ id classFormatterDelegate;
479+ SEL classFormatterSelector;
480+ JKClassFormatterIMP classFormatterIMP;
481+#ifdef __BLOCKS__
482+ JKClassFormatterBlock classFormatterBlock;
483+#endif
484+};
485+
486+// This is a JSONKit private class.
487+@interface JKSerializer : NSObject {
488+ JKEncodeState *encodeState;
489+}
490+
491+#ifdef __BLOCKS__
492+#define JKSERIALIZER_BLOCKS_PROTO id(^)(id object)
493+#else
494+#define JKSERIALIZER_BLOCKS_PROTO id
495+#endif
496+
497++ (id)serializeObject:(id)object options:(JKSerializeOptionFlags)optionFlags encodeOption:(JKEncodeOptionType)encodeOption block:(JKSERIALIZER_BLOCKS_PROTO)block delegate:(id)delegate selector:(SEL)selector error:(NSError **)error;
498+- (id)serializeObject:(id)object options:(JKSerializeOptionFlags)optionFlags encodeOption:(JKEncodeOptionType)encodeOption block:(JKSERIALIZER_BLOCKS_PROTO)block delegate:(id)delegate selector:(SEL)selector error:(NSError **)error;
499+- (void)releaseState;
500+
501+@end
502+
503+struct JKHashTableEntry {
504+ NSUInteger keyHash;
505+ id key, object;
506+};
507+
508+
509+typedef uint32_t UTF32; /* at least 32 bits */
510+typedef uint16_t UTF16; /* at least 16 bits */
511+typedef uint8_t UTF8; /* typically 8 bits */
512+
513+typedef enum {
514+ conversionOK, /* conversion successful */
515+ sourceExhausted, /* partial character in source, but hit end */
516+ targetExhausted, /* insuff. room in target for conversion */
517+ sourceIllegal /* source sequence is illegal/malformed */
518+} ConversionResult;
519+
520+#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD
521+#define UNI_MAX_BMP (UTF32)0x0000FFFF
522+#define UNI_MAX_UTF16 (UTF32)0x0010FFFF
523+#define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF
524+#define UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF
525+#define UNI_SUR_HIGH_START (UTF32)0xD800
526+#define UNI_SUR_HIGH_END (UTF32)0xDBFF
527+#define UNI_SUR_LOW_START (UTF32)0xDC00
528+#define UNI_SUR_LOW_END (UTF32)0xDFFF
529+
530+
531+#if !defined(JK_FAST_TRAILING_BYTES)
532+static const char trailingBytesForUTF8[256] = {
533+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
534+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
535+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
536+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
537+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
538+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
539+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
540+ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
541+};
542+#endif
543+
544+static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, 0x03C82080UL, 0xFA082080UL, 0x82082080UL };
545+static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
546+
547+#define JK_AT_STRING_PTR(x) (&((x)->stringBuffer.bytes.ptr[(x)->atIndex]))
548+#define JK_END_STRING_PTR(x) (&((x)->stringBuffer.bytes.ptr[(x)->stringBuffer.bytes.length]))
549+
550+
551+static JKArray *_JKArrayCreate(id *objects, NSUInteger count, BOOL mutableCollection);
552+static void _JKArrayInsertObjectAtIndex(JKArray *array, id newObject, NSUInteger objectIndex);
553+static void _JKArrayReplaceObjectAtIndexWithObject(JKArray *array, NSUInteger objectIndex, id newObject);
554+static void _JKArrayRemoveObjectAtIndex(JKArray *array, NSUInteger objectIndex);
555+
556+
557+static NSUInteger _JKDictionaryCapacityForCount(NSUInteger count);
558+static JKDictionary *_JKDictionaryCreate(id *keys, NSUInteger *keyHashes, id *objects, NSUInteger count, BOOL mutableCollection);
559+static JKHashTableEntry *_JKDictionaryHashEntry(JKDictionary *dictionary);
560+static NSUInteger _JKDictionaryCapacity(JKDictionary *dictionary);
561+static void _JKDictionaryResizeIfNeccessary(JKDictionary *dictionary);
562+static void _JKDictionaryRemoveObjectWithEntry(JKDictionary *dictionary, JKHashTableEntry *entry);
563+static void _JKDictionaryAddObject(JKDictionary *dictionary, NSUInteger keyHash, id key, id object);
564+static JKHashTableEntry *_JKDictionaryHashTableEntryForKey(JKDictionary *dictionary, id aKey);
565+
566+
567+static void _JSONDecoderCleanup(JSONDecoder *decoder);
568+
569+static id _NSStringObjectFromJSONString(NSString *jsonString, JKParseOptionFlags parseOptionFlags, NSError **error, BOOL mutableCollection);
570+
571+
572+static void jk_managedBuffer_release(JKManagedBuffer *managedBuffer);
573+static void jk_managedBuffer_setToStackBuffer(JKManagedBuffer *managedBuffer, unsigned char *ptr, size_t length);
574+static unsigned char *jk_managedBuffer_resize(JKManagedBuffer *managedBuffer, size_t newSize);
575+static void jk_objectStack_release(JKObjectStack *objectStack);
576+static void jk_objectStack_setToStackBuffer(JKObjectStack *objectStack, void **objects, void **keys, CFHashCode *cfHashes, size_t count);
577+static int jk_objectStack_resize(JKObjectStack *objectStack, size_t newCount);
578+
579+static void jk_error(JKParseState *parseState, NSString *format, ...);
580+static int jk_parse_string(JKParseState *parseState);
581+static int jk_parse_number(JKParseState *parseState);
582+static size_t jk_parse_is_newline(JKParseState *parseState, const unsigned char *atCharacterPtr);
583+JK_STATIC_INLINE int jk_parse_skip_newline(JKParseState *parseState);
584+JK_STATIC_INLINE void jk_parse_skip_whitespace(JKParseState *parseState);
585+static int jk_parse_next_token(JKParseState *parseState);
586+static void jk_error_parse_accept_or3(JKParseState *parseState, int state, NSString *or1String, NSString *or2String, NSString *or3String);
587+static void *jk_create_dictionary(JKParseState *parseState, size_t startingObjectIndex);
588+static void *jk_parse_dictionary(JKParseState *parseState);
589+static void *jk_parse_array(JKParseState *parseState);
590+static void *jk_object_for_token(JKParseState *parseState);
591+static void *jk_cachedObjects(JKParseState *parseState);
592+JK_STATIC_INLINE void jk_cache_age(JKParseState *parseState);
593+JK_STATIC_INLINE void jk_set_parsed_token(JKParseState *parseState, const unsigned char *ptr, size_t length, JKTokenType type, size_t advanceBy);
594+
595+
596+static void jk_encode_error(JKEncodeState *encodeState, NSString *format, ...);
597+static int jk_encode_printf(JKEncodeState *encodeState, JKEncodeCache *cacheSlot, size_t startingAtIndex, id object, const char *format, ...);
598+static int jk_encode_write(JKEncodeState *encodeState, JKEncodeCache *cacheSlot, size_t startingAtIndex, id object, const char *format);
599+static int jk_encode_writePrettyPrintWhiteSpace(JKEncodeState *encodeState);
600+static int jk_encode_write1slow(JKEncodeState *encodeState, ssize_t depthChange, const char *format);
601+static int jk_encode_write1fast(JKEncodeState *encodeState, ssize_t depthChange JK_UNUSED_ARG, const char *format);
602+static int jk_encode_writen(JKEncodeState *encodeState, JKEncodeCache *cacheSlot, size_t startingAtIndex, id object, const char *format, size_t length);
603+JK_STATIC_INLINE JKHash jk_encode_object_hash(void *objectPtr);
604+JK_STATIC_INLINE void jk_encode_updateCache(JKEncodeState *encodeState, JKEncodeCache *cacheSlot, size_t startingAtIndex, id object);
605+static int jk_encode_add_atom_to_buffer(JKEncodeState *encodeState, void *objectPtr);
606+
607+#define jk_encode_write1(es, dc, f) (JK_EXPECT_F(_jk_encode_prettyPrint) ? jk_encode_write1slow(es, dc, f) : jk_encode_write1fast(es, dc, f))
608+
609+
610+JK_STATIC_INLINE size_t jk_min(size_t a, size_t b);
611+JK_STATIC_INLINE size_t jk_max(size_t a, size_t b);
612+JK_STATIC_INLINE JKHash jk_calculateHash(JKHash currentHash, unsigned char c);
613+
614+// JSONKit v1.4 used both a JKArray : NSArray and JKMutableArray : NSMutableArray, and the same for the dictionary collection type.
615+// However, Louis Gerbarg (via cocoa-dev) pointed out that Cocoa / Core Foundation actually implements only a single class that inherits from the
616+// mutable version, and keeps an ivar bit for whether or not that instance is mutable. This means that the immutable versions of the collection
617+// classes receive the mutating methods, but this is handled by having those methods throw an exception when the ivar bit is set to immutable.
618+// We adopt the same strategy here. It's both cleaner and gets rid of the method swizzling hackery used in JSONKit v1.4.
619+
620+
621+// This is a workaround for issue #23 https://github.com/johnezang/JSONKit/pull/23
622+// Basically, there seem to be a problem with using +load in static libraries on iOS. However, __attribute__ ((constructor)) does work correctly.
623+// Since we do not require anything "special" that +load provides, and we can accomplish the same thing using __attribute__ ((constructor)), the +load logic was moved here.
624+
625+static Class _JKArrayClass = NULL;
626+static size_t _JKArrayInstanceSize = 0UL;
627+static Class _JKDictionaryClass = NULL;
628+static size_t _JKDictionaryInstanceSize = 0UL;
629+
630+// For JSONDecoder...
631+static Class _jk_NSNumberClass = NULL;
632+static NSNumberAllocImp _jk_NSNumberAllocImp = NULL;
633+static NSNumberInitWithUnsignedLongLongImp _jk_NSNumberInitWithUnsignedLongLongImp = NULL;
634+
635+extern void jk_collectionClassLoadTimeInitialization(void) __attribute__ ((constructor));
636+
637+void jk_collectionClassLoadTimeInitialization(void) {
638+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // Though technically not required, the run time environment at load time initialization may be less than ideal.
639+
640+ _JKArrayClass = objc_getClass("JKArray");
641+ _JKArrayInstanceSize = jk_max(16UL, class_getInstanceSize(_JKArrayClass));
642+
643+ _JKDictionaryClass = objc_getClass("JKDictionary");
644+ _JKDictionaryInstanceSize = jk_max(16UL, class_getInstanceSize(_JKDictionaryClass));
645+
646+ // For JSONDecoder...
647+ _jk_NSNumberClass = [NSNumber class];
648+ _jk_NSNumberAllocImp = (NSNumberAllocImp)[NSNumber methodForSelector:@selector(alloc)];
649+
650+ // Hacktacular. Need to do it this way due to the nature of class clusters.
651+ id temp_NSNumber = [NSNumber alloc];
652+ _jk_NSNumberInitWithUnsignedLongLongImp = (NSNumberInitWithUnsignedLongLongImp)[temp_NSNumber methodForSelector:@selector(initWithUnsignedLongLong:)];
653+ [[temp_NSNumber init] release];
654+ temp_NSNumber = NULL;
655+
656+ [pool release]; pool = NULL;
657+}
658+
659+
660+#pragma mark -
661+@interface JKArray : NSMutableArray <NSCopying, NSMutableCopying, NSFastEnumeration> {
662+ id *objects;
663+ NSUInteger count, capacity, mutations;
664+}
665+@end
666+
667+@implementation JKArray
668+
669++ (id)allocWithZone:(NSZone *)zone
670+{
671+#pragma unused(zone)
672+ [NSException raise:NSInvalidArgumentException format:@"*** - [%@ %@]: The %@ class is private to JSONKit and should not be used in this fashion.", NSStringFromClass([self class]), NSStringFromSelector(_cmd), NSStringFromClass([self class])];
673+ return(NULL);
674+}
675+
676+static JKArray *_JKArrayCreate(id *objects, NSUInteger count, BOOL mutableCollection) {
677+ NSCParameterAssert((objects != NULL) && (_JKArrayClass != NULL) && (_JKArrayInstanceSize > 0UL));
678+ JKArray *array = NULL;
679+ if(JK_EXPECT_T((array = (JKArray *)calloc(1UL, _JKArrayInstanceSize)) != NULL)) { // Directly allocate the JKArray instance via calloc.
680+ object_setClass(array, _JKArrayClass);
681+ if((array = [array init]) == NULL) { return(NULL); }
682+ array->capacity = count;
683+ array->count = count;
684+ if(JK_EXPECT_F((array->objects = (id *)malloc(sizeof(id) * array->capacity)) == NULL)) { [array autorelease]; return(NULL); }
685+ memcpy(array->objects, objects, array->capacity * sizeof(id));
686+ array->mutations = (mutableCollection == NO) ? 0UL : 1UL;
687+ }
688+ return(array);
689+}
690+
691+// Note: The caller is responsible for -retaining the object that is to be added.
692+static void _JKArrayInsertObjectAtIndex(JKArray *array, id newObject, NSUInteger objectIndex) {
693+ NSCParameterAssert((array != NULL) && (array->objects != NULL) && (array->count <= array->capacity) && (objectIndex <= array->count) && (newObject != NULL));
694+ if(!((array != NULL) && (array->objects != NULL) && (objectIndex <= array->count) && (newObject != NULL))) { [newObject autorelease]; return; }
695+ if((array->count + 1UL) >= array->capacity) {
696+ id *newObjects = NULL;
697+ if((newObjects = (id *)realloc(array->objects, sizeof(id) * (array->capacity + 16UL))) == NULL) { [NSException raise:NSMallocException format:@"Unable to resize objects array."]; }
698+ array->objects = newObjects;
699+ array->capacity += 16UL;
700+ memset(&array->objects[array->count], 0, sizeof(id) * (array->capacity - array->count));
701+ }
702+ array->count++;
703+ if((objectIndex + 1UL) < array->count) { memmove(&array->objects[objectIndex + 1UL], &array->objects[objectIndex], sizeof(id) * ((array->count - 1UL) - objectIndex)); array->objects[objectIndex] = NULL; }
704+ array->objects[objectIndex] = newObject;
705+}
706+
707+// Note: The caller is responsible for -retaining the object that is to be added.
708+static void _JKArrayReplaceObjectAtIndexWithObject(JKArray *array, NSUInteger objectIndex, id newObject) {
709+ NSCParameterAssert((array != NULL) && (array->objects != NULL) && (array->count <= array->capacity) && (objectIndex < array->count) && (array->objects[objectIndex] != NULL) && (newObject != NULL));
710+ if(!((array != NULL) && (array->objects != NULL) && (objectIndex < array->count) && (array->objects[objectIndex] != NULL) && (newObject != NULL))) { [newObject autorelease]; return; }
711+ CFRelease(array->objects[objectIndex]);
712+ array->objects[objectIndex] = NULL;
713+ array->objects[objectIndex] = newObject;
714+}
715+
716+static void _JKArrayRemoveObjectAtIndex(JKArray *array, NSUInteger objectIndex) {
717+ NSCParameterAssert((array != NULL) && (array->objects != NULL) && (array->count > 0UL) && (array->count <= array->capacity) && (objectIndex < array->count) && (array->objects[objectIndex] != NULL));
718+ if(!((array != NULL) && (array->objects != NULL) && (array->count > 0UL) && (array->count <= array->capacity) && (objectIndex < array->count) && (array->objects[objectIndex] != NULL))) { return; }
719+ CFRelease(array->objects[objectIndex]);
720+ array->objects[objectIndex] = NULL;
721+ if((objectIndex + 1UL) < array->count) { memmove(&array->objects[objectIndex], &array->objects[objectIndex + 1UL], sizeof(id) * ((array->count - 1UL) - objectIndex)); array->objects[array->count - 1UL] = NULL; }
722+ array->count--;
723+}
724+
725+- (void)dealloc
726+{
727+ if(JK_EXPECT_T(objects != NULL)) {
728+ NSUInteger atObject = 0UL;
729+ for(atObject = 0UL; atObject < count; atObject++) { if(JK_EXPECT_T(objects[atObject] != NULL)) { CFRelease(objects[atObject]); objects[atObject] = NULL; } }
730+ free(objects); objects = NULL;
731+ }
732+
733+ [super dealloc];
734+}
735+
736+- (NSUInteger)count
737+{
738+ NSParameterAssert((objects != NULL) && (count <= capacity));
739+ return(count);
740+}
741+
742+- (void)getObjects:(id *)objectsPtr range:(NSRange)range
743+{
744+ NSParameterAssert((objects != NULL) && (count <= capacity));
745+ if((objectsPtr == NULL) && (NSMaxRange(range) > 0UL)) { [NSException raise:NSRangeException format:@"*** -[%@ %@]: pointer to objects array is NULL but range length is %lu", NSStringFromClass([self class]), NSStringFromSelector(_cmd), (unsigned long)NSMaxRange(range)]; }
746+ if((range.location > count) || (NSMaxRange(range) > count)) { [NSException raise:NSRangeException format:@"*** -[%@ %@]: index (%lu) beyond bounds (%lu)", NSStringFromClass([self class]), NSStringFromSelector(_cmd), (unsigned long)NSMaxRange(range), (unsigned long)count]; }
747+#ifndef __clang_analyzer__
748+ memcpy(objectsPtr, objects + range.location, range.length * sizeof(id));
749+#endif
750+}
751+
752+- (id)objectAtIndex:(NSUInteger)objectIndex
753+{
754+ if(objectIndex >= count) { [NSException raise:NSRangeException format:@"*** -[%@ %@]: index (%lu) beyond bounds (%lu)", NSStringFromClass([self class]), NSStringFromSelector(_cmd), (unsigned long)objectIndex, (unsigned long)count]; }
755+ NSParameterAssert((objects != NULL) && (count <= capacity) && (objects[objectIndex] != NULL));
756+ return(objects[objectIndex]);
757+}
758+
759+- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len
760+{
761+ NSParameterAssert((state != NULL) && (stackbuf != NULL) && (len > 0UL) && (objects != NULL) && (count <= capacity));
762+ if(JK_EXPECT_F(state->state == 0UL)) { state->mutationsPtr = (unsigned long *)&mutations; state->itemsPtr = stackbuf; }
763+ if(JK_EXPECT_F(state->state >= count)) { return(0UL); }
764+
765+ NSUInteger enumeratedCount = 0UL;
766+ while(JK_EXPECT_T(enumeratedCount < len) && JK_EXPECT_T(state->state < count)) { NSParameterAssert(objects[state->state] != NULL); stackbuf[enumeratedCount++] = objects[state->state++]; }
767+
768+ return(enumeratedCount);
769+}
770+
771+- (void)insertObject:(id)anObject atIndex:(NSUInteger)objectIndex
772+{
773+ if(mutations == 0UL) { [NSException raise:NSInternalInconsistencyException format:@"*** -[%@ %@]: mutating method sent to immutable object", NSStringFromClass([self class]), NSStringFromSelector(_cmd)]; }
774+ if(anObject == NULL) { [NSException raise:NSInvalidArgumentException format:@"*** -[%@ %@]: attempt to insert nil", NSStringFromClass([self class]), NSStringFromSelector(_cmd)]; }
775+ if(objectIndex > count) { [NSException raise:NSRangeException format:@"*** -[%@ %@]: index (%lu) beyond bounds (%lu)", NSStringFromClass([self class]), NSStringFromSelector(_cmd), (unsigned long)objectIndex, (unsigned long)(count + 1UL)]; }
776+#ifdef __clang_analyzer__
777+ [anObject retain]; // Stupid clang analyzer... Issue #19.
778+#else
779+ anObject = [anObject retain];
780+#endif
781+ _JKArrayInsertObjectAtIndex(self, anObject, objectIndex);
782+ mutations = (mutations == NSUIntegerMax) ? 1UL : mutations + 1UL;
783+}
784+
785+- (void)removeObjectAtIndex:(NSUInteger)objectIndex
786+{
787+ if(mutations == 0UL) { [NSException raise:NSInternalInconsistencyException format:@"*** -[%@ %@]: mutating method sent to immutable object", NSStringFromClass([self class]), NSStringFromSelector(_cmd)]; }
788+ if(objectIndex >= count) { [NSException raise:NSRangeException format:@"*** -[%@ %@]: index (%lu) beyond bounds (%lu)", NSStringFromClass([self class]), NSStringFromSelector(_cmd), (unsigned long)objectIndex, (unsigned long)count]; }
789+ _JKArrayRemoveObjectAtIndex(self, objectIndex);
790+ mutations = (mutations == NSUIntegerMax) ? 1UL : mutations + 1UL;
791+}
792+
793+- (void)replaceObjectAtIndex:(NSUInteger)objectIndex withObject:(id)anObject
794+{
795+ if(mutations == 0UL) { [NSException raise:NSInternalInconsistencyException format:@"*** -[%@ %@]: mutating method sent to immutable object", NSStringFromClass([self class]), NSStringFromSelector(_cmd)]; }
796+ if(anObject == NULL) { [NSException raise:NSInvalidArgumentException format:@"*** -[%@ %@]: attempt to insert nil", NSStringFromClass([self class]), NSStringFromSelector(_cmd)]; }
797+ if(objectIndex >= count) { [NSException raise:NSRangeException format:@"*** -[%@ %@]: index (%lu) beyond bounds (%lu)", NSStringFromClass([self class]), NSStringFromSelector(_cmd), (unsigned long)objectIndex, (unsigned long)count]; }
798+#ifdef __clang_analyzer__
799+ [anObject retain]; // Stupid clang analyzer... Issue #19.
800+#else
801+ anObject = [anObject retain];
802+#endif
803+ _JKArrayReplaceObjectAtIndexWithObject(self, objectIndex, anObject);
804+ mutations = (mutations == NSUIntegerMax) ? 1UL : mutations + 1UL;
805+}
806+
807+- (id)copyWithZone:(NSZone *)zone
808+{
809+ NSParameterAssert((objects != NULL) && (count <= capacity));
810+ return((mutations == 0UL) ? [self retain] : [(NSArray *)[NSArray allocWithZone:zone] initWithObjects:objects count:count]);
811+}
812+
813+- (id)mutableCopyWithZone:(NSZone *)zone
814+{
815+ NSParameterAssert((objects != NULL) && (count <= capacity));
816+ return([(NSMutableArray *)[NSMutableArray allocWithZone:zone] initWithObjects:objects count:count]);
817+}
818+
819+@end
820+
821+
822+#pragma mark -
823+@interface JKDictionaryEnumerator : NSEnumerator {
824+ id collection;
825+ NSUInteger nextObject;
826+}
827+
828+- (id)initWithJKDictionary:(JKDictionary *)initDictionary;
829+- (NSArray *)allObjects;
830+- (id)nextObject;
831+
832+@end
833+
834+@implementation JKDictionaryEnumerator
835+
836+- (id)initWithJKDictionary:(JKDictionary *)initDictionary
837+{
838+ NSParameterAssert(initDictionary != NULL);
839+ if((self = [super init]) == NULL) { return(NULL); }
840+ if((collection = (id)CFRetain(initDictionary)) == NULL) { [self autorelease]; return(NULL); }
841+ return(self);
842+}
843+
844+- (void)dealloc
845+{
846+ if(collection != NULL) { CFRelease(collection); collection = NULL; }
847+ [super dealloc];
848+}
849+
850+- (NSArray *)allObjects
851+{
852+ NSParameterAssert(collection != NULL);
853+ NSUInteger count = [(NSDictionary *)collection count], atObject = 0UL;
854+ id objects[count];
855+
856+ while((objects[atObject] = [self nextObject]) != NULL) { NSParameterAssert(atObject < count); atObject++; }
857+
858+ return([NSArray arrayWithObjects:objects count:atObject]);
859+}
860+
861+- (id)nextObject
862+{
863+ NSParameterAssert((collection != NULL) && (_JKDictionaryHashEntry(collection) != NULL));
864+ JKHashTableEntry *entry = _JKDictionaryHashEntry(collection);
865+ NSUInteger capacity = _JKDictionaryCapacity(collection);
866+ id returnObject = NULL;
867+
868+ if(entry != NULL) { while((nextObject < capacity) && ((returnObject = entry[nextObject++].key) == NULL)) { /* ... */ } }
869+
870+ return(returnObject);
871+}
872+
873+@end
874+
875+#pragma mark -
876+@interface JKDictionary : NSMutableDictionary <NSCopying, NSMutableCopying, NSFastEnumeration> {
877+ NSUInteger count, capacity, mutations;
878+ JKHashTableEntry *entry;
879+}
880+@end
881+
882+@implementation JKDictionary
883+
884++ (id)allocWithZone:(NSZone *)zone
885+{
886+#pragma unused(zone)
887+ [NSException raise:NSInvalidArgumentException format:@"*** - [%@ %@]: The %@ class is private to JSONKit and should not be used in this fashion.", NSStringFromClass([self class]), NSStringFromSelector(_cmd), NSStringFromClass([self class])];
888+ return(NULL);
889+}
890+
891+// These values are taken from Core Foundation CF-550 CFBasicHash.m. As a bonus, they align very well with our JKHashTableEntry struct too.
892+static const NSUInteger jk_dictionaryCapacities[] = {
893+ 0UL, 3UL, 7UL, 13UL, 23UL, 41UL, 71UL, 127UL, 191UL, 251UL, 383UL, 631UL, 1087UL, 1723UL,
894+ 2803UL, 4523UL, 7351UL, 11959UL, 19447UL, 31231UL, 50683UL, 81919UL, 132607UL,
895+ 214519UL, 346607UL, 561109UL, 907759UL, 1468927UL, 2376191UL, 3845119UL,
896+ 6221311UL, 10066421UL, 16287743UL, 26354171UL, 42641881UL, 68996069UL,
897+ 111638519UL, 180634607UL, 292272623UL, 472907251UL
898+};
899+
900+static NSUInteger _JKDictionaryCapacityForCount(NSUInteger count) {
901+ NSUInteger bottom = 0UL, top = sizeof(jk_dictionaryCapacities) / sizeof(NSUInteger), mid = 0UL, tableSize = (NSUInteger)lround(floor(((double)count) * 1.33));
902+ while(top > bottom) { mid = (top + bottom) / 2UL; if(jk_dictionaryCapacities[mid] < tableSize) { bottom = mid + 1UL; } else { top = mid; } }
903+ return(jk_dictionaryCapacities[bottom]);
904+}
905+
906+static void _JKDictionaryResizeIfNeccessary(JKDictionary *dictionary) {
907+ NSCParameterAssert((dictionary != NULL) && (dictionary->entry != NULL) && (dictionary->count <= dictionary->capacity));
908+
909+ NSUInteger capacityForCount = 0UL;
910+ if(dictionary->capacity < (capacityForCount = _JKDictionaryCapacityForCount(dictionary->count + 1UL))) { // resize
911+ NSUInteger oldCapacity = dictionary->capacity;
912+#ifndef NS_BLOCK_ASSERTIONS
913+ NSUInteger oldCount = dictionary->count;
914+#endif
915+ JKHashTableEntry *oldEntry = dictionary->entry;
916+ if(JK_EXPECT_F((dictionary->entry = (JKHashTableEntry *)calloc(1UL, sizeof(JKHashTableEntry) * capacityForCount)) == NULL)) { [NSException raise:NSMallocException format:@"Unable to allocate memory for hash table."]; }
917+ dictionary->capacity = capacityForCount;
918+ dictionary->count = 0UL;
919+
920+ NSUInteger idx = 0UL;
921+ for(idx = 0UL; idx < oldCapacity; idx++) { if(oldEntry[idx].key != NULL) { _JKDictionaryAddObject(dictionary, oldEntry[idx].keyHash, oldEntry[idx].key, oldEntry[idx].object); oldEntry[idx].keyHash = 0UL; oldEntry[idx].key = NULL; oldEntry[idx].object = NULL; } }
922+ NSCParameterAssert((oldCount == dictionary->count));
923+ free(oldEntry); oldEntry = NULL;
924+ }
925+}
926+
927+static JKDictionary *_JKDictionaryCreate(id *keys, NSUInteger *keyHashes, id *objects, NSUInteger count, BOOL mutableCollection) {
928+ NSCParameterAssert((keys != NULL) && (keyHashes != NULL) && (objects != NULL) && (_JKDictionaryClass != NULL) && (_JKDictionaryInstanceSize > 0UL));
929+ JKDictionary *dictionary = NULL;
930+ if(JK_EXPECT_T((dictionary = (JKDictionary *)calloc(1UL, _JKDictionaryInstanceSize)) != NULL)) { // Directly allocate the JKDictionary instance via calloc.
931+ object_setClass(dictionary, _JKDictionaryClass);
932+ if((dictionary = [dictionary init]) == NULL) { return(NULL); }
933+ dictionary->capacity = _JKDictionaryCapacityForCount(count);
934+ dictionary->count = 0UL;
935+
936+ if(JK_EXPECT_F((dictionary->entry = (JKHashTableEntry *)calloc(1UL, sizeof(JKHashTableEntry) * dictionary->capacity)) == NULL)) { [dictionary autorelease]; return(NULL); }
937+
938+ NSUInteger idx = 0UL;
939+ for(idx = 0UL; idx < count; idx++) { _JKDictionaryAddObject(dictionary, keyHashes[idx], keys[idx], objects[idx]); }
940+
941+ dictionary->mutations = (mutableCollection == NO) ? 0UL : 1UL;
942+ }
943+ return(dictionary);
944+}
945+
946+- (void)dealloc
947+{
948+ if(JK_EXPECT_T(entry != NULL)) {
949+ NSUInteger atEntry = 0UL;
950+ for(atEntry = 0UL; atEntry < capacity; atEntry++) {
951+ if(JK_EXPECT_T(entry[atEntry].key != NULL)) { CFRelease(entry[atEntry].key); entry[atEntry].key = NULL; }
952+ if(JK_EXPECT_T(entry[atEntry].object != NULL)) { CFRelease(entry[atEntry].object); entry[atEntry].object = NULL; }
953+ }
954+
955+ free(entry); entry = NULL;
956+ }
957+
958+ [super dealloc];
959+}
960+
961+static JKHashTableEntry *_JKDictionaryHashEntry(JKDictionary *dictionary) {
962+ NSCParameterAssert(dictionary != NULL);
963+ return(dictionary->entry);
964+}
965+
966+static NSUInteger _JKDictionaryCapacity(JKDictionary *dictionary) {
967+ NSCParameterAssert(dictionary != NULL);
968+ return(dictionary->capacity);
969+}
970+
971+static void _JKDictionaryRemoveObjectWithEntry(JKDictionary *dictionary, JKHashTableEntry *entry) {
972+ NSCParameterAssert((dictionary != NULL) && (entry != NULL) && (entry->key != NULL) && (entry->object != NULL) && (dictionary->count > 0UL) && (dictionary->count <= dictionary->capacity));
973+ CFRelease(entry->key); entry->key = NULL;
974+ CFRelease(entry->object); entry->object = NULL;
975+ entry->keyHash = 0UL;
976+ dictionary->count--;
977+ // In order for certain invariants that are used to speed up the search for a particular key, we need to "re-add" all the entries in the hash table following this entry until we hit a NULL entry.
978+ NSUInteger removeIdx = entry - dictionary->entry, idx = 0UL;
979+ NSCParameterAssert((removeIdx < dictionary->capacity));
980+ for(idx = 0UL; idx < dictionary->capacity; idx++) {
981+ NSUInteger entryIdx = (removeIdx + idx + 1UL) % dictionary->capacity;
982+ JKHashTableEntry *atEntry = &dictionary->entry[entryIdx];
983+ if(atEntry->key == NULL) { break; }
984+ NSUInteger keyHash = atEntry->keyHash;
985+ id key = atEntry->key, object = atEntry->object;
986+ NSCParameterAssert(object != NULL);
987+ atEntry->keyHash = 0UL;
988+ atEntry->key = NULL;
989+ atEntry->object = NULL;
990+ NSUInteger addKeyEntry = keyHash % dictionary->capacity, addIdx = 0UL;
991+ for(addIdx = 0UL; addIdx < dictionary->capacity; addIdx++) {
992+ JKHashTableEntry *atAddEntry = &dictionary->entry[((addKeyEntry + addIdx) % dictionary->capacity)];
993+ if(JK_EXPECT_T(atAddEntry->key == NULL)) { NSCParameterAssert((atAddEntry->keyHash == 0UL) && (atAddEntry->object == NULL)); atAddEntry->key = key; atAddEntry->object = object; atAddEntry->keyHash = keyHash; break; }
994+ }
995+ }
996+}
997+
998+static void _JKDictionaryAddObject(JKDictionary *dictionary, NSUInteger keyHash, id key, id object) {
999+ NSCParameterAssert((dictionary != NULL) && (key != NULL) && (object != NULL) && (dictionary->count < dictionary->capacity) && (dictionary->entry != NULL));
1000+ NSUInteger keyEntry = keyHash % dictionary->capacity, idx = 0UL;
1001+ for(idx = 0UL; idx < dictionary->capacity; idx++) {
1002+ NSUInteger entryIdx = (keyEntry + idx) % dictionary->capacity;
1003+ JKHashTableEntry *atEntry = &dictionary->entry[entryIdx];
1004+ if(JK_EXPECT_F(atEntry->keyHash == keyHash) && JK_EXPECT_T(atEntry->key != NULL) && (JK_EXPECT_F(key == atEntry->key) || JK_EXPECT_F(CFEqual(atEntry->key, key)))) { _JKDictionaryRemoveObjectWithEntry(dictionary, atEntry); }
1005+ if(JK_EXPECT_T(atEntry->key == NULL)) { NSCParameterAssert((atEntry->keyHash == 0UL) && (atEntry->object == NULL)); atEntry->key = key; atEntry->object = object; atEntry->keyHash = keyHash; dictionary->count++; return; }
1006+ }
1007+
1008+ // We should never get here. If we do, we -release the key / object because it's our responsibility.
1009+ CFRelease(key);
1010+ CFRelease(object);
1011+}
1012+
1013+- (NSUInteger)count
1014+{
1015+ return(count);
1016+}
1017+
1018+static JKHashTableEntry *_JKDictionaryHashTableEntryForKey(JKDictionary *dictionary, id aKey) {
1019+ NSCParameterAssert((dictionary != NULL) && (dictionary->entry != NULL) && (dictionary->count <= dictionary->capacity));
1020+ if((aKey == NULL) || (dictionary->capacity == 0UL)) { return(NULL); }
1021+ NSUInteger keyHash = CFHash(aKey), keyEntry = (keyHash % dictionary->capacity), idx = 0UL;
1022+ JKHashTableEntry *atEntry = NULL;
1023+ for(idx = 0UL; idx < dictionary->capacity; idx++) {
1024+ atEntry = &dictionary->entry[(keyEntry + idx) % dictionary->capacity];
1025+ if(JK_EXPECT_T(atEntry->keyHash == keyHash) && JK_EXPECT_T(atEntry->key != NULL) && ((atEntry->key == aKey) || CFEqual(atEntry->key, aKey))) { NSCParameterAssert(atEntry->object != NULL); return(atEntry); break; }
1026+ if(JK_EXPECT_F(atEntry->key == NULL)) { NSCParameterAssert(atEntry->object == NULL); return(NULL); break; } // If the key was in the table, we would have found it by now.
1027+ }
1028+ return(NULL);
1029+}
1030+
1031+- (id)objectForKey:(id)aKey
1032+{
1033+ NSParameterAssert((entry != NULL) && (count <= capacity));
1034+ JKHashTableEntry *entryForKey = _JKDictionaryHashTableEntryForKey(self, aKey);
1035+ return((entryForKey != NULL) ? entryForKey->object : NULL);
1036+}
1037+
1038+- (void)getObjects:(id *)objects andKeys:(id *)keys
1039+{
1040+ NSParameterAssert((entry != NULL) && (count <= capacity));
1041+ NSUInteger atEntry = 0UL; NSUInteger arrayIdx = 0UL;
1042+ for(atEntry = 0UL; atEntry < capacity; atEntry++) {
1043+ if(JK_EXPECT_T(entry[atEntry].key != NULL)) {
1044+ NSCParameterAssert((entry[atEntry].object != NULL) && (arrayIdx < count));
1045+ if(JK_EXPECT_T(keys != NULL)) { keys[arrayIdx] = entry[atEntry].key; }
1046+ if(JK_EXPECT_T(objects != NULL)) { objects[arrayIdx] = entry[atEntry].object; }
1047+ arrayIdx++;
1048+ }
1049+ }
1050+}
1051+
1052+- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len
1053+{
1054+ NSParameterAssert((state != NULL) && (stackbuf != NULL) && (len > 0UL) && (entry != NULL) && (count <= capacity));
1055+ if(JK_EXPECT_F(state->state == 0UL)) { state->mutationsPtr = (unsigned long *)&mutations; state->itemsPtr = stackbuf; }
1056+ if(JK_EXPECT_F(state->state >= capacity)) { return(0UL); }
1057+
1058+ NSUInteger enumeratedCount = 0UL;
1059+ while(JK_EXPECT_T(enumeratedCount < len) && JK_EXPECT_T(state->state < capacity)) { if(JK_EXPECT_T(entry[state->state].key != NULL)) { stackbuf[enumeratedCount++] = entry[state->state].key; } state->state++; }
1060+
1061+ return(enumeratedCount);
1062+}
1063+
1064+- (NSEnumerator *)keyEnumerator
1065+{
1066+ return([[[JKDictionaryEnumerator alloc] initWithJKDictionary:self] autorelease]);
1067+}
1068+
1069+- (void)setObject:(id)anObject forKey:(id)aKey
1070+{
1071+ if(mutations == 0UL) { [NSException raise:NSInternalInconsistencyException format:@"*** -[%@ %@]: mutating method sent to immutable object", NSStringFromClass([self class]), NSStringFromSelector(_cmd)]; }
1072+ if(aKey == NULL) { [NSException raise:NSInvalidArgumentException format:@"*** -[%@ %@]: attempt to insert nil key", NSStringFromClass([self class]), NSStringFromSelector(_cmd)]; }
1073+ if(anObject == NULL) { [NSException raise:NSInvalidArgumentException format:@"*** -[%@ %@]: attempt to insert nil value (key: %@)", NSStringFromClass([self class]), NSStringFromSelector(_cmd), aKey]; }
1074+
1075+ _JKDictionaryResizeIfNeccessary(self);
1076+#ifndef __clang_analyzer__
1077+ aKey = [aKey copy]; // Why on earth would clang complain that this -copy "might leak",
1078+ anObject = [anObject retain]; // but this -retain doesn't!?
1079+#endif // __clang_analyzer__
1080+ _JKDictionaryAddObject(self, CFHash(aKey), aKey, anObject);
1081+ mutations = (mutations == NSUIntegerMax) ? 1UL : mutations + 1UL;
1082+}
1083+
1084+- (void)removeObjectForKey:(id)aKey
1085+{
1086+ if(mutations == 0UL) { [NSException raise:NSInternalInconsistencyException format:@"*** -[%@ %@]: mutating method sent to immutable object", NSStringFromClass([self class]), NSStringFromSelector(_cmd)]; }
1087+ if(aKey == NULL) { [NSException raise:NSInvalidArgumentException format:@"*** -[%@ %@]: attempt to remove nil key", NSStringFromClass([self class]), NSStringFromSelector(_cmd)]; }
1088+ JKHashTableEntry *entryForKey = _JKDictionaryHashTableEntryForKey(self, aKey);
1089+ if(entryForKey != NULL) {
1090+ _JKDictionaryRemoveObjectWithEntry(self, entryForKey);
1091+ mutations = (mutations == NSUIntegerMax) ? 1UL : mutations + 1UL;
1092+ }
1093+}
1094+
1095+- (id)copyWithZone:(NSZone *)zone
1096+{
1097+ NSParameterAssert((entry != NULL) && (count <= capacity));
1098+ return((mutations == 0UL) ? [self retain] : [[NSDictionary allocWithZone:zone] initWithDictionary:self]);
1099+}
1100+
1101+- (id)mutableCopyWithZone:(NSZone *)zone
1102+{
1103+ NSParameterAssert((entry != NULL) && (count <= capacity));
1104+ return([[NSMutableDictionary allocWithZone:zone] initWithDictionary:self]);
1105+}
1106+
1107+@end
1108+
1109+
1110+
1111+#pragma mark -
1112+
1113+JK_STATIC_INLINE size_t jk_min(size_t a, size_t b) { return((a < b) ? a : b); }
1114+JK_STATIC_INLINE size_t jk_max(size_t a, size_t b) { return((a > b) ? a : b); }
1115+
1116+JK_STATIC_INLINE JKHash jk_calculateHash(JKHash currentHash, unsigned char c) { return((((currentHash << 5) + currentHash) + (c - 29)) ^ (currentHash >> 19)); }
1117+
1118+
1119+static void jk_error(JKParseState *parseState, NSString *format, ...) {
1120+ NSCParameterAssert((parseState != NULL) && (format != NULL));
1121+
1122+ va_list varArgsList;
1123+ va_start(varArgsList, format);
1124+ NSString *formatString = [[[NSString alloc] initWithFormat:format arguments:varArgsList] autorelease];
1125+ va_end(varArgsList);
1126+
1127+#if 0
1128+ const unsigned char *lineStart = parseState->stringBuffer.bytes.ptr + parseState->lineStartIndex;
1129+ const unsigned char *lineEnd = lineStart;
1130+ const unsigned char *atCharacterPtr = NULL;
1131+
1132+ for(atCharacterPtr = lineStart; atCharacterPtr < JK_END_STRING_PTR(parseState); atCharacterPtr++) { lineEnd = atCharacterPtr; if(jk_parse_is_newline(parseState, atCharacterPtr)) { break; } }
1133+
1134+ NSString *lineString = @"", *carretString = @"";
1135+ if(lineStart < JK_END_STRING_PTR(parseState)) {
1136+ lineString = [[[NSString alloc] initWithBytes:lineStart length:(lineEnd - lineStart) encoding:NSUTF8StringEncoding] autorelease];
1137+ carretString = [NSString stringWithFormat:@"%*.*s^", (int)(parseState->atIndex - parseState->lineStartIndex), (int)(parseState->atIndex - parseState->lineStartIndex), " "];
1138+ }
1139+#endif
1140+
1141+ if(parseState->error == NULL) {
1142+ parseState->error = [NSError errorWithDomain:@"JKErrorDomain" code:-1L userInfo:
1143+ [NSDictionary dictionaryWithObjectsAndKeys:
1144+ formatString, NSLocalizedDescriptionKey,
1145+ [NSNumber numberWithUnsignedLong:parseState->atIndex], @"JKAtIndexKey",
1146+ [NSNumber numberWithUnsignedLong:parseState->lineNumber], @"JKLineNumberKey",
1147+ //lineString, @"JKErrorLine0Key",
1148+ //carretString, @"JKErrorLine1Key",
1149+ NULL]];
1150+ }
1151+}
1152+
1153+#pragma mark -
1154+#pragma mark Buffer and Object Stack management functions
1155+
1156+static void jk_managedBuffer_release(JKManagedBuffer *managedBuffer) {
1157+ if((managedBuffer->flags & JKManagedBufferMustFree)) {
1158+ if(managedBuffer->bytes.ptr != NULL) { free(managedBuffer->bytes.ptr); managedBuffer->bytes.ptr = NULL; }
1159+ managedBuffer->flags &= ~JKManagedBufferMustFree;
1160+ }
1161+
1162+ managedBuffer->bytes.ptr = NULL;
1163+ managedBuffer->bytes.length = 0UL;
1164+ managedBuffer->flags &= ~JKManagedBufferLocationMask;
1165+}
1166+
1167+static void jk_managedBuffer_setToStackBuffer(JKManagedBuffer *managedBuffer, unsigned char *ptr, size_t length) {
1168+ jk_managedBuffer_release(managedBuffer);
1169+ managedBuffer->bytes.ptr = ptr;
1170+ managedBuffer->bytes.length = length;
1171+ managedBuffer->flags = (managedBuffer->flags & ~JKManagedBufferLocationMask) | JKManagedBufferOnStack;
1172+}
1173+
1174+static unsigned char *jk_managedBuffer_resize(JKManagedBuffer *managedBuffer, size_t newSize) {
1175+ size_t roundedUpNewSize = newSize;
1176+
1177+ if(managedBuffer->roundSizeUpToMultipleOf > 0UL) { roundedUpNewSize = newSize + ((managedBuffer->roundSizeUpToMultipleOf - (newSize % managedBuffer->roundSizeUpToMultipleOf)) % managedBuffer->roundSizeUpToMultipleOf); }
1178+
1179+ if((roundedUpNewSize != managedBuffer->bytes.length) && (roundedUpNewSize > managedBuffer->bytes.length)) {
1180+ if((managedBuffer->flags & JKManagedBufferLocationMask) == JKManagedBufferOnStack) {
1181+ NSCParameterAssert((managedBuffer->flags & JKManagedBufferMustFree) == 0);
1182+ unsigned char *newBuffer = NULL, *oldBuffer = managedBuffer->bytes.ptr;
1183+
1184+ if((newBuffer = (unsigned char *)malloc(roundedUpNewSize)) == NULL) { return(NULL); }
1185+ memcpy(newBuffer, oldBuffer, jk_min(managedBuffer->bytes.length, roundedUpNewSize));
1186+ managedBuffer->flags = (managedBuffer->flags & ~JKManagedBufferLocationMask) | (JKManagedBufferOnHeap | JKManagedBufferMustFree);
1187+ managedBuffer->bytes.ptr = newBuffer;
1188+ managedBuffer->bytes.length = roundedUpNewSize;
1189+ } else {
1190+ NSCParameterAssert(((managedBuffer->flags & JKManagedBufferMustFree) != 0) && ((managedBuffer->flags & JKManagedBufferLocationMask) == JKManagedBufferOnHeap));
1191+ if((managedBuffer->bytes.ptr = (unsigned char *)reallocf(managedBuffer->bytes.ptr, roundedUpNewSize)) == NULL) { return(NULL); }
1192+ managedBuffer->bytes.length = roundedUpNewSize;
1193+ }
1194+ }
1195+
1196+ return(managedBuffer->bytes.ptr);
1197+}
1198+
1199+
1200+
1201+static void jk_objectStack_release(JKObjectStack *objectStack) {
1202+ NSCParameterAssert(objectStack != NULL);
1203+
1204+ NSCParameterAssert(objectStack->index <= objectStack->count);
1205+ size_t atIndex = 0UL;
1206+ for(atIndex = 0UL; atIndex < objectStack->index; atIndex++) {
1207+ if(objectStack->objects[atIndex] != NULL) { CFRelease(objectStack->objects[atIndex]); objectStack->objects[atIndex] = NULL; }
1208+ if(objectStack->keys[atIndex] != NULL) { CFRelease(objectStack->keys[atIndex]); objectStack->keys[atIndex] = NULL; }
1209+ }
1210+ objectStack->index = 0UL;
1211+
1212+ if(objectStack->flags & JKObjectStackMustFree) {
1213+ NSCParameterAssert((objectStack->flags & JKObjectStackLocationMask) == JKObjectStackOnHeap);
1214+ if(objectStack->objects != NULL) { free(objectStack->objects); objectStack->objects = NULL; }
1215+ if(objectStack->keys != NULL) { free(objectStack->keys); objectStack->keys = NULL; }
1216+ if(objectStack->cfHashes != NULL) { free(objectStack->cfHashes); objectStack->cfHashes = NULL; }
1217+ objectStack->flags &= ~JKObjectStackMustFree;
1218+ }
1219+
1220+ objectStack->objects = NULL;
1221+ objectStack->keys = NULL;
1222+ objectStack->cfHashes = NULL;
1223+
1224+ objectStack->count = 0UL;
1225+ objectStack->flags &= ~JKObjectStackLocationMask;
1226+}
1227+
1228+static void jk_objectStack_setToStackBuffer(JKObjectStack *objectStack, void **objects, void **keys, CFHashCode *cfHashes, size_t count) {
1229+ NSCParameterAssert((objectStack != NULL) && (objects != NULL) && (keys != NULL) && (cfHashes != NULL) && (count > 0UL));
1230+ jk_objectStack_release(objectStack);
1231+ objectStack->objects = objects;
1232+ objectStack->keys = keys;
1233+ objectStack->cfHashes = cfHashes;
1234+ objectStack->count = count;
1235+ objectStack->flags = (objectStack->flags & ~JKObjectStackLocationMask) | JKObjectStackOnStack;
1236+#ifndef NS_BLOCK_ASSERTIONS
1237+ size_t idx;
1238+ for(idx = 0UL; idx < objectStack->count; idx++) { objectStack->objects[idx] = NULL; objectStack->keys[idx] = NULL; objectStack->cfHashes[idx] = 0UL; }
1239+#endif
1240+}
1241+
1242+static int jk_objectStack_resize(JKObjectStack *objectStack, size_t newCount) {
1243+ size_t roundedUpNewCount = newCount;
1244+ int returnCode = 0;
1245+
1246+ void **newObjects = NULL, **newKeys = NULL;
1247+ CFHashCode *newCFHashes = NULL;
1248+
1249+ if(objectStack->roundSizeUpToMultipleOf > 0UL) { roundedUpNewCount = newCount + ((objectStack->roundSizeUpToMultipleOf - (newCount % objectStack->roundSizeUpToMultipleOf)) % objectStack->roundSizeUpToMultipleOf); }
1250+
1251+ if((roundedUpNewCount != objectStack->count) && (roundedUpNewCount > objectStack->count)) {
1252+ if((objectStack->flags & JKObjectStackLocationMask) == JKObjectStackOnStack) {
1253+ NSCParameterAssert((objectStack->flags & JKObjectStackMustFree) == 0);
1254+
1255+ if((newObjects = (void ** )calloc(1UL, roundedUpNewCount * sizeof(void * ))) == NULL) { returnCode = 1; goto errorExit; }
1256+ memcpy(newObjects, objectStack->objects, jk_min(objectStack->count, roundedUpNewCount) * sizeof(void *));
1257+ if((newKeys = (void ** )calloc(1UL, roundedUpNewCount * sizeof(void * ))) == NULL) { returnCode = 1; goto errorExit; }
1258+ memcpy(newKeys, objectStack->keys, jk_min(objectStack->count, roundedUpNewCount) * sizeof(void *));
1259+
1260+ if((newCFHashes = (CFHashCode *)calloc(1UL, roundedUpNewCount * sizeof(CFHashCode))) == NULL) { returnCode = 1; goto errorExit; }
1261+ memcpy(newCFHashes, objectStack->cfHashes, jk_min(objectStack->count, roundedUpNewCount) * sizeof(CFHashCode));
1262+
1263+ objectStack->flags = (objectStack->flags & ~JKObjectStackLocationMask) | (JKObjectStackOnHeap | JKObjectStackMustFree);
1264+ objectStack->objects = newObjects; newObjects = NULL;
1265+ objectStack->keys = newKeys; newKeys = NULL;
1266+ objectStack->cfHashes = newCFHashes; newCFHashes = NULL;
1267+ objectStack->count = roundedUpNewCount;
1268+ } else {
1269+ NSCParameterAssert(((objectStack->flags & JKObjectStackMustFree) != 0) && ((objectStack->flags & JKObjectStackLocationMask) == JKObjectStackOnHeap));
1270+ if((newObjects = (void ** )realloc(objectStack->objects, roundedUpNewCount * sizeof(void * ))) != NULL) { objectStack->objects = newObjects; newObjects = NULL; } else { returnCode = 1; goto errorExit; }
1271+ if((newKeys = (void ** )realloc(objectStack->keys, roundedUpNewCount * sizeof(void * ))) != NULL) { objectStack->keys = newKeys; newKeys = NULL; } else { returnCode = 1; goto errorExit; }
1272+ if((newCFHashes = (CFHashCode *)realloc(objectStack->cfHashes, roundedUpNewCount * sizeof(CFHashCode))) != NULL) { objectStack->cfHashes = newCFHashes; newCFHashes = NULL; } else { returnCode = 1; goto errorExit; }
1273+
1274+#ifndef NS_BLOCK_ASSERTIONS
1275+ size_t idx;
1276+ for(idx = objectStack->count; idx < roundedUpNewCount; idx++) { objectStack->objects[idx] = NULL; objectStack->keys[idx] = NULL; objectStack->cfHashes[idx] = 0UL; }
1277+#endif
1278+ objectStack->count = roundedUpNewCount;
1279+ }
1280+ }
1281+
1282+ errorExit:
1283+ if(newObjects != NULL) { free(newObjects); newObjects = NULL; }
1284+ if(newKeys != NULL) { free(newKeys); newKeys = NULL; }
1285+ if(newCFHashes != NULL) { free(newCFHashes); newCFHashes = NULL; }
1286+
1287+ return(returnCode);
1288+}
1289+
1290+////////////
1291+#pragma mark -
1292+#pragma mark Unicode related functions
1293+
1294+JK_STATIC_INLINE ConversionResult isValidCodePoint(UTF32 *u32CodePoint) {
1295+ ConversionResult result = conversionOK;
1296+ UTF32 ch = *u32CodePoint;
1297+
1298+ if(JK_EXPECT_F(ch >= UNI_SUR_HIGH_START) && (JK_EXPECT_T(ch <= UNI_SUR_LOW_END))) { result = sourceIllegal; ch = UNI_REPLACEMENT_CHAR; goto finished; }
1299+ if(JK_EXPECT_F(ch >= 0xFDD0U) && (JK_EXPECT_F(ch <= 0xFDEFU) || JK_EXPECT_F((ch & 0xFFFEU) == 0xFFFEU)) && JK_EXPECT_T(ch <= 0x10FFFFU)) { result = sourceIllegal; ch = UNI_REPLACEMENT_CHAR; goto finished; }
1300+ if(JK_EXPECT_F(ch == 0U)) { result = sourceIllegal; ch = UNI_REPLACEMENT_CHAR; goto finished; }
1301+
1302+ finished:
1303+ *u32CodePoint = ch;
1304+ return(result);
1305+}
1306+
1307+
1308+static int isLegalUTF8(const UTF8 *source, size_t length) {
1309+ const UTF8 *srcptr = source + length;
1310+ UTF8 a;
1311+
1312+ switch(length) {
1313+ default: return(0); // Everything else falls through when "true"...
1314+ case 4: if(JK_EXPECT_F(((a = (*--srcptr)) < 0x80) || (a > 0xBF))) { return(0); }
1315+ case 3: if(JK_EXPECT_F(((a = (*--srcptr)) < 0x80) || (a > 0xBF))) { return(0); }
1316+ case 2: if(JK_EXPECT_F( (a = (*--srcptr)) > 0xBF )) { return(0); }
1317+
1318+ switch(*source) { // no fall-through in this inner switch
1319+ case 0xE0: if(JK_EXPECT_F(a < 0xA0)) { return(0); } break;
1320+ case 0xED: if(JK_EXPECT_F(a > 0x9F)) { return(0); } break;
1321+ case 0xF0: if(JK_EXPECT_F(a < 0x90)) { return(0); } break;
1322+ case 0xF4: if(JK_EXPECT_F(a > 0x8F)) { return(0); } break;
1323+ default: if(JK_EXPECT_F(a < 0x80)) { return(0); }
1324+ }
1325+
1326+ case 1: if(JK_EXPECT_F((JK_EXPECT_T(*source < 0xC2)) && JK_EXPECT_F(*source >= 0x80))) { return(0); }
1327+ }
1328+
1329+ if(JK_EXPECT_F(*source > 0xF4)) { return(0); }
1330+
1331+ return(1);
1332+}
1333+
1334+static ConversionResult ConvertSingleCodePointInUTF8(const UTF8 *sourceStart, const UTF8 *sourceEnd, UTF8 const **nextUTF8, UTF32 *convertedUTF32) {
1335+ ConversionResult result = conversionOK;
1336+ const UTF8 *source = sourceStart;
1337+ UTF32 ch = 0UL;
1338+
1339+#if !defined(JK_FAST_TRAILING_BYTES)
1340+ unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
1341+#else
1342+ unsigned short extraBytesToRead = __builtin_clz(((*source)^0xff) << 25);
1343+#endif
1344+
1345+ if(JK_EXPECT_F((source + extraBytesToRead + 1) > sourceEnd) || JK_EXPECT_F(!isLegalUTF8(source, extraBytesToRead + 1))) {
1346+ source++;
1347+ while((source < sourceEnd) && (((*source) & 0xc0) == 0x80) && ((source - sourceStart) < (extraBytesToRead + 1))) { source++; }
1348+ NSCParameterAssert(source <= sourceEnd);
1349+ result = ((source < sourceEnd) && (((*source) & 0xc0) != 0x80)) ? sourceIllegal : ((sourceStart + extraBytesToRead + 1) > sourceEnd) ? sourceExhausted : sourceIllegal;
1350+ ch = UNI_REPLACEMENT_CHAR;
1351+ goto finished;
1352+ }
1353+
1354+ switch(extraBytesToRead) { // The cases all fall through.
1355+ case 5: ch += *source++; ch <<= 6;
1356+ case 4: ch += *source++; ch <<= 6;
1357+ case 3: ch += *source++; ch <<= 6;
1358+ case 2: ch += *source++; ch <<= 6;
1359+ case 1: ch += *source++; ch <<= 6;
1360+ case 0: ch += *source++;
1361+ }
1362+ ch -= offsetsFromUTF8[extraBytesToRead];
1363+
1364+ result = isValidCodePoint(&ch);
1365+
1366+ finished:
1367+ *nextUTF8 = source;
1368+ *convertedUTF32 = ch;
1369+
1370+ return(result);
1371+}
1372+
1373+
1374+static ConversionResult ConvertUTF32toUTF8 (UTF32 u32CodePoint, UTF8 **targetStart, UTF8 *targetEnd) {
1375+ const UTF32 byteMask = 0xBF, byteMark = 0x80;
1376+ ConversionResult result = conversionOK;
1377+ UTF8 *target = *targetStart;
1378+ UTF32 ch = u32CodePoint;
1379+ unsigned short bytesToWrite = 0;
1380+
1381+ result = isValidCodePoint(&ch);
1382+
1383+ // Figure out how many bytes the result will require. Turn any illegally large UTF32 things (> Plane 17) into replacement chars.
1384+ if(ch < (UTF32)0x80) { bytesToWrite = 1; }
1385+ else if(ch < (UTF32)0x800) { bytesToWrite = 2; }
1386+ else if(ch < (UTF32)0x10000) { bytesToWrite = 3; }
1387+ else if(ch <= UNI_MAX_LEGAL_UTF32) { bytesToWrite = 4; }
1388+ else { bytesToWrite = 3; ch = UNI_REPLACEMENT_CHAR; result = sourceIllegal; }
1389+
1390+ target += bytesToWrite;
1391+ if (target > targetEnd) { target -= bytesToWrite; result = targetExhausted; goto finished; }
1392+
1393+ switch (bytesToWrite) { // note: everything falls through.
1394+ case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
1395+ case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
1396+ case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
1397+ case 1: *--target = (UTF8) (ch | firstByteMark[bytesToWrite]);
1398+ }
1399+
1400+ target += bytesToWrite;
1401+
1402+ finished:
1403+ *targetStart = target;
1404+ return(result);
1405+}
1406+
1407+JK_STATIC_INLINE int jk_string_add_unicodeCodePoint(JKParseState *parseState, uint32_t unicodeCodePoint, size_t *tokenBufferIdx, JKHash *stringHash) {
1408+ UTF8 *u8s = &parseState->token.tokenBuffer.bytes.ptr[*tokenBufferIdx];
1409+ ConversionResult result;
1410+
1411+ if((result = ConvertUTF32toUTF8(unicodeCodePoint, &u8s, (parseState->token.tokenBuffer.bytes.ptr + parseState->token.tokenBuffer.bytes.length))) != conversionOK) { if(result == targetExhausted) { return(1); } }
1412+ size_t utf8len = u8s - &parseState->token.tokenBuffer.bytes.ptr[*tokenBufferIdx], nextIdx = (*tokenBufferIdx) + utf8len;
1413+
1414+ while(*tokenBufferIdx < nextIdx) { *stringHash = jk_calculateHash(*stringHash, parseState->token.tokenBuffer.bytes.ptr[(*tokenBufferIdx)++]); }
1415+
1416+ return(0);
1417+}
1418+
1419+////////////
1420+#pragma mark -
1421+#pragma mark Decoding / parsing / deserializing functions
1422+
1423+static int jk_parse_string(JKParseState *parseState) {
1424+ NSCParameterAssert((parseState != NULL) && (JK_AT_STRING_PTR(parseState) <= JK_END_STRING_PTR(parseState)));
1425+ const unsigned char *stringStart = JK_AT_STRING_PTR(parseState) + 1;
1426+ const unsigned char *endOfBuffer = JK_END_STRING_PTR(parseState);
1427+ const unsigned char *atStringCharacter = stringStart;
1428+ unsigned char *tokenBuffer = parseState->token.tokenBuffer.bytes.ptr;
1429+ size_t tokenStartIndex = parseState->atIndex;
1430+ size_t tokenBufferIdx = 0UL;
1431+
1432+ int onlySimpleString = 1, stringState = JSONStringStateStart;
1433+ uint16_t escapedUnicode1 = 0U, escapedUnicode2 = 0U;
1434+ uint32_t escapedUnicodeCodePoint = 0U;
1435+ JKHash stringHash = JK_HASH_INIT;
1436+
1437+ while(1) {
1438+ unsigned long currentChar;
1439+
1440+ if(JK_EXPECT_F(atStringCharacter == endOfBuffer)) { /* XXX Add error message */ stringState = JSONStringStateError; goto finishedParsing; }
1441+
1442+ if(JK_EXPECT_F((currentChar = *atStringCharacter++) >= 0x80UL)) {
1443+ const unsigned char *nextValidCharacter = NULL;
1444+ UTF32 u32ch = 0U;
1445+ ConversionResult result;
1446+
1447+ if(JK_EXPECT_F((result = ConvertSingleCodePointInUTF8(atStringCharacter - 1, endOfBuffer, (UTF8 const **)&nextValidCharacter, &u32ch)) != conversionOK)) { goto switchToSlowPath; }
1448+ stringHash = jk_calculateHash(stringHash, currentChar);
1449+ while(atStringCharacter < nextValidCharacter) { NSCParameterAssert(JK_AT_STRING_PTR(parseState) <= JK_END_STRING_PTR(parseState)); stringHash = jk_calculateHash(stringHash, *atStringCharacter++); }
1450+ continue;
1451+ } else {
1452+ if(JK_EXPECT_F(currentChar == (unsigned long)'"')) { stringState = JSONStringStateFinished; goto finishedParsing; }
1453+
1454+ if(JK_EXPECT_F(currentChar == (unsigned long)'\\')) {
1455+ switchToSlowPath:
1456+ onlySimpleString = 0;
1457+ stringState = JSONStringStateParsing;
1458+ tokenBufferIdx = (atStringCharacter - stringStart) - 1L;
1459+ if(JK_EXPECT_F((tokenBufferIdx + 16UL) > parseState->token.tokenBuffer.bytes.length)) { if((tokenBuffer = jk_managedBuffer_resize(&parseState->token.tokenBuffer, tokenBufferIdx + 1024UL)) == NULL) { jk_error(parseState, @"Internal error: Unable to resize temporary buffer. %@ line #%ld", [NSString stringWithUTF8String:__FILE__], (long)__LINE__); stringState = JSONStringStateError; goto finishedParsing; } }
1460+ memcpy(tokenBuffer, stringStart, tokenBufferIdx);
1461+ goto slowMatch;
1462+ }
1463+
1464+ if(JK_EXPECT_F(currentChar < 0x20UL)) { jk_error(parseState, @"Invalid character < 0x20 found in string: 0x%2.2x.", currentChar); stringState = JSONStringStateError; goto finishedParsing; }
1465+
1466+ stringHash = jk_calculateHash(stringHash, currentChar);
1467+ }
1468+ }
1469+
1470+ slowMatch:
1471+
1472+ for(atStringCharacter = (stringStart + ((atStringCharacter - stringStart) - 1L)); (atStringCharacter < endOfBuffer) && (tokenBufferIdx < parseState->token.tokenBuffer.bytes.length); atStringCharacter++) {
1473+ if((tokenBufferIdx + 16UL) > parseState->token.tokenBuffer.bytes.length) { if((tokenBuffer = jk_managedBuffer_resize(&parseState->token.tokenBuffer, tokenBufferIdx + 1024UL)) == NULL) { jk_error(parseState, @"Internal error: Unable to resize temporary buffer. %@ line #%ld", [NSString stringWithUTF8String:__FILE__], (long)__LINE__); stringState = JSONStringStateError; goto finishedParsing; } }
1474+
1475+ NSCParameterAssert(tokenBufferIdx < parseState->token.tokenBuffer.bytes.length);
1476+
1477+ unsigned long currentChar = (*atStringCharacter), escapedChar;
1478+
1479+ if(JK_EXPECT_T(stringState == JSONStringStateParsing)) {
1480+ if(JK_EXPECT_T(currentChar >= 0x20UL)) {
1481+ if(JK_EXPECT_T(currentChar < (unsigned long)0x80)) { // Not a UTF8 sequence
1482+ if(JK_EXPECT_F(currentChar == (unsigned long)'"')) { stringState = JSONStringStateFinished; atStringCharacter++; goto finishedParsing; }
1483+ if(JK_EXPECT_F(currentChar == (unsigned long)'\\')) { stringState = JSONStringStateEscape; continue; }
1484+ stringHash = jk_calculateHash(stringHash, currentChar);
1485+ tokenBuffer[tokenBufferIdx++] = currentChar;
1486+ continue;
1487+ } else { // UTF8 sequence
1488+ const unsigned char *nextValidCharacter = NULL;
1489+ UTF32 u32ch = 0U;
1490+ ConversionResult result;
1491+
1492+ if(JK_EXPECT_F((result = ConvertSingleCodePointInUTF8(atStringCharacter, endOfBuffer, (UTF8 const **)&nextValidCharacter, &u32ch)) != conversionOK)) {
1493+ if((result == sourceIllegal) && ((parseState->parseOptionFlags & JKParseOptionLooseUnicode) == 0)) { jk_error(parseState, @"Illegal UTF8 sequence found in \"\" string."); stringState = JSONStringStateError; goto finishedParsing; }
1494+ if(result == sourceExhausted) { jk_error(parseState, @"End of buffer reached while parsing UTF8 in \"\" string."); stringState = JSONStringStateError; goto finishedParsing; }
1495+ if(jk_string_add_unicodeCodePoint(parseState, u32ch, &tokenBufferIdx, &stringHash)) { jk_error(parseState, @"Internal error: Unable to add UTF8 sequence to internal string buffer. %@ line #%ld", [NSString stringWithUTF8String:__FILE__], (long)__LINE__); stringState = JSONStringStateError; goto finishedParsing; }
1496+ atStringCharacter = nextValidCharacter - 1;
1497+ continue;
1498+ } else {
1499+ while(atStringCharacter < nextValidCharacter) { tokenBuffer[tokenBufferIdx++] = *atStringCharacter; stringHash = jk_calculateHash(stringHash, *atStringCharacter++); }
1500+ atStringCharacter--;
1501+ continue;
1502+ }
1503+ }
1504+ } else { // currentChar < 0x20
1505+ jk_error(parseState, @"Invalid character < 0x20 found in string: 0x%2.2x.", currentChar); stringState = JSONStringStateError; goto finishedParsing;
1506+ }
1507+
1508+ } else { // stringState != JSONStringStateParsing
1509+ int isSurrogate = 1;
1510+
1511+ switch(stringState) {
1512+ case JSONStringStateEscape:
1513+ switch(currentChar) {
1514+ case 'u': escapedUnicode1 = 0U; escapedUnicode2 = 0U; escapedUnicodeCodePoint = 0U; stringState = JSONStringStateEscapedUnicode1; break;
1515+
1516+ case 'b': escapedChar = '\b'; goto parsedEscapedChar;
1517+ case 'f': escapedChar = '\f'; goto parsedEscapedChar;
1518+ case 'n': escapedChar = '\n'; goto parsedEscapedChar;
1519+ case 'r': escapedChar = '\r'; goto parsedEscapedChar;
1520+ case 't': escapedChar = '\t'; goto parsedEscapedChar;
1521+ case '\\': escapedChar = '\\'; goto parsedEscapedChar;
1522+ case '/': escapedChar = '/'; goto parsedEscapedChar;
1523+ case '"': escapedChar = '"'; goto parsedEscapedChar;
1524+
1525+ parsedEscapedChar:
1526+ stringState = JSONStringStateParsing;
1527+ stringHash = jk_calculateHash(stringHash, escapedChar);
1528+ tokenBuffer[tokenBufferIdx++] = escapedChar;
1529+ break;
1530+
1531+ default: jk_error(parseState, @"Invalid escape sequence found in \"\" string."); stringState = JSONStringStateError; goto finishedParsing; break;
1532+ }
1533+ break;
1534+
1535+ case JSONStringStateEscapedUnicode1:
1536+ case JSONStringStateEscapedUnicode2:
1537+ case JSONStringStateEscapedUnicode3:
1538+ case JSONStringStateEscapedUnicode4: isSurrogate = 0;
1539+ case JSONStringStateEscapedUnicodeSurrogate1:
1540+ case JSONStringStateEscapedUnicodeSurrogate2:
1541+ case JSONStringStateEscapedUnicodeSurrogate3:
1542+ case JSONStringStateEscapedUnicodeSurrogate4:
1543+ {
1544+ uint16_t hexValue = 0U;
1545+
1546+ switch(currentChar) {
1547+ case '0' ... '9': hexValue = currentChar - '0'; goto parsedHex;
1548+ case 'a' ... 'f': hexValue = (currentChar - 'a') + 10U; goto parsedHex;
1549+ case 'A' ... 'F': hexValue = (currentChar - 'A') + 10U; goto parsedHex;
1550+
1551+ parsedHex:
1552+ if(!isSurrogate) { escapedUnicode1 = (escapedUnicode1 << 4) | hexValue; } else { escapedUnicode2 = (escapedUnicode2 << 4) | hexValue; }
1553+
1554+ if(stringState == JSONStringStateEscapedUnicode4) {
1555+ if(((escapedUnicode1 >= 0xD800U) && (escapedUnicode1 < 0xE000U))) {
1556+ if((escapedUnicode1 >= 0xD800U) && (escapedUnicode1 < 0xDC00U)) { stringState = JSONStringStateEscapedNeedEscapeForSurrogate; }
1557+ else if((escapedUnicode1 >= 0xDC00U) && (escapedUnicode1 < 0xE000U)) {
1558+ if((parseState->parseOptionFlags & JKParseOptionLooseUnicode)) { escapedUnicodeCodePoint = UNI_REPLACEMENT_CHAR; }
1559+ else { jk_error(parseState, @"Illegal \\u Unicode escape sequence."); stringState = JSONStringStateError; goto finishedParsing; }
1560+ }
1561+ }
1562+ else { escapedUnicodeCodePoint = escapedUnicode1; }
1563+ }
1564+
1565+ if(stringState == JSONStringStateEscapedUnicodeSurrogate4) {
1566+ if((escapedUnicode2 < 0xdc00) || (escapedUnicode2 > 0xdfff)) {
1567+ if((parseState->parseOptionFlags & JKParseOptionLooseUnicode)) { escapedUnicodeCodePoint = UNI_REPLACEMENT_CHAR; }
1568+ else { jk_error(parseState, @"Illegal \\u Unicode escape sequence."); stringState = JSONStringStateError; goto finishedParsing; }
1569+ }
1570+ else { escapedUnicodeCodePoint = ((escapedUnicode1 - 0xd800) * 0x400) + (escapedUnicode2 - 0xdc00) + 0x10000; }
1571+ }
1572+
1573+ if((stringState == JSONStringStateEscapedUnicode4) || (stringState == JSONStringStateEscapedUnicodeSurrogate4)) {
1574+ if((isValidCodePoint(&escapedUnicodeCodePoint) == sourceIllegal) && ((parseState->parseOptionFlags & JKParseOptionLooseUnicode) == 0)) { jk_error(parseState, @"Illegal \\u Unicode escape sequence."); stringState = JSONStringStateError; goto finishedParsing; }
1575+ stringState = JSONStringStateParsing;
1576+ if(jk_string_add_unicodeCodePoint(parseState, escapedUnicodeCodePoint, &tokenBufferIdx, &stringHash)) { jk_error(parseState, @"Internal error: Unable to add UTF8 sequence to internal string buffer. %@ line #%ld", [NSString stringWithUTF8String:__FILE__], (long)__LINE__); stringState = JSONStringStateError; goto finishedParsing; }
1577+ }
1578+ else if((stringState >= JSONStringStateEscapedUnicode1) && (stringState <= JSONStringStateEscapedUnicodeSurrogate4)) { stringState++; }
1579+ break;
1580+
1581+ default: jk_error(parseState, @"Unexpected character found in \\u Unicode escape sequence. Found '%c', expected [0-9a-fA-F].", currentChar); stringState = JSONStringStateError; goto finishedParsing; break;
1582+ }
1583+ }
1584+ break;
1585+
1586+ case JSONStringStateEscapedNeedEscapeForSurrogate:
1587+ if(currentChar == '\\') { stringState = JSONStringStateEscapedNeedEscapedUForSurrogate; }
1588+ else {
1589+ if((parseState->parseOptionFlags & JKParseOptionLooseUnicode) == 0) { jk_error(parseState, @"Required a second \\u Unicode escape sequence following a surrogate \\u Unicode escape sequence."); stringState = JSONStringStateError; goto finishedParsing; }
1590+ else { stringState = JSONStringStateParsing; atStringCharacter--; if(jk_string_add_unicodeCodePoint(parseState, UNI_REPLACEMENT_CHAR, &tokenBufferIdx, &stringHash)) { jk_error(parseState, @"Internal error: Unable to add UTF8 sequence to internal string buffer. %@ line #%ld", [NSString stringWithUTF8String:__FILE__], (long)__LINE__); stringState = JSONStringStateError; goto finishedParsing; } }
1591+ }
1592+ break;
1593+
1594+ case JSONStringStateEscapedNeedEscapedUForSurrogate:
1595+ if(currentChar == 'u') { stringState = JSONStringStateEscapedUnicodeSurrogate1; }
1596+ else {
1597+ if((parseState->parseOptionFlags & JKParseOptionLooseUnicode) == 0) { jk_error(parseState, @"Required a second \\u Unicode escape sequence following a surrogate \\u Unicode escape sequence."); stringState = JSONStringStateError; goto finishedParsing; }
1598+ else { stringState = JSONStringStateParsing; atStringCharacter -= 2; if(jk_string_add_unicodeCodePoint(parseState, UNI_REPLACEMENT_CHAR, &tokenBufferIdx, &stringHash)) { jk_error(parseState, @"Internal error: Unable to add UTF8 sequence to internal string buffer. %@ line #%ld", [NSString stringWithUTF8String:__FILE__], (long)__LINE__); stringState = JSONStringStateError; goto finishedParsing; } }
1599+ }
1600+ break;
1601+
1602+ default: jk_error(parseState, @"Internal error: Unknown stringState. %@ line #%ld", [NSString stringWithUTF8String:__FILE__], (long)__LINE__); stringState = JSONStringStateError; goto finishedParsing; break;
1603+ }
1604+ }
1605+ }
1606+
1607+finishedParsing:
1608+
1609+ if(JK_EXPECT_T(stringState == JSONStringStateFinished)) {
1610+ NSCParameterAssert((parseState->stringBuffer.bytes.ptr + tokenStartIndex) < atStringCharacter);
1611+
1612+ parseState->token.tokenPtrRange.ptr = parseState->stringBuffer.bytes.ptr + tokenStartIndex;
1613+ parseState->token.tokenPtrRange.length = (atStringCharacter - parseState->token.tokenPtrRange.ptr);
1614+
1615+ if(JK_EXPECT_T(onlySimpleString)) {
1616+ NSCParameterAssert(((parseState->token.tokenPtrRange.ptr + 1) < endOfBuffer) && (parseState->token.tokenPtrRange.length >= 2UL) && (((parseState->token.tokenPtrRange.ptr + 1) + (parseState->token.tokenPtrRange.length - 2)) < endOfBuffer));
1617+ parseState->token.value.ptrRange.ptr = parseState->token.tokenPtrRange.ptr + 1;
1618+ parseState->token.value.ptrRange.length = parseState->token.tokenPtrRange.length - 2UL;
1619+ } else {
1620+ parseState->token.value.ptrRange.ptr = parseState->token.tokenBuffer.bytes.ptr;
1621+ parseState->token.value.ptrRange.length = tokenBufferIdx;
1622+ }
1623+
1624+ parseState->token.value.hash = stringHash;
1625+ parseState->token.value.type = JKValueTypeString;
1626+ parseState->atIndex = (atStringCharacter - parseState->stringBuffer.bytes.ptr);
1627+ }
1628+
1629+ if(JK_EXPECT_F(stringState != JSONStringStateFinished)) { jk_error(parseState, @"Invalid string."); }
1630+ return(JK_EXPECT_T(stringState == JSONStringStateFinished) ? 0 : 1);
1631+}
1632+
1633+static int jk_parse_number(JKParseState *parseState) {
1634+ NSCParameterAssert((parseState != NULL) && (JK_AT_STRING_PTR(parseState) <= JK_END_STRING_PTR(parseState)));
1635+ const unsigned char *numberStart = JK_AT_STRING_PTR(parseState);
1636+ const unsigned char *endOfBuffer = JK_END_STRING_PTR(parseState);
1637+ const unsigned char *atNumberCharacter = NULL;
1638+ int numberState = JSONNumberStateWholeNumberStart, isFloatingPoint = 0, isNegative = 0, backup = 0;
1639+ size_t startingIndex = parseState->atIndex;
1640+
1641+ for(atNumberCharacter = numberStart; (JK_EXPECT_T(atNumberCharacter < endOfBuffer)) && (JK_EXPECT_T(!(JK_EXPECT_F(numberState == JSONNumberStateFinished) || JK_EXPECT_F(numberState == JSONNumberStateError)))); atNumberCharacter++) {
1642+ unsigned long currentChar = (unsigned long)(*atNumberCharacter), lowerCaseCC = currentChar | 0x20UL;
1643+
1644+ switch(numberState) {
1645+ case JSONNumberStateWholeNumberStart: if (currentChar == '-') { numberState = JSONNumberStateWholeNumberMinus; isNegative = 1; break; }
1646+ case JSONNumberStateWholeNumberMinus: if (currentChar == '0') { numberState = JSONNumberStateWholeNumberZero; break; }
1647+ else if( (currentChar >= '1') && (currentChar <= '9')) { numberState = JSONNumberStateWholeNumber; break; }
1648+ else { /* XXX Add error message */ numberState = JSONNumberStateError; break; }
1649+ case JSONNumberStateExponentStart: if( (currentChar == '+') || (currentChar == '-')) { numberState = JSONNumberStateExponentPlusMinus; break; }
1650+ case JSONNumberStateFractionalNumberStart:
1651+ case JSONNumberStateExponentPlusMinus:if(!((currentChar >= '0') && (currentChar <= '9'))) { /* XXX Add error message */ numberState = JSONNumberStateError; break; }
1652+ else { if(numberState == JSONNumberStateFractionalNumberStart) { numberState = JSONNumberStateFractionalNumber; }
1653+ else { numberState = JSONNumberStateExponent; } break; }
1654+ case JSONNumberStateWholeNumberZero:
1655+ case JSONNumberStateWholeNumber: if (currentChar == '.') { numberState = JSONNumberStateFractionalNumberStart; isFloatingPoint = 1; break; }
1656+ case JSONNumberStateFractionalNumber: if (lowerCaseCC == 'e') { numberState = JSONNumberStateExponentStart; isFloatingPoint = 1; break; }
1657+ case JSONNumberStateExponent: if(!((currentChar >= '0') && (currentChar <= '9')) || (numberState == JSONNumberStateWholeNumberZero)) { numberState = JSONNumberStateFinished; backup = 1; break; }
1658+ break;
1659+ default: /* XXX Add error message */ numberState = JSONNumberStateError; break;
1660+ }
1661+ }
1662+
1663+ parseState->token.tokenPtrRange.ptr = parseState->stringBuffer.bytes.ptr + startingIndex;
1664+ parseState->token.tokenPtrRange.length = (atNumberCharacter - parseState->token.tokenPtrRange.ptr) - backup;
1665+ parseState->atIndex = (parseState->token.tokenPtrRange.ptr + parseState->token.tokenPtrRange.length) - parseState->stringBuffer.bytes.ptr;
1666+
1667+ if(JK_EXPECT_T(numberState == JSONNumberStateFinished)) {
1668+ unsigned char numberTempBuf[parseState->token.tokenPtrRange.length + 4UL];
1669+ unsigned char *endOfNumber = NULL;
1670+
1671+ memcpy(numberTempBuf, parseState->token.tokenPtrRange.ptr, parseState->token.tokenPtrRange.length);
1672+ numberTempBuf[parseState->token.tokenPtrRange.length] = 0;
1673+
1674+ errno = 0;
1675+
1676+ // Treat "-0" as a floating point number, which is capable of representing negative zeros.
1677+ if(JK_EXPECT_F(parseState->token.tokenPtrRange.length == 2UL) && JK_EXPECT_F(numberTempBuf[1] == '0') && JK_EXPECT_F(isNegative)) { isFloatingPoint = 1; }
1678+
1679+ if(isFloatingPoint) {
1680+ parseState->token.value.number.doubleValue = strtod((const char *)numberTempBuf, (char **)&endOfNumber); // strtod is documented to return U+2261 (identical to) 0.0 on an underflow error (along with setting errno to ERANGE).
1681+ parseState->token.value.type = JKValueTypeDouble;
1682+ parseState->token.value.ptrRange.ptr = (const unsigned char *)&parseState->token.value.number.doubleValue;
1683+ parseState->token.value.ptrRange.length = sizeof(double);
1684+ parseState->token.value.hash = (JK_HASH_INIT + parseState->token.value.type);
1685+ } else {
1686+ if(isNegative) {
1687+ parseState->token.value.number.longLongValue = strtoll((const char *)numberTempBuf, (char **)&endOfNumber, 10);
1688+ parseState->token.value.type = JKValueTypeLongLong;
1689+ parseState->token.value.ptrRange.ptr = (const unsigned char *)&parseState->token.value.number.longLongValue;
1690+ parseState->token.value.ptrRange.length = sizeof(long long);
1691+ parseState->token.value.hash = (JK_HASH_INIT + parseState->token.value.type) + (JKHash)parseState->token.value.number.longLongValue;
1692+ } else {
1693+ parseState->token.value.number.unsignedLongLongValue = strtoull((const char *)numberTempBuf, (char **)&endOfNumber, 10);
1694+ parseState->token.value.type = JKValueTypeUnsignedLongLong;
1695+ parseState->token.value.ptrRange.ptr = (const unsigned char *)&parseState->token.value.number.unsignedLongLongValue;
1696+ parseState->token.value.ptrRange.length = sizeof(unsigned long long);
1697+ parseState->token.value.hash = (JK_HASH_INIT + parseState->token.value.type) + (JKHash)parseState->token.value.number.unsignedLongLongValue;
1698+ }
1699+ }
1700+
1701+ if(JK_EXPECT_F(errno != 0)) {
1702+ numberState = JSONNumberStateError;
1703+ if(errno == ERANGE) {
1704+ switch(parseState->token.value.type) {
1705+ case JKValueTypeDouble: jk_error(parseState, @"The value '%s' could not be represented as a 'double' due to %s.", numberTempBuf, (parseState->token.value.number.doubleValue == 0.0) ? "underflow" : "overflow"); break; // see above for == 0.0.
1706+ case JKValueTypeLongLong: jk_error(parseState, @"The value '%s' exceeded the minimum value that could be represented: %lld.", numberTempBuf, parseState->token.value.number.longLongValue); break;
1707+ case JKValueTypeUnsignedLongLong: jk_error(parseState, @"The value '%s' exceeded the maximum value that could be represented: %llu.", numberTempBuf, parseState->token.value.number.unsignedLongLongValue); break;
1708+ default: jk_error(parseState, @"Internal error: Unknown token value type. %@ line #%ld", [NSString stringWithUTF8String:__FILE__], (long)__LINE__); break;
1709+ }
1710+ }
1711+ }
1712+ if(JK_EXPECT_F(endOfNumber != &numberTempBuf[parseState->token.tokenPtrRange.length]) && JK_EXPECT_F(numberState != JSONNumberStateError)) { numberState = JSONNumberStateError; jk_error(parseState, @"The conversion function did not consume all of the number tokens characters."); }
1713+
1714+ size_t hashIndex = 0UL;
1715+ for(hashIndex = 0UL; hashIndex < parseState->token.value.ptrRange.length; hashIndex++) { parseState->token.value.hash = jk_calculateHash(parseState->token.value.hash, parseState->token.value.ptrRange.ptr[hashIndex]); }
1716+ }
1717+
1718+ if(JK_EXPECT_F(numberState != JSONNumberStateFinished)) { jk_error(parseState, @"Invalid number."); }
1719+ return(JK_EXPECT_T((numberState == JSONNumberStateFinished)) ? 0 : 1);
1720+}
1721+
1722+JK_STATIC_INLINE void jk_set_parsed_token(JKParseState *parseState, const unsigned char *ptr, size_t length, JKTokenType type, size_t advanceBy) {
1723+ parseState->token.tokenPtrRange.ptr = ptr;
1724+ parseState->token.tokenPtrRange.length = length;
1725+ parseState->token.type = type;
1726+ parseState->atIndex += advanceBy;
1727+}
1728+
1729+static size_t jk_parse_is_newline(JKParseState *parseState, const unsigned char *atCharacterPtr) {
1730+ NSCParameterAssert((parseState != NULL) && (atCharacterPtr != NULL) && (atCharacterPtr >= parseState->stringBuffer.bytes.ptr) && (atCharacterPtr < JK_END_STRING_PTR(parseState)));
1731+ const unsigned char *endOfStringPtr = JK_END_STRING_PTR(parseState);
1732+
1733+ if(JK_EXPECT_F(atCharacterPtr >= endOfStringPtr)) { return(0UL); }
1734+
1735+ if(JK_EXPECT_F((*(atCharacterPtr + 0)) == '\n')) { return(1UL); }
1736+ if(JK_EXPECT_F((*(atCharacterPtr + 0)) == '\r')) { if((JK_EXPECT_T((atCharacterPtr + 1) < endOfStringPtr)) && ((*(atCharacterPtr + 1)) == '\n')) { return(2UL); } return(1UL); }
1737+ if(parseState->parseOptionFlags & JKParseOptionUnicodeNewlines) {
1738+ if((JK_EXPECT_F((*(atCharacterPtr + 0)) == 0xc2)) && (((atCharacterPtr + 1) < endOfStringPtr) && ((*(atCharacterPtr + 1)) == 0x85))) { return(2UL); }
1739+ if((JK_EXPECT_F((*(atCharacterPtr + 0)) == 0xe2)) && (((atCharacterPtr + 2) < endOfStringPtr) && ((*(atCharacterPtr + 1)) == 0x80) && (((*(atCharacterPtr + 2)) == 0xa8) || ((*(atCharacterPtr + 2)) == 0xa9)))) { return(3UL); }
1740+ }
1741+
1742+ return(0UL);
1743+}
1744+
1745+JK_STATIC_INLINE int jk_parse_skip_newline(JKParseState *parseState) {
1746+ size_t newlineAdvanceAtIndex = 0UL;
1747+ if(JK_EXPECT_F((newlineAdvanceAtIndex = jk_parse_is_newline(parseState, JK_AT_STRING_PTR(parseState))) > 0UL)) { parseState->lineNumber++; parseState->atIndex += (newlineAdvanceAtIndex - 1UL); parseState->lineStartIndex = parseState->atIndex + 1UL; return(1); }
1748+ return(0);
1749+}
1750+
1751+JK_STATIC_INLINE void jk_parse_skip_whitespace(JKParseState *parseState) {
1752+#ifndef __clang_analyzer__
1753+ NSCParameterAssert((parseState != NULL) && (JK_AT_STRING_PTR(parseState) <= JK_END_STRING_PTR(parseState)));
1754+ const unsigned char *atCharacterPtr = NULL;
1755+ const unsigned char *endOfStringPtr = JK_END_STRING_PTR(parseState);
1756+
1757+ for(atCharacterPtr = JK_AT_STRING_PTR(parseState); (JK_EXPECT_T((atCharacterPtr = JK_AT_STRING_PTR(parseState)) < endOfStringPtr)); parseState->atIndex++) {
1758+ if(((*(atCharacterPtr + 0)) == ' ') || ((*(atCharacterPtr + 0)) == '\t')) { continue; }
1759+ if(jk_parse_skip_newline(parseState)) { continue; }
1760+ if(parseState->parseOptionFlags & JKParseOptionComments) {
1761+ if((JK_EXPECT_F((*(atCharacterPtr + 0)) == '/')) && (JK_EXPECT_T((atCharacterPtr + 1) < endOfStringPtr))) {
1762+ if((*(atCharacterPtr + 1)) == '/') {
1763+ parseState->atIndex++;
1764+ for(atCharacterPtr = JK_AT_STRING_PTR(parseState); (JK_EXPECT_T((atCharacterPtr = JK_AT_STRING_PTR(parseState)) < endOfStringPtr)); parseState->atIndex++) { if(jk_parse_skip_newline(parseState)) { break; } }
1765+ continue;
1766+ }
1767+ if((*(atCharacterPtr + 1)) == '*') {
1768+ parseState->atIndex++;
1769+ for(atCharacterPtr = JK_AT_STRING_PTR(parseState); (JK_EXPECT_T((atCharacterPtr = JK_AT_STRING_PTR(parseState)) < endOfStringPtr)); parseState->atIndex++) {
1770+ if(jk_parse_skip_newline(parseState)) { continue; }
1771+ if(((*(atCharacterPtr + 0)) == '*') && (((atCharacterPtr + 1) < endOfStringPtr) && ((*(atCharacterPtr + 1)) == '/'))) { parseState->atIndex++; break; }
1772+ }
1773+ continue;
1774+ }
1775+ }
1776+ }
1777+ break;
1778+ }
1779+#endif
1780+}
1781+
1782+static int jk_parse_next_token(JKParseState *parseState) {
1783+ NSCParameterAssert((parseState != NULL) && (JK_AT_STRING_PTR(parseState) <= JK_END_STRING_PTR(parseState)));
1784+ const unsigned char *atCharacterPtr = NULL;
1785+ const unsigned char *endOfStringPtr = JK_END_STRING_PTR(parseState);
1786+ unsigned char currentCharacter = 0U;
1787+ int stopParsing = 0;
1788+
1789+ parseState->prev_atIndex = parseState->atIndex;
1790+ parseState->prev_lineNumber = parseState->lineNumber;
1791+ parseState->prev_lineStartIndex = parseState->lineStartIndex;
1792+
1793+ jk_parse_skip_whitespace(parseState);
1794+
1795+ if((JK_AT_STRING_PTR(parseState) == endOfStringPtr)) { stopParsing = 1; }
1796+
1797+ if((JK_EXPECT_T(stopParsing == 0)) && (JK_EXPECT_T((atCharacterPtr = JK_AT_STRING_PTR(parseState)) < endOfStringPtr))) {
1798+ currentCharacter = *atCharacterPtr;
1799+
1800+ if(JK_EXPECT_T(currentCharacter == '"')) { if(JK_EXPECT_T((stopParsing = jk_parse_string(parseState)) == 0)) { jk_set_parsed_token(parseState, parseState->token.tokenPtrRange.ptr, parseState->token.tokenPtrRange.length, JKTokenTypeString, 0UL); } }
1801+ else if(JK_EXPECT_T(currentCharacter == ':')) { jk_set_parsed_token(parseState, atCharacterPtr, 1UL, JKTokenTypeSeparator, 1UL); }
1802+ else if(JK_EXPECT_T(currentCharacter == ',')) { jk_set_parsed_token(parseState, atCharacterPtr, 1UL, JKTokenTypeComma, 1UL); }
1803+ else if((JK_EXPECT_T(currentCharacter >= '0') && JK_EXPECT_T(currentCharacter <= '9')) || JK_EXPECT_T(currentCharacter == '-')) { if(JK_EXPECT_T((stopParsing = jk_parse_number(parseState)) == 0)) { jk_set_parsed_token(parseState, parseState->token.tokenPtrRange.ptr, parseState->token.tokenPtrRange.length, JKTokenTypeNumber, 0UL); } }
1804+ else if(JK_EXPECT_T(currentCharacter == '{')) { jk_set_parsed_token(parseState, atCharacterPtr, 1UL, JKTokenTypeObjectBegin, 1UL); }
1805+ else if(JK_EXPECT_T(currentCharacter == '}')) { jk_set_parsed_token(parseState, atCharacterPtr, 1UL, JKTokenTypeObjectEnd, 1UL); }
1806+ else if(JK_EXPECT_T(currentCharacter == '[')) { jk_set_parsed_token(parseState, atCharacterPtr, 1UL, JKTokenTypeArrayBegin, 1UL); }
1807+ else if(JK_EXPECT_T(currentCharacter == ']')) { jk_set_parsed_token(parseState, atCharacterPtr, 1UL, JKTokenTypeArrayEnd, 1UL); }
1808+
1809+ else if(JK_EXPECT_T(currentCharacter == 't')) { if(!((JK_EXPECT_T((atCharacterPtr + 4UL) < endOfStringPtr)) && (JK_EXPECT_T(atCharacterPtr[1] == 'r')) && (JK_EXPECT_T(atCharacterPtr[2] == 'u')) && (JK_EXPECT_T(atCharacterPtr[3] == 'e')))) { stopParsing = 1; /* XXX Add error message */ } else { jk_set_parsed_token(parseState, atCharacterPtr, 4UL, JKTokenTypeTrue, 4UL); } }
1810+ else if(JK_EXPECT_T(currentCharacter == 'f')) { if(!((JK_EXPECT_T((atCharacterPtr + 5UL) < endOfStringPtr)) && (JK_EXPECT_T(atCharacterPtr[1] == 'a')) && (JK_EXPECT_T(atCharacterPtr[2] == 'l')) && (JK_EXPECT_T(atCharacterPtr[3] == 's')) && (JK_EXPECT_T(atCharacterPtr[4] == 'e')))) { stopParsing = 1; /* XXX Add error message */ } else { jk_set_parsed_token(parseState, atCharacterPtr, 5UL, JKTokenTypeFalse, 5UL); } }
1811+ else if(JK_EXPECT_T(currentCharacter == 'n')) { if(!((JK_EXPECT_T((atCharacterPtr + 4UL) < endOfStringPtr)) && (JK_EXPECT_T(atCharacterPtr[1] == 'u')) && (JK_EXPECT_T(atCharacterPtr[2] == 'l')) && (JK_EXPECT_T(atCharacterPtr[3] == 'l')))) { stopParsing = 1; /* XXX Add error message */ } else { jk_set_parsed_token(parseState, atCharacterPtr, 4UL, JKTokenTypeNull, 4UL); } }
1812+ else { stopParsing = 1; /* XXX Add error message */ }
1813+ }
1814+
1815+ if(JK_EXPECT_F(stopParsing)) { jk_error(parseState, @"Unexpected token, wanted '{', '}', '[', ']', ',', ':', 'true', 'false', 'null', '\"STRING\"', 'NUMBER'."); }
1816+ return(stopParsing);
1817+}
1818+
1819+static void jk_error_parse_accept_or3(JKParseState *parseState, int state, NSString *or1String, NSString *or2String, NSString *or3String) {
1820+ NSString *acceptStrings[16];
1821+ int acceptIdx = 0;
1822+ if(state & JKParseAcceptValue) { acceptStrings[acceptIdx++] = or1String; }
1823+ if(state & JKParseAcceptComma) { acceptStrings[acceptIdx++] = or2String; }
1824+ if(state & JKParseAcceptEnd) { acceptStrings[acceptIdx++] = or3String; }
1825+ if(acceptIdx == 1) { jk_error(parseState, @"Expected %@, not '%*.*s'", acceptStrings[0], (int)parseState->token.tokenPtrRange.length, (int)parseState->token.tokenPtrRange.length, parseState->token.tokenPtrRange.ptr); }
1826+ else if(acceptIdx == 2) { jk_error(parseState, @"Expected %@ or %@, not '%*.*s'", acceptStrings[0], acceptStrings[1], (int)parseState->token.tokenPtrRange.length, (int)parseState->token.tokenPtrRange.length, parseState->token.tokenPtrRange.ptr); }
1827+ else if(acceptIdx == 3) { jk_error(parseState, @"Expected %@, %@, or %@, not '%*.*s", acceptStrings[0], acceptStrings[1], acceptStrings[2], (int)parseState->token.tokenPtrRange.length, (int)parseState->token.tokenPtrRange.length, parseState->token.tokenPtrRange.ptr); }
1828+}
1829+
1830+static void *jk_parse_array(JKParseState *parseState) {
1831+ size_t startingObjectIndex = parseState->objectStack.index;
1832+ int arrayState = JKParseAcceptValueOrEnd, stopParsing = 0;
1833+ void *parsedArray = NULL;
1834+
1835+ while(JK_EXPECT_T((JK_EXPECT_T(stopParsing == 0)) && (JK_EXPECT_T(parseState->atIndex < parseState->stringBuffer.bytes.length)))) {
1836+ if(JK_EXPECT_F(parseState->objectStack.index > (parseState->objectStack.count - 4UL))) { if(jk_objectStack_resize(&parseState->objectStack, parseState->objectStack.count + 128UL)) { jk_error(parseState, @"Internal error: [array] objectsIndex > %zu, resize failed? %@ line %#ld", (parseState->objectStack.count - 4UL), [NSString stringWithUTF8String:__FILE__], (long)__LINE__); break; } }
1837+
1838+ if(JK_EXPECT_T((stopParsing = jk_parse_next_token(parseState)) == 0)) {
1839+ void *object = NULL;
1840+#ifndef NS_BLOCK_ASSERTIONS
1841+ parseState->objectStack.objects[parseState->objectStack.index] = NULL;
1842+ parseState->objectStack.keys [parseState->objectStack.index] = NULL;
1843+#endif
1844+ switch(parseState->token.type) {
1845+ case JKTokenTypeNumber:
1846+ case JKTokenTypeString:
1847+ case JKTokenTypeTrue:
1848+ case JKTokenTypeFalse:
1849+ case JKTokenTypeNull:
1850+ case JKTokenTypeArrayBegin:
1851+ case JKTokenTypeObjectBegin:
1852+ if(JK_EXPECT_F((arrayState & JKParseAcceptValue) == 0)) { parseState->errorIsPrev = 1; jk_error(parseState, @"Unexpected value."); stopParsing = 1; break; }
1853+ if(JK_EXPECT_F((object = jk_object_for_token(parseState)) == NULL)) { jk_error(parseState, @"Internal error: Object == NULL"); stopParsing = 1; break; } else { parseState->objectStack.objects[parseState->objectStack.index++] = object; arrayState = JKParseAcceptCommaOrEnd; }
1854+ break;
1855+ case JKTokenTypeArrayEnd: if(JK_EXPECT_T(arrayState & JKParseAcceptEnd)) { NSCParameterAssert(parseState->objectStack.index >= startingObjectIndex); parsedArray = (void *)_JKArrayCreate((id *)&parseState->objectStack.objects[startingObjectIndex], (parseState->objectStack.index - startingObjectIndex), parseState->mutableCollections); } else { parseState->errorIsPrev = 1; jk_error(parseState, @"Unexpected ']'."); } stopParsing = 1; break;
1856+ case JKTokenTypeComma: if(JK_EXPECT_T(arrayState & JKParseAcceptComma)) { arrayState = JKParseAcceptValue; } else { parseState->errorIsPrev = 1; jk_error(parseState, @"Unexpected ','."); stopParsing = 1; } break;
1857+ default: parseState->errorIsPrev = 1; jk_error_parse_accept_or3(parseState, arrayState, @"a value", @"a comma", @"a ']'"); stopParsing = 1; break;
1858+ }
1859+ }
1860+ }
1861+
1862+ if(JK_EXPECT_F(parsedArray == NULL)) { size_t idx = 0UL; for(idx = startingObjectIndex; idx < parseState->objectStack.index; idx++) { if(parseState->objectStack.objects[idx] != NULL) { CFRelease(parseState->objectStack.objects[idx]); parseState->objectStack.objects[idx] = NULL; } } }
1863+#if !defined(NS_BLOCK_ASSERTIONS)
1864+ else { size_t idx = 0UL; for(idx = startingObjectIndex; idx < parseState->objectStack.index; idx++) { parseState->objectStack.objects[idx] = NULL; parseState->objectStack.keys[idx] = NULL; } }
1865+#endif
1866+
1867+ parseState->objectStack.index = startingObjectIndex;
1868+ return(parsedArray);
1869+}
1870+
1871+static void *jk_create_dictionary(JKParseState *parseState, size_t startingObjectIndex) {
1872+ void *parsedDictionary = NULL;
1873+
1874+ parseState->objectStack.index--;
1875+
1876+ parsedDictionary = _JKDictionaryCreate((id *)&parseState->objectStack.keys[startingObjectIndex], (NSUInteger *)&parseState->objectStack.cfHashes[startingObjectIndex], (id *)&parseState->objectStack.objects[startingObjectIndex], (parseState->objectStack.index - startingObjectIndex), parseState->mutableCollections);
1877+
1878+ return(parsedDictionary);
1879+}
1880+
1881+static void *jk_parse_dictionary(JKParseState *parseState) {
1882+ size_t startingObjectIndex = parseState->objectStack.index;
1883+ int dictState = JKParseAcceptValueOrEnd, stopParsing = 0;
1884+ void *parsedDictionary = NULL;
1885+
1886+ while(JK_EXPECT_T((JK_EXPECT_T(stopParsing == 0)) && (JK_EXPECT_T(parseState->atIndex < parseState->stringBuffer.bytes.length)))) {
1887+ if(JK_EXPECT_F(parseState->objectStack.index > (parseState->objectStack.count - 4UL))) { if(jk_objectStack_resize(&parseState->objectStack, parseState->objectStack.count + 128UL)) { jk_error(parseState, @"Internal error: [dictionary] objectsIndex > %zu, resize failed? %@ line #%ld", (parseState->objectStack.count - 4UL), [NSString stringWithUTF8String:__FILE__], (long)__LINE__); break; } }
1888+
1889+ size_t objectStackIndex = parseState->objectStack.index++;
1890+ parseState->objectStack.keys[objectStackIndex] = NULL;
1891+ parseState->objectStack.objects[objectStackIndex] = NULL;
1892+ void *key = NULL, *object = NULL;
1893+
1894+ if(JK_EXPECT_T((JK_EXPECT_T(stopParsing == 0)) && (JK_EXPECT_T((stopParsing = jk_parse_next_token(parseState)) == 0)))) {
1895+ switch(parseState->token.type) {
1896+ case JKTokenTypeString:
1897+ if(JK_EXPECT_F((dictState & JKParseAcceptValue) == 0)) { parseState->errorIsPrev = 1; jk_error(parseState, @"Unexpected string."); stopParsing = 1; break; }
1898+ if(JK_EXPECT_F((key = jk_object_for_token(parseState)) == NULL)) { jk_error(parseState, @"Internal error: Key == NULL."); stopParsing = 1; break; }
1899+ else {
1900+ parseState->objectStack.keys[objectStackIndex] = key;
1901+ if(JK_EXPECT_T(parseState->token.value.cacheItem != NULL)) { if(JK_EXPECT_F(parseState->token.value.cacheItem->cfHash == 0UL)) { parseState->token.value.cacheItem->cfHash = CFHash(key); } parseState->objectStack.cfHashes[objectStackIndex] = parseState->token.value.cacheItem->cfHash; }
1902+ else { parseState->objectStack.cfHashes[objectStackIndex] = CFHash(key); }
1903+ }
1904+ break;
1905+
1906+ case JKTokenTypeObjectEnd: if((JK_EXPECT_T(dictState & JKParseAcceptEnd))) { NSCParameterAssert(parseState->objectStack.index >= startingObjectIndex); parsedDictionary = jk_create_dictionary(parseState, startingObjectIndex); } else { parseState->errorIsPrev = 1; jk_error(parseState, @"Unexpected '}'."); } stopParsing = 1; break;
1907+ case JKTokenTypeComma: if((JK_EXPECT_T(dictState & JKParseAcceptComma))) { dictState = JKParseAcceptValue; parseState->objectStack.index--; continue; } else { parseState->errorIsPrev = 1; jk_error(parseState, @"Unexpected ','."); stopParsing = 1; } break;
1908+
1909+ default: parseState->errorIsPrev = 1; jk_error_parse_accept_or3(parseState, dictState, @"a \"STRING\"", @"a comma", @"a '}'"); stopParsing = 1; break;
1910+ }
1911+ }
1912+
1913+ if(JK_EXPECT_T(stopParsing == 0)) {
1914+ if(JK_EXPECT_T((stopParsing = jk_parse_next_token(parseState)) == 0)) { if(JK_EXPECT_F(parseState->token.type != JKTokenTypeSeparator)) { parseState->errorIsPrev = 1; jk_error(parseState, @"Expected ':'."); stopParsing = 1; } }
1915+ }
1916+
1917+ if((JK_EXPECT_T(stopParsing == 0)) && (JK_EXPECT_T((stopParsing = jk_parse_next_token(parseState)) == 0))) {
1918+ switch(parseState->token.type) {
1919+ case JKTokenTypeNumber:
1920+ case JKTokenTypeString:
1921+ case JKTokenTypeTrue:
1922+ case JKTokenTypeFalse:
1923+ case JKTokenTypeNull:
1924+ case JKTokenTypeArrayBegin:
1925+ case JKTokenTypeObjectBegin:
1926+ if(JK_EXPECT_F((dictState & JKParseAcceptValue) == 0)) { parseState->errorIsPrev = 1; jk_error(parseState, @"Unexpected value."); stopParsing = 1; break; }
1927+ if(JK_EXPECT_F((object = jk_object_for_token(parseState)) == NULL)) { jk_error(parseState, @"Internal error: Object == NULL."); stopParsing = 1; break; } else { parseState->objectStack.objects[objectStackIndex] = object; dictState = JKParseAcceptCommaOrEnd; }
1928+ break;
1929+ default: parseState->errorIsPrev = 1; jk_error_parse_accept_or3(parseState, dictState, @"a value", @"a comma", @"a '}'"); stopParsing = 1; break;
1930+ }
1931+ }
1932+ }
1933+
1934+ if(JK_EXPECT_F(parsedDictionary == NULL)) { size_t idx = 0UL; for(idx = startingObjectIndex; idx < parseState->objectStack.index; idx++) { if(parseState->objectStack.keys[idx] != NULL) { CFRelease(parseState->objectStack.keys[idx]); parseState->objectStack.keys[idx] = NULL; } if(parseState->objectStack.objects[idx] != NULL) { CFRelease(parseState->objectStack.objects[idx]); parseState->objectStack.objects[idx] = NULL; } } }
1935+#if !defined(NS_BLOCK_ASSERTIONS)
1936+ else { size_t idx = 0UL; for(idx = startingObjectIndex; idx < parseState->objectStack.index; idx++) { parseState->objectStack.objects[idx] = NULL; parseState->objectStack.keys[idx] = NULL; } }
1937+#endif
1938+
1939+ parseState->objectStack.index = startingObjectIndex;
1940+ return(parsedDictionary);
1941+}
1942+
1943+static id json_parse_it(JKParseState *parseState) {
1944+ id parsedObject = NULL;
1945+ int stopParsing = 0;
1946+
1947+ while((JK_EXPECT_T(stopParsing == 0)) && (JK_EXPECT_T(parseState->atIndex < parseState->stringBuffer.bytes.length))) {
1948+ if((JK_EXPECT_T(stopParsing == 0)) && (JK_EXPECT_T((stopParsing = jk_parse_next_token(parseState)) == 0))) {
1949+ switch(parseState->token.type) {
1950+ case JKTokenTypeArrayBegin:
1951+ case JKTokenTypeObjectBegin: parsedObject = [(id)jk_object_for_token(parseState) autorelease]; stopParsing = 1; break;
1952+ default: jk_error(parseState, @"Expected either '[' or '{'."); stopParsing = 1; break;
1953+ }
1954+ }
1955+ }
1956+
1957+ NSCParameterAssert((parseState->objectStack.index == 0) && (JK_AT_STRING_PTR(parseState) <= JK_END_STRING_PTR(parseState)));
1958+
1959+ if((parsedObject == NULL) && (JK_AT_STRING_PTR(parseState) == JK_END_STRING_PTR(parseState))) { jk_error(parseState, @"Reached the end of the buffer."); }
1960+ if(parsedObject == NULL) { jk_error(parseState, @"Unable to parse JSON."); }
1961+
1962+ if((parsedObject != NULL) && (JK_AT_STRING_PTR(parseState) < JK_END_STRING_PTR(parseState))) {
1963+ jk_parse_skip_whitespace(parseState);
1964+ if((parsedObject != NULL) && ((parseState->parseOptionFlags & JKParseOptionPermitTextAfterValidJSON) == 0) && (JK_AT_STRING_PTR(parseState) < JK_END_STRING_PTR(parseState))) {
1965+ jk_error(parseState, @"A valid JSON object was parsed but there were additional non-white-space characters remaining.");
1966+ parsedObject = NULL;
1967+ }
1968+ }
1969+
1970+ return(parsedObject);
1971+}
1972+
1973+////////////
1974+#pragma mark -
1975+#pragma mark Object cache
1976+
1977+// This uses a Galois Linear Feedback Shift Register (LFSR) PRNG to pick which item in the cache to age. It has a period of (2^32)-1.
1978+// NOTE: A LFSR *MUST* be initialized to a non-zero value and must always have a non-zero value. The LFSR is initalized to 1 in -initWithParseOptions:
1979+JK_STATIC_INLINE void jk_cache_age(JKParseState *parseState) {
1980+ NSCParameterAssert((parseState != NULL) && (parseState->cache.prng_lfsr != 0U));
1981+ parseState->cache.prng_lfsr = (parseState->cache.prng_lfsr >> 1) ^ ((0U - (parseState->cache.prng_lfsr & 1U)) & 0x80200003U);
1982+ parseState->cache.age[parseState->cache.prng_lfsr & (parseState->cache.count - 1UL)] >>= 1;
1983+}
1984+
1985+// The object cache is nothing more than a hash table with open addressing collision resolution that is bounded by JK_CACHE_PROBES attempts.
1986+//
1987+// The hash table is a linear C array of JKTokenCacheItem. The terms "item" and "bucket" are synonymous with the index in to the cache array, i.e. cache.items[bucket].
1988+//
1989+// Items in the cache have an age associated with them. An items age is incremented using saturating unsigned arithmetic and decremeted using unsigned right shifts.
1990+// Thus, an items age is managed using an AIMD policy- additive increase, multiplicative decrease. All age calculations and manipulations are branchless.
1991+// The primitive C type MUST be unsigned. It is currently a "char", which allows (at a minimum and in practice) 8 bits.
1992+//
1993+// A "useable bucket" is a bucket that is not in use (never populated), or has an age == 0.
1994+//
1995+// When an item is found in the cache, it's age is incremented.
1996+// If a useable bucket hasn't been found, the current item (bucket) is aged along with two random items.
1997+//
1998+// If a value is not found in the cache, and no useable bucket has been found, that value is not added to the cache.
1999+
2000+static void *jk_cachedObjects(JKParseState *parseState) {
2001+ unsigned long bucket = parseState->token.value.hash & (parseState->cache.count - 1UL), setBucket = 0UL, useableBucket = 0UL, x = 0UL;
2002+ void *parsedAtom = NULL;
2003+
2004+ if(JK_EXPECT_F(parseState->token.value.ptrRange.length == 0UL) && JK_EXPECT_T(parseState->token.value.type == JKValueTypeString)) { return(@""); }
2005+
2006+ for(x = 0UL; x < JK_CACHE_PROBES; x++) {
2007+ if(JK_EXPECT_F(parseState->cache.items[bucket].object == NULL)) { setBucket = 1UL; useableBucket = bucket; break; }
2008+
2009+ if((JK_EXPECT_T(parseState->cache.items[bucket].hash == parseState->token.value.hash)) && (JK_EXPECT_T(parseState->cache.items[bucket].size == parseState->token.value.ptrRange.length)) && (JK_EXPECT_T(parseState->cache.items[bucket].type == parseState->token.value.type)) && (JK_EXPECT_T(parseState->cache.items[bucket].bytes != NULL)) && (JK_EXPECT_T(memcmp(parseState->cache.items[bucket].bytes, parseState->token.value.ptrRange.ptr, parseState->token.value.ptrRange.length) == 0U))) {
2010+ parseState->cache.age[bucket] = (((uint32_t)parseState->cache.age[bucket]) + 1U) - (((((uint32_t)parseState->cache.age[bucket]) + 1U) >> 31) ^ 1U);
2011+ parseState->token.value.cacheItem = &parseState->cache.items[bucket];
2012+ NSCParameterAssert(parseState->cache.items[bucket].object != NULL);
2013+ return((void *)CFRetain(parseState->cache.items[bucket].object));
2014+ } else {
2015+ if(JK_EXPECT_F(setBucket == 0UL) && JK_EXPECT_F(parseState->cache.age[bucket] == 0U)) { setBucket = 1UL; useableBucket = bucket; }
2016+ if(JK_EXPECT_F(setBucket == 0UL)) { parseState->cache.age[bucket] >>= 1; jk_cache_age(parseState); jk_cache_age(parseState); }
2017+ // This is the open addressing function. The values length and type are used as a form of "double hashing" to distribute values with the same effective value hash across different object cache buckets.
2018+ // The values type is a prime number that is relatively coprime to the other primes in the set of value types and the number of hash table buckets.
2019+ bucket = (parseState->token.value.hash + (parseState->token.value.ptrRange.length * (x + 1UL)) + (parseState->token.value.type * (x + 1UL)) + (3UL * (x + 1UL))) & (parseState->cache.count - 1UL);
2020+ }
2021+ }
2022+
2023+ switch(parseState->token.value.type) {
2024+ case JKValueTypeString: parsedAtom = (void *)CFStringCreateWithBytes(NULL, parseState->token.value.ptrRange.ptr, parseState->token.value.ptrRange.length, kCFStringEncodingUTF8, 0); break;
2025+ case JKValueTypeLongLong: parsedAtom = (void *)CFNumberCreate(NULL, kCFNumberLongLongType, &parseState->token.value.number.longLongValue); break;
2026+ case JKValueTypeUnsignedLongLong:
2027+ if(parseState->token.value.number.unsignedLongLongValue <= LLONG_MAX) { parsedAtom = (void *)CFNumberCreate(NULL, kCFNumberLongLongType, &parseState->token.value.number.unsignedLongLongValue); }
2028+ else { parsedAtom = (void *)parseState->objCImpCache.NSNumberInitWithUnsignedLongLong(parseState->objCImpCache.NSNumberAlloc(parseState->objCImpCache.NSNumberClass, @selector(alloc)), @selector(initWithUnsignedLongLong:), parseState->token.value.number.unsignedLongLongValue); }
2029+ break;
2030+ case JKValueTypeDouble: parsedAtom = (void *)CFNumberCreate(NULL, kCFNumberDoubleType, &parseState->token.value.number.doubleValue); break;
2031+ default: jk_error(parseState, @"Internal error: Unknown token value type. %@ line #%ld", [NSString stringWithUTF8String:__FILE__], (long)__LINE__); break;
2032+ }
2033+
2034+ if(JK_EXPECT_T(setBucket) && (JK_EXPECT_T(parsedAtom != NULL))) {
2035+ bucket = useableBucket;
2036+ if(JK_EXPECT_T((parseState->cache.items[bucket].object != NULL))) { CFRelease(parseState->cache.items[bucket].object); parseState->cache.items[bucket].object = NULL; }
2037+
2038+ if(JK_EXPECT_T((parseState->cache.items[bucket].bytes = (unsigned char *)reallocf(parseState->cache.items[bucket].bytes, parseState->token.value.ptrRange.length)) != NULL)) {
2039+ memcpy(parseState->cache.items[bucket].bytes, parseState->token.value.ptrRange.ptr, parseState->token.value.ptrRange.length);
2040+ parseState->cache.items[bucket].object = (void *)CFRetain(parsedAtom);
2041+ parseState->cache.items[bucket].hash = parseState->token.value.hash;
2042+ parseState->cache.items[bucket].cfHash = 0UL;
2043+ parseState->cache.items[bucket].size = parseState->token.value.ptrRange.length;
2044+ parseState->cache.items[bucket].type = parseState->token.value.type;
2045+ parseState->token.value.cacheItem = &parseState->cache.items[bucket];
2046+ parseState->cache.age[bucket] = JK_INIT_CACHE_AGE;
2047+ } else { // The realloc failed, so clear the appropriate fields.
2048+ parseState->cache.items[bucket].hash = 0UL;
2049+ parseState->cache.items[bucket].cfHash = 0UL;
2050+ parseState->cache.items[bucket].size = 0UL;
2051+ parseState->cache.items[bucket].type = 0UL;
2052+ }
2053+ }
2054+
2055+ return(parsedAtom);
2056+}
2057+
2058+
2059+static void *jk_object_for_token(JKParseState *parseState) {
2060+ void *parsedAtom = NULL;
2061+
2062+ parseState->token.value.cacheItem = NULL;
2063+ switch(parseState->token.type) {
2064+ case JKTokenTypeString: parsedAtom = jk_cachedObjects(parseState); break;
2065+ case JKTokenTypeNumber: parsedAtom = jk_cachedObjects(parseState); break;
2066+ case JKTokenTypeObjectBegin: parsedAtom = jk_parse_dictionary(parseState); break;
2067+ case JKTokenTypeArrayBegin: parsedAtom = jk_parse_array(parseState); break;
2068+ case JKTokenTypeTrue: parsedAtom = (void *)kCFBooleanTrue; break;
2069+ case JKTokenTypeFalse: parsedAtom = (void *)kCFBooleanFalse; break;
2070+ case JKTokenTypeNull: parsedAtom = (void *)kCFNull; break;
2071+ default: jk_error(parseState, @"Internal error: Unknown token type. %@ line #%ld", [NSString stringWithUTF8String:__FILE__], (long)__LINE__); break;
2072+ }
2073+
2074+ return(parsedAtom);
2075+}
2076+
2077+#pragma mark -
2078+@implementation JSONDecoder
2079+
2080++ (id)decoder
2081+{
2082+ return([self decoderWithParseOptions:JKParseOptionStrict]);
2083+}
2084+
2085++ (id)decoderWithParseOptions:(JKParseOptionFlags)parseOptionFlags
2086+{
2087+ return([[[self alloc] initWithParseOptions:parseOptionFlags] autorelease]);
2088+}
2089+
2090+- (id)init
2091+{
2092+ return([self initWithParseOptions:JKParseOptionStrict]);
2093+}
2094+
2095+- (id)initWithParseOptions:(JKParseOptionFlags)parseOptionFlags
2096+{
2097+ if((self = [super init]) == NULL) { return(NULL); }
2098+
2099+ if(parseOptionFlags & ~JKParseOptionValidFlags) { [self autorelease]; [NSException raise:NSInvalidArgumentException format:@"Invalid parse options."]; }
2100+
2101+ if((parseState = (JKParseState *)calloc(1UL, sizeof(JKParseState))) == NULL) { goto errorExit; }
2102+
2103+ parseState->parseOptionFlags = parseOptionFlags;
2104+
2105+ parseState->token.tokenBuffer.roundSizeUpToMultipleOf = 4096UL;
2106+ parseState->objectStack.roundSizeUpToMultipleOf = 2048UL;
2107+
2108+ parseState->objCImpCache.NSNumberClass = _jk_NSNumberClass;
2109+ parseState->objCImpCache.NSNumberAlloc = _jk_NSNumberAllocImp;
2110+ parseState->objCImpCache.NSNumberInitWithUnsignedLongLong = _jk_NSNumberInitWithUnsignedLongLongImp;
2111+
2112+ parseState->cache.prng_lfsr = 1U;
2113+ parseState->cache.count = JK_CACHE_SLOTS;
2114+ if((parseState->cache.items = (JKTokenCacheItem *)calloc(1UL, sizeof(JKTokenCacheItem) * parseState->cache.count)) == NULL) { goto errorExit; }
2115+
2116+ return(self);
2117+
2118+ errorExit:
2119+ if(self) { [self autorelease]; self = NULL; }
2120+ return(NULL);
2121+}
2122+
2123+// This is here primarily to support the NSString and NSData convenience functions so the autoreleased JSONDecoder can release most of its resources before the pool pops.
2124+static void _JSONDecoderCleanup(JSONDecoder *decoder) {
2125+ if((decoder != NULL) && (decoder->parseState != NULL)) {
2126+ jk_managedBuffer_release(&decoder->parseState->token.tokenBuffer);
2127+ jk_objectStack_release(&decoder->parseState->objectStack);
2128+
2129+ [decoder clearCache];
2130+ if(decoder->parseState->cache.items != NULL) { free(decoder->parseState->cache.items); decoder->parseState->cache.items = NULL; }
2131+
2132+ free(decoder->parseState); decoder->parseState = NULL;
2133+ }
2134+}
2135+
2136+- (void)dealloc
2137+{
2138+ _JSONDecoderCleanup(self);
2139+ [super dealloc];
2140+}
2141+
2142+- (void)clearCache
2143+{
2144+ if(JK_EXPECT_T(parseState != NULL)) {
2145+ if(JK_EXPECT_T(parseState->cache.items != NULL)) {
2146+ size_t idx = 0UL;
2147+ for(idx = 0UL; idx < parseState->cache.count; idx++) {
2148+ if(JK_EXPECT_T(parseState->cache.items[idx].object != NULL)) { CFRelease(parseState->cache.items[idx].object); parseState->cache.items[idx].object = NULL; }
2149+ if(JK_EXPECT_T(parseState->cache.items[idx].bytes != NULL)) { free(parseState->cache.items[idx].bytes); parseState->cache.items[idx].bytes = NULL; }
2150+ memset(&parseState->cache.items[idx], 0, sizeof(JKTokenCacheItem));
2151+ parseState->cache.age[idx] = 0U;
2152+ }
2153+ }
2154+ }
2155+}
2156+
2157+// This needs to be completely rewritten.
2158+static id _JKParseUTF8String(JKParseState *parseState, BOOL mutableCollections, const unsigned char *string, size_t length, NSError **error) {
2159+ NSCParameterAssert((parseState != NULL) && (string != NULL) && (parseState->cache.prng_lfsr != 0U));
2160+ parseState->stringBuffer.bytes.ptr = string;
2161+ parseState->stringBuffer.bytes.length = length;
2162+ parseState->atIndex = 0UL;
2163+ parseState->lineNumber = 1UL;
2164+ parseState->lineStartIndex = 0UL;
2165+ parseState->prev_atIndex = 0UL;
2166+ parseState->prev_lineNumber = 1UL;
2167+ parseState->prev_lineStartIndex = 0UL;
2168+ parseState->error = NULL;
2169+ parseState->errorIsPrev = 0;
2170+ parseState->mutableCollections = (mutableCollections == NO) ? NO : YES;
2171+
2172+ unsigned char stackTokenBuffer[JK_TOKENBUFFER_SIZE] JK_ALIGNED(64);
2173+ jk_managedBuffer_setToStackBuffer(&parseState->token.tokenBuffer, stackTokenBuffer, sizeof(stackTokenBuffer));
2174+
2175+ void *stackObjects [JK_STACK_OBJS] JK_ALIGNED(64);
2176+ void *stackKeys [JK_STACK_OBJS] JK_ALIGNED(64);
2177+ CFHashCode stackCFHashes[JK_STACK_OBJS] JK_ALIGNED(64);
2178+ jk_objectStack_setToStackBuffer(&parseState->objectStack, stackObjects, stackKeys, stackCFHashes, JK_STACK_OBJS);
2179+
2180+ id parsedJSON = json_parse_it(parseState);
2181+
2182+ if((error != NULL) && (parseState->error != NULL)) { *error = parseState->error; }
2183+
2184+ jk_managedBuffer_release(&parseState->token.tokenBuffer);
2185+ jk_objectStack_release(&parseState->objectStack);
2186+
2187+ parseState->stringBuffer.bytes.ptr = NULL;
2188+ parseState->stringBuffer.bytes.length = 0UL;
2189+ parseState->atIndex = 0UL;
2190+ parseState->lineNumber = 1UL;
2191+ parseState->lineStartIndex = 0UL;
2192+ parseState->prev_atIndex = 0UL;
2193+ parseState->prev_lineNumber = 1UL;
2194+ parseState->prev_lineStartIndex = 0UL;
2195+ parseState->error = NULL;
2196+ parseState->errorIsPrev = 0;
2197+ parseState->mutableCollections = NO;
2198+
2199+ return(parsedJSON);
2200+}
2201+
2202+////////////
2203+#pragma mark Deprecated as of v1.4
2204+////////////
2205+
2206+// Deprecated in JSONKit v1.4. Use objectWithUTF8String:length: instead.
2207+- (id)parseUTF8String:(const unsigned char *)string length:(size_t)length
2208+{
2209+ return([self objectWithUTF8String:string length:length error:NULL]);
2210+}
2211+
2212+// Deprecated in JSONKit v1.4. Use objectWithUTF8String:length:error: instead.
2213+- (id)parseUTF8String:(const unsigned char *)string length:(size_t)length error:(NSError **)error
2214+{
2215+ return([self objectWithUTF8String:string length:length error:error]);
2216+}
2217+
2218+// Deprecated in JSONKit v1.4. Use objectWithData: instead.
2219+- (id)parseJSONData:(NSData *)jsonData
2220+{
2221+ return([self objectWithData:jsonData error:NULL]);
2222+}
2223+
2224+// Deprecated in JSONKit v1.4. Use objectWithData:error: instead.
2225+- (id)parseJSONData:(NSData *)jsonData error:(NSError **)error
2226+{
2227+ return([self objectWithData:jsonData error:error]);
2228+}
2229+
2230+////////////
2231+#pragma mark Methods that return immutable collection objects
2232+////////////
2233+
2234+- (id)objectWithUTF8String:(const unsigned char *)string length:(NSUInteger)length
2235+{
2236+ return([self objectWithUTF8String:string length:length error:NULL]);
2237+}
2238+
2239+- (id)objectWithUTF8String:(const unsigned char *)string length:(NSUInteger)length error:(NSError **)error
2240+{
2241+ if(parseState == NULL) { [NSException raise:NSInternalInconsistencyException format:@"parseState is NULL."]; }
2242+ if(string == NULL) { [NSException raise:NSInvalidArgumentException format:@"The string argument is NULL."]; }
2243+
2244+ return(_JKParseUTF8String(parseState, NO, string, (size_t)length, error));
2245+}
2246+
2247+- (id)objectWithData:(NSData *)jsonData
2248+{
2249+ return([self objectWithData:jsonData error:NULL]);
2250+}
2251+
2252+- (id)objectWithData:(NSData *)jsonData error:(NSError **)error
2253+{
2254+ if(jsonData == NULL) { [NSException raise:NSInvalidArgumentException format:@"The jsonData argument is NULL."]; }
2255+ return([self objectWithUTF8String:(const unsigned char *)[jsonData bytes] length:[jsonData length] error:error]);
2256+}
2257+
2258+////////////
2259+#pragma mark Methods that return mutable collection objects
2260+////////////
2261+
2262+- (id)mutableObjectWithUTF8String:(const unsigned char *)string length:(NSUInteger)length
2263+{
2264+ return([self mutableObjectWithUTF8String:string length:length error:NULL]);
2265+}
2266+
2267+- (id)mutableObjectWithUTF8String:(const unsigned char *)string length:(NSUInteger)length error:(NSError **)error
2268+{
2269+ if(parseState == NULL) { [NSException raise:NSInternalInconsistencyException format:@"parseState is NULL."]; }
2270+ if(string == NULL) { [NSException raise:NSInvalidArgumentException format:@"The string argument is NULL."]; }
2271+
2272+ return(_JKParseUTF8String(parseState, YES, string, (size_t)length, error));
2273+}
2274+
2275+- (id)mutableObjectWithData:(NSData *)jsonData
2276+{
2277+ return([self mutableObjectWithData:jsonData error:NULL]);
2278+}
2279+
2280+- (id)mutableObjectWithData:(NSData *)jsonData error:(NSError **)error
2281+{
2282+ if(jsonData == NULL) { [NSException raise:NSInvalidArgumentException format:@"The jsonData argument is NULL."]; }
2283+ return([self mutableObjectWithUTF8String:(const unsigned char *)[jsonData bytes] length:[jsonData length] error:error]);
2284+}
2285+
2286+@end
2287+
2288+/*
2289+ The NSString and NSData convenience methods need a little bit of explanation.
2290+
2291+ Prior to JSONKit v1.4, the NSString -objectFromJSONStringWithParseOptions:error: method looked like
2292+
2293+ const unsigned char *utf8String = (const unsigned char *)[self UTF8String];
2294+ if(utf8String == NULL) { return(NULL); }
2295+ size_t utf8Length = strlen((const char *)utf8String);
2296+ return([[JSONDecoder decoderWithParseOptions:parseOptionFlags] parseUTF8String:utf8String length:utf8Length error:error]);
2297+
2298+ This changed with v1.4 to a more complicated method. The reason for this is to keep the amount of memory that is
2299+ allocated, but not yet freed because it is dependent on the autorelease pool to pop before it can be reclaimed.
2300+
2301+ In the simpler v1.3 code, this included all the bytes used to store the -UTF8String along with the JSONDecoder and all its overhead.
2302+
2303+ Now we use an autoreleased CFMutableData that is sized to the UTF8 length of the NSString in question and is used to hold the UTF8
2304+ conversion of said string.
2305+
2306+ Once parsed, the CFMutableData has its length set to 0. This should, hopefully, allow the CFMutableData to realloc and/or free
2307+ the buffer.
2308+
2309+ Another change made was a slight modification to JSONDecoder so that most of the cleanup work that was done in -dealloc was moved
2310+ to a private, internal function. These convenience routines keep the pointer to the autoreleased JSONDecoder and calls
2311+ _JSONDecoderCleanup() to early release the decoders resources since we already know that particular decoder is not going to be used
2312+ again.
2313+
2314+ If everything goes smoothly, this will most likely result in perhaps a few hundred bytes that are allocated but waiting for the
2315+ autorelease pool to pop. This is compared to the thousands and easily hundreds of thousands of bytes that would have been in
2316+ autorelease limbo. It's more complicated for us, but a win for the user.
2317+
2318+ Autorelease objects are used in case things don't go smoothly. By having them autoreleased, we effectively guarantee that our
2319+ requirement to -release the object is always met, not matter what goes wrong. The downside is having a an object or two in
2320+ autorelease limbo, but we've done our best to minimize that impact, so it all balances out.
2321+ */
2322+
2323+@implementation NSString (JSONKitDeserializing)
2324+
2325+static id _NSStringObjectFromJSONString(NSString *jsonString, JKParseOptionFlags parseOptionFlags, NSError **error, BOOL mutableCollection) {
2326+ id returnObject = NULL;
2327+ CFMutableDataRef mutableData = NULL;
2328+ JSONDecoder *decoder = NULL;
2329+
2330+ CFIndex stringLength = CFStringGetLength((CFStringRef)jsonString);
2331+ NSUInteger stringUTF8Length = [jsonString lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
2332+
2333+ if((mutableData = (CFMutableDataRef)[(id)CFDataCreateMutable(NULL, (NSUInteger)stringUTF8Length) autorelease]) != NULL) {
2334+ UInt8 *utf8String = CFDataGetMutableBytePtr(mutableData);
2335+ CFIndex usedBytes = 0L, convertedCount = 0L;
2336+
2337+ convertedCount = CFStringGetBytes((CFStringRef)jsonString, CFRangeMake(0L, stringLength), kCFStringEncodingUTF8, '?', NO, utf8String, (NSUInteger)stringUTF8Length, &usedBytes);
2338+ if(JK_EXPECT_F(convertedCount != stringLength) || JK_EXPECT_F(usedBytes < 0L)) { if(error != NULL) { *error = [NSError errorWithDomain:@"JKErrorDomain" code:-1L userInfo:[NSDictionary dictionaryWithObject:@"An error occurred converting the contents of a NSString to UTF8." forKey:NSLocalizedDescriptionKey]]; } goto exitNow; }
2339+
2340+ if(mutableCollection == NO) { returnObject = [(decoder = [JSONDecoder decoderWithParseOptions:parseOptionFlags]) objectWithUTF8String:(const unsigned char *)utf8String length:(size_t)usedBytes error:error]; }
2341+ else { returnObject = [(decoder = [JSONDecoder decoderWithParseOptions:parseOptionFlags]) mutableObjectWithUTF8String:(const unsigned char *)utf8String length:(size_t)usedBytes error:error]; }
2342+ }
2343+
2344+exitNow:
2345+ if(mutableData != NULL) { CFDataSetLength(mutableData, 0L); }
2346+ if(decoder != NULL) { _JSONDecoderCleanup(decoder); }
2347+ return(returnObject);
2348+}
2349+
2350+- (id)objectFromJSONString
2351+{
2352+ return([self objectFromJSONStringWithParseOptions:JKParseOptionStrict error:NULL]);
2353+}
2354+
2355+- (id)objectFromJSONStringWithParseOptions:(JKParseOptionFlags)parseOptionFlags
2356+{
2357+ return([self objectFromJSONStringWithParseOptions:parseOptionFlags error:NULL]);
2358+}
2359+
2360+- (id)objectFromJSONStringWithParseOptions:(JKParseOptionFlags)parseOptionFlags error:(NSError **)error
2361+{
2362+ return(_NSStringObjectFromJSONString(self, parseOptionFlags, error, NO));
2363+}
2364+
2365+
2366+- (id)mutableObjectFromJSONString
2367+{
2368+ return([self mutableObjectFromJSONStringWithParseOptions:JKParseOptionStrict error:NULL]);
2369+}
2370+
2371+- (id)mutableObjectFromJSONStringWithParseOptions:(JKParseOptionFlags)parseOptionFlags
2372+{
2373+ return([self mutableObjectFromJSONStringWithParseOptions:parseOptionFlags error:NULL]);
2374+}
2375+
2376+- (id)mutableObjectFromJSONStringWithParseOptions:(JKParseOptionFlags)parseOptionFlags error:(NSError **)error
2377+{
2378+ return(_NSStringObjectFromJSONString(self, parseOptionFlags, error, YES));
2379+}
2380+
2381+@end
2382+
2383+@implementation NSData (JSONKitDeserializing)
2384+
2385+- (id)objectFromJSONData
2386+{
2387+ return([self objectFromJSONDataWithParseOptions:JKParseOptionStrict error:NULL]);
2388+}
2389+
2390+- (id)objectFromJSONDataWithParseOptions:(JKParseOptionFlags)parseOptionFlags
2391+{
2392+ return([self objectFromJSONDataWithParseOptions:parseOptionFlags error:NULL]);
2393+}
2394+
2395+- (id)objectFromJSONDataWithParseOptions:(JKParseOptionFlags)parseOptionFlags error:(NSError **)error
2396+{
2397+ JSONDecoder *decoder = NULL;
2398+ id returnObject = [(decoder = [JSONDecoder decoderWithParseOptions:parseOptionFlags]) objectWithData:self error:error];
2399+ if(decoder != NULL) { _JSONDecoderCleanup(decoder); }
2400+ return(returnObject);
2401+}
2402+
2403+- (id)mutableObjectFromJSONData
2404+{
2405+ return([self mutableObjectFromJSONDataWithParseOptions:JKParseOptionStrict error:NULL]);
2406+}
2407+
2408+- (id)mutableObjectFromJSONDataWithParseOptions:(JKParseOptionFlags)parseOptionFlags
2409+{
2410+ return([self mutableObjectFromJSONDataWithParseOptions:parseOptionFlags error:NULL]);
2411+}
2412+
2413+- (id)mutableObjectFromJSONDataWithParseOptions:(JKParseOptionFlags)parseOptionFlags error:(NSError **)error
2414+{
2415+ JSONDecoder *decoder = NULL;
2416+ id returnObject = [(decoder = [JSONDecoder decoderWithParseOptions:parseOptionFlags]) mutableObjectWithData:self error:error];
2417+ if(decoder != NULL) { _JSONDecoderCleanup(decoder); }
2418+ return(returnObject);
2419+}
2420+
2421+
2422+@end
2423+
2424+////////////
2425+#pragma mark -
2426+#pragma mark Encoding / deserializing functions
2427+
2428+static void jk_encode_error(JKEncodeState *encodeState, NSString *format, ...) {
2429+ NSCParameterAssert((encodeState != NULL) && (format != NULL));
2430+
2431+ va_list varArgsList;
2432+ va_start(varArgsList, format);
2433+ NSString *formatString = [[[NSString alloc] initWithFormat:format arguments:varArgsList] autorelease];
2434+ va_end(varArgsList);
2435+
2436+ if(encodeState->error == NULL) {
2437+ encodeState->error = [NSError errorWithDomain:@"JKErrorDomain" code:-1L userInfo:
2438+ [NSDictionary dictionaryWithObjectsAndKeys:
2439+ formatString, NSLocalizedDescriptionKey,
2440+ NULL]];
2441+ }
2442+}
2443+
2444+JK_STATIC_INLINE void jk_encode_updateCache(JKEncodeState *encodeState, JKEncodeCache *cacheSlot, size_t startingAtIndex, id object) {
2445+ NSCParameterAssert(encodeState != NULL);
2446+ if(JK_EXPECT_T(cacheSlot != NULL)) {
2447+ NSCParameterAssert((object != NULL) && (startingAtIndex <= encodeState->atIndex));
2448+ cacheSlot->object = object;
2449+ cacheSlot->offset = startingAtIndex;
2450+ cacheSlot->length = (size_t)(encodeState->atIndex - startingAtIndex);
2451+ }
2452+}
2453+
2454+static int jk_encode_printf(JKEncodeState *encodeState, JKEncodeCache *cacheSlot, size_t startingAtIndex, id object, const char *format, ...) {
2455+ va_list varArgsList, varArgsListCopy;
2456+ va_start(varArgsList, format);
2457+ va_copy(varArgsListCopy, varArgsList);
2458+
2459+ NSCParameterAssert((encodeState != NULL) && (encodeState->atIndex < encodeState->stringBuffer.bytes.length) && (startingAtIndex <= encodeState->atIndex) && (format != NULL));
2460+
2461+ ssize_t formattedStringLength = 0L;
2462+ int returnValue = 0;
2463+
2464+ if(JK_EXPECT_T((formattedStringLength = vsnprintf((char *)&encodeState->stringBuffer.bytes.ptr[encodeState->atIndex], (encodeState->stringBuffer.bytes.length - encodeState->atIndex), format, varArgsList)) >= (ssize_t)(encodeState->stringBuffer.bytes.length - encodeState->atIndex))) {
2465+ NSCParameterAssert(((encodeState->atIndex + (formattedStringLength * 2UL) + 256UL) > encodeState->stringBuffer.bytes.length));
2466+ if(JK_EXPECT_F(((encodeState->atIndex + (formattedStringLength * 2UL) + 256UL) > encodeState->stringBuffer.bytes.length)) && JK_EXPECT_F((jk_managedBuffer_resize(&encodeState->stringBuffer, encodeState->atIndex + (formattedStringLength * 2UL)+ 4096UL) == NULL))) { jk_encode_error(encodeState, @"Unable to resize temporary buffer."); returnValue = 1; goto exitNow; }
2467+ if(JK_EXPECT_F((formattedStringLength = vsnprintf((char *)&encodeState->stringBuffer.bytes.ptr[encodeState->atIndex], (encodeState->stringBuffer.bytes.length - encodeState->atIndex), format, varArgsListCopy)) >= (ssize_t)(encodeState->stringBuffer.bytes.length - encodeState->atIndex))) { jk_encode_error(encodeState, @"vsnprintf failed unexpectedly."); returnValue = 1; goto exitNow; }
2468+ }
2469+
2470+exitNow:
2471+ va_end(varArgsList);
2472+ va_end(varArgsListCopy);
2473+ if(JK_EXPECT_T(returnValue == 0)) { encodeState->atIndex += formattedStringLength; jk_encode_updateCache(encodeState, cacheSlot, startingAtIndex, object); }
2474+ return(returnValue);
2475+}
2476+
2477+static int jk_encode_write(JKEncodeState *encodeState, JKEncodeCache *cacheSlot, size_t startingAtIndex, id object, const char *format) {
2478+ NSCParameterAssert((encodeState != NULL) && (encodeState->atIndex < encodeState->stringBuffer.bytes.length) && (startingAtIndex <= encodeState->atIndex) && (format != NULL));
2479+ if(JK_EXPECT_F(((encodeState->atIndex + strlen(format) + 256UL) > encodeState->stringBuffer.bytes.length)) && JK_EXPECT_F((jk_managedBuffer_resize(&encodeState->stringBuffer, encodeState->atIndex + strlen(format) + 1024UL) == NULL))) { jk_encode_error(encodeState, @"Unable to resize temporary buffer."); return(1); }
2480+
2481+ size_t formatIdx = 0UL;
2482+ for(formatIdx = 0UL; format[formatIdx] != 0; formatIdx++) { NSCParameterAssert(encodeState->atIndex < encodeState->stringBuffer.bytes.length); encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = format[formatIdx]; }
2483+ jk_encode_updateCache(encodeState, cacheSlot, startingAtIndex, object);
2484+ return(0);
2485+}
2486+
2487+static int jk_encode_writePrettyPrintWhiteSpace(JKEncodeState *encodeState) {
2488+ NSCParameterAssert((encodeState != NULL) && ((encodeState->serializeOptionFlags & JKSerializeOptionPretty) != 0UL));
2489+ if(JK_EXPECT_F((encodeState->atIndex + ((encodeState->depth + 1UL) * 2UL) + 16UL) > encodeState->stringBuffer.bytes.length) && JK_EXPECT_T(jk_managedBuffer_resize(&encodeState->stringBuffer, encodeState->atIndex + ((encodeState->depth + 1UL) * 2UL) + 4096UL) == NULL)) { jk_encode_error(encodeState, @"Unable to resize temporary buffer."); return(1); }
2490+ encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = '\n';
2491+ size_t depthWhiteSpace = 0UL;
2492+ for(depthWhiteSpace = 0UL; depthWhiteSpace < (encodeState->depth * 2UL); depthWhiteSpace++) { NSCParameterAssert(encodeState->atIndex < encodeState->stringBuffer.bytes.length); encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = ' '; }
2493+ return(0);
2494+}
2495+
2496+static int jk_encode_write1slow(JKEncodeState *encodeState, ssize_t depthChange, const char *format) {
2497+ NSCParameterAssert((encodeState != NULL) && (encodeState->atIndex < encodeState->stringBuffer.bytes.length) && (format != NULL) && ((depthChange >= -1L) && (depthChange <= 1L)) && ((encodeState->depth == 0UL) ? (depthChange >= 0L) : 1) && ((encodeState->serializeOptionFlags & JKSerializeOptionPretty) != 0UL));
2498+ if(JK_EXPECT_F((encodeState->atIndex + ((encodeState->depth + 1UL) * 2UL) + 16UL) > encodeState->stringBuffer.bytes.length) && JK_EXPECT_F(jk_managedBuffer_resize(&encodeState->stringBuffer, encodeState->atIndex + ((encodeState->depth + 1UL) * 2UL) + 4096UL) == NULL)) { jk_encode_error(encodeState, @"Unable to resize temporary buffer."); return(1); }
2499+ encodeState->depth += depthChange;
2500+ if(JK_EXPECT_T(format[0] == ':')) { encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = format[0]; encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = ' '; }
2501+ else {
2502+ if(JK_EXPECT_F(depthChange == -1L)) { if(JK_EXPECT_F(jk_encode_writePrettyPrintWhiteSpace(encodeState))) { return(1); } }
2503+ encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = format[0];
2504+ if(JK_EXPECT_T(depthChange != -1L)) { if(JK_EXPECT_F(jk_encode_writePrettyPrintWhiteSpace(encodeState))) { return(1); } }
2505+ }
2506+ NSCParameterAssert(encodeState->atIndex < encodeState->stringBuffer.bytes.length);
2507+ return(0);
2508+}
2509+
2510+static int jk_encode_write1fast(JKEncodeState *encodeState, ssize_t depthChange JK_UNUSED_ARG, const char *format) {
2511+ NSCParameterAssert((encodeState != NULL) && (encodeState->atIndex < encodeState->stringBuffer.bytes.length) && ((encodeState->serializeOptionFlags & JKSerializeOptionPretty) == 0UL));
2512+ if(JK_EXPECT_T((encodeState->atIndex + 4UL) < encodeState->stringBuffer.bytes.length)) { encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = format[0]; }
2513+ else { return(jk_encode_write(encodeState, NULL, 0UL, NULL, format)); }
2514+ return(0);
2515+}
2516+
2517+static int jk_encode_writen(JKEncodeState *encodeState, JKEncodeCache *cacheSlot, size_t startingAtIndex, id object, const char *format, size_t length) {
2518+ NSCParameterAssert((encodeState != NULL) && (encodeState->atIndex < encodeState->stringBuffer.bytes.length) && (startingAtIndex <= encodeState->atIndex));
2519+ if(JK_EXPECT_F((encodeState->stringBuffer.bytes.length - encodeState->atIndex) < (length + 4UL))) { if(jk_managedBuffer_resize(&encodeState->stringBuffer, encodeState->atIndex + 4096UL + length) == NULL) { jk_encode_error(encodeState, @"Unable to resize temporary buffer."); return(1); } }
2520+ memcpy(encodeState->stringBuffer.bytes.ptr + encodeState->atIndex, format, length);
2521+ encodeState->atIndex += length;
2522+ jk_encode_updateCache(encodeState, cacheSlot, startingAtIndex, object);
2523+ return(0);
2524+}
2525+
2526+JK_STATIC_INLINE JKHash jk_encode_object_hash(void *objectPtr) {
2527+ return( ( (((JKHash)objectPtr) >> 21) ^ (((JKHash)objectPtr) >> 9) ) + (((JKHash)objectPtr) >> 4) );
2528+}
2529+
2530+static int jk_encode_add_atom_to_buffer(JKEncodeState *encodeState, void *objectPtr) {
2531+ NSCParameterAssert((encodeState != NULL) && (encodeState->atIndex < encodeState->stringBuffer.bytes.length) && (objectPtr != NULL));
2532+
2533+ id object = (id)objectPtr, encodeCacheObject = object;
2534+ int isClass = JKClassUnknown;
2535+ size_t startingAtIndex = encodeState->atIndex;
2536+
2537+ JKHash objectHash = jk_encode_object_hash(objectPtr);
2538+ JKEncodeCache *cacheSlot = &encodeState->cache[objectHash % JK_ENCODE_CACHE_SLOTS];
2539+
2540+ if(JK_EXPECT_T(cacheSlot->object == object)) {
2541+ NSCParameterAssert((cacheSlot->object != NULL) &&
2542+ (cacheSlot->offset < encodeState->atIndex) && ((cacheSlot->offset + cacheSlot->length) < encodeState->atIndex) &&
2543+ (cacheSlot->offset < encodeState->stringBuffer.bytes.length) && ((cacheSlot->offset + cacheSlot->length) < encodeState->stringBuffer.bytes.length) &&
2544+ ((encodeState->stringBuffer.bytes.ptr + encodeState->atIndex) < (encodeState->stringBuffer.bytes.ptr + encodeState->stringBuffer.bytes.length)) &&
2545+ ((encodeState->stringBuffer.bytes.ptr + cacheSlot->offset) < (encodeState->stringBuffer.bytes.ptr + encodeState->stringBuffer.bytes.length)) &&
2546+ ((encodeState->stringBuffer.bytes.ptr + cacheSlot->offset + cacheSlot->length) < (encodeState->stringBuffer.bytes.ptr + encodeState->stringBuffer.bytes.length)));
2547+ if(JK_EXPECT_F(((encodeState->atIndex + cacheSlot->length + 256UL) > encodeState->stringBuffer.bytes.length)) && JK_EXPECT_F((jk_managedBuffer_resize(&encodeState->stringBuffer, encodeState->atIndex + cacheSlot->length + 1024UL) == NULL))) { jk_encode_error(encodeState, @"Unable to resize temporary buffer."); return(1); }
2548+ NSCParameterAssert(((encodeState->atIndex + cacheSlot->length) < encodeState->stringBuffer.bytes.length) &&
2549+ ((encodeState->stringBuffer.bytes.ptr + encodeState->atIndex) < (encodeState->stringBuffer.bytes.ptr + encodeState->stringBuffer.bytes.length)) &&
2550+ ((encodeState->stringBuffer.bytes.ptr + encodeState->atIndex + cacheSlot->length) < (encodeState->stringBuffer.bytes.ptr + encodeState->stringBuffer.bytes.length)) &&
2551+ ((encodeState->stringBuffer.bytes.ptr + cacheSlot->offset) < (encodeState->stringBuffer.bytes.ptr + encodeState->stringBuffer.bytes.length)) &&
2552+ ((encodeState->stringBuffer.bytes.ptr + cacheSlot->offset + cacheSlot->length) < (encodeState->stringBuffer.bytes.ptr + encodeState->stringBuffer.bytes.length)) &&
2553+ ((encodeState->stringBuffer.bytes.ptr + cacheSlot->offset + cacheSlot->length) < (encodeState->stringBuffer.bytes.ptr + encodeState->atIndex)));
2554+ memcpy(encodeState->stringBuffer.bytes.ptr + encodeState->atIndex, encodeState->stringBuffer.bytes.ptr + cacheSlot->offset, cacheSlot->length);
2555+ encodeState->atIndex += cacheSlot->length;
2556+ return(0);
2557+ }
2558+
2559+ // When we encounter a class that we do not handle, and we have either a delegate or block that the user supplied to format unsupported classes,
2560+ // we "re-run" the object check. However, we re-run the object check exactly ONCE. If the user supplies an object that isn't one of the
2561+ // supported classes, we fail the second time (i.e., double fault error).
2562+ BOOL rerunningAfterClassFormatter = NO;
2563+ rerunAfterClassFormatter:;
2564+
2565+ // XXX XXX XXX XXX
2566+ //
2567+ // We need to work around a bug in 10.7, which breaks ABI compatibility with Objective-C going back not just to 10.0, but OpenStep and even NextStep.
2568+ //
2569+ // It has long been documented that "the very first thing that a pointer to an Objective-C object "points to" is a pointer to that objects class".
2570+ //
2571+ // This is euphemistically called "tagged pointers". There are a number of highly technical problems with this, most involving long passages from
2572+ // the C standard(s). In short, one can make a strong case, couched from the perspective of the C standard(s), that that 10.7 "tagged pointers" are
2573+ // fundamentally Wrong and Broken, and should have never been implemented. Assuming those points are glossed over, because the change is very clearly
2574+ // breaking ABI compatibility, this should have resulted in a minimum of a "minimum version required" bump in various shared libraries to prevent
2575+ // causes code that used to work just fine to suddenly break without warning.
2576+ //
2577+ // In fact, the C standard says that the hack below is "undefined behavior"- there is no requirement that the 10.7 tagged pointer hack of setting the
2578+ // "lower, unused bits" must be preserved when casting the result to an integer type, but this "works" because for most architectures
2579+ // `sizeof(long) == sizeof(void *)` and the compiler uses the same representation for both. (note: this is informal, not meant to be
2580+ // normative or pedantically correct).
2581+ //
2582+ // In other words, while this "works" for now, technically the compiler is not obligated to do "what we want", and a later version of the compiler
2583+ // is not required in any way to produce the same results or behavior that earlier versions of the compiler did for the statement below.
2584+ //
2585+ // Fan-fucking-tastic.
2586+ //
2587+ // Why not just use `object_getClass()`? Because `object->isa` reduces to (typically) a *single* instruction. Calling `object_getClass()` requires
2588+ // that the compiler potentially spill registers, establish a function call frame / environment, and finally execute a "jump subroutine" instruction.
2589+ // Then, the called subroutine must spend half a dozen instructions in its prolog, however many instructions doing whatever it does, then half a dozen
2590+ // instructions in its prolog. One instruction compared to dozens, maybe a hundred instructions.
2591+ //
2592+ // Yes, that's one to two orders of magnitude difference. Which is compelling in its own right. When going for performance, you're often happy with
2593+ // gains in the two to three percent range.
2594+ //
2595+ // XXX XXX XXX XXX
2596+
2597+
2598+ BOOL workAroundMacOSXABIBreakingBug = (JK_EXPECT_F(((NSUInteger)object) & 0x1)) ? YES : NO;
2599+ void *objectISA = (JK_EXPECT_F(workAroundMacOSXABIBreakingBug)) ? NULL : *((void **)objectPtr);
2600+ if(JK_EXPECT_F(workAroundMacOSXABIBreakingBug)) { goto slowClassLookup; }
2601+
2602+ if(JK_EXPECT_T(objectISA == encodeState->fastClassLookup.stringClass)) { isClass = JKClassString; }
2603+ else if(JK_EXPECT_T(objectISA == encodeState->fastClassLookup.numberClass)) { isClass = JKClassNumber; }
2604+ else if(JK_EXPECT_T(objectISA == encodeState->fastClassLookup.dictionaryClass)) { isClass = JKClassDictionary; }
2605+ else if(JK_EXPECT_T(objectISA == encodeState->fastClassLookup.arrayClass)) { isClass = JKClassArray; }
2606+ else if(JK_EXPECT_T(objectISA == encodeState->fastClassLookup.nullClass)) { isClass = JKClassNull; }
2607+ else {
2608+ slowClassLookup:
2609+ if(JK_EXPECT_T([object isKindOfClass:[NSString class]])) { if(workAroundMacOSXABIBreakingBug == NO) { encodeState->fastClassLookup.stringClass = objectISA; } isClass = JKClassString; }
2610+ else if(JK_EXPECT_T([object isKindOfClass:[NSNumber class]])) { if(workAroundMacOSXABIBreakingBug == NO) { encodeState->fastClassLookup.numberClass = objectISA; } isClass = JKClassNumber; }
2611+ else if(JK_EXPECT_T([object isKindOfClass:[NSDictionary class]])) { if(workAroundMacOSXABIBreakingBug == NO) { encodeState->fastClassLookup.dictionaryClass = objectISA; } isClass = JKClassDictionary; }
2612+ else if(JK_EXPECT_T([object isKindOfClass:[NSArray class]])) { if(workAroundMacOSXABIBreakingBug == NO) { encodeState->fastClassLookup.arrayClass = objectISA; } isClass = JKClassArray; }
2613+ else if(JK_EXPECT_T([object isKindOfClass:[NSNull class]])) { if(workAroundMacOSXABIBreakingBug == NO) { encodeState->fastClassLookup.nullClass = objectISA; } isClass = JKClassNull; }
2614+ else {
2615+ if((rerunningAfterClassFormatter == NO) && (
2616+#ifdef __BLOCKS__
2617+ ((encodeState->classFormatterBlock) && ((object = encodeState->classFormatterBlock(object)) != NULL)) ||
2618+#endif
2619+ ((encodeState->classFormatterIMP) && ((object = encodeState->classFormatterIMP(encodeState->classFormatterDelegate, encodeState->classFormatterSelector, object)) != NULL)) )) { rerunningAfterClassFormatter = YES; goto rerunAfterClassFormatter; }
2620+
2621+ if(rerunningAfterClassFormatter == NO) { jk_encode_error(encodeState, @"Unable to serialize object class %@.", NSStringFromClass([encodeCacheObject class])); return(1); }
2622+ else { jk_encode_error(encodeState, @"Unable to serialize object class %@ that was returned by the unsupported class formatter. Original object class was %@.", (object == NULL) ? @"NULL" : NSStringFromClass([object class]), NSStringFromClass([encodeCacheObject class])); return(1); }
2623+ }
2624+ }
2625+
2626+ // This is here for the benefit of the optimizer. It allows the optimizer to do loop invariant code motion for the JKClassArray
2627+ // and JKClassDictionary cases when printing simple, single characters via jk_encode_write(), which is actually a macro:
2628+ // #define jk_encode_write1(es, dc, f) (_jk_encode_prettyPrint ? jk_encode_write1slow(es, dc, f) : jk_encode_write1fast(es, dc, f))
2629+ int _jk_encode_prettyPrint = JK_EXPECT_T((encodeState->serializeOptionFlags & JKSerializeOptionPretty) == 0) ? 0 : 1;
2630+
2631+ switch(isClass) {
2632+ case JKClassString:
2633+ {
2634+ {
2635+ const unsigned char *cStringPtr = (const unsigned char *)CFStringGetCStringPtr((CFStringRef)object, kCFStringEncodingMacRoman);
2636+ if(cStringPtr != NULL) {
2637+ const unsigned char *utf8String = cStringPtr;
2638+ size_t utf8Idx = 0UL;
2639+
2640+ CFIndex stringLength = CFStringGetLength((CFStringRef)object);
2641+ if(JK_EXPECT_F(((encodeState->atIndex + (stringLength * 2UL) + 256UL) > encodeState->stringBuffer.bytes.length)) && JK_EXPECT_F((jk_managedBuffer_resize(&encodeState->stringBuffer, encodeState->atIndex + (stringLength * 2UL) + 1024UL) == NULL))) { jk_encode_error(encodeState, @"Unable to resize temporary buffer."); return(1); }
2642+
2643+ if(JK_EXPECT_T((encodeState->encodeOption & JKEncodeOptionStringObjTrimQuotes) == 0UL)) { encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = '\"'; }
2644+ for(utf8Idx = 0UL; utf8String[utf8Idx] != 0U; utf8Idx++) {
2645+ NSCParameterAssert(((&encodeState->stringBuffer.bytes.ptr[encodeState->atIndex]) - encodeState->stringBuffer.bytes.ptr) < (ssize_t)encodeState->stringBuffer.bytes.length);
2646+ NSCParameterAssert(encodeState->atIndex < encodeState->stringBuffer.bytes.length);
2647+ if(JK_EXPECT_F(utf8String[utf8Idx] >= 0x80U)) { encodeState->atIndex = startingAtIndex; goto slowUTF8Path; }
2648+ if(JK_EXPECT_F(utf8String[utf8Idx] < 0x20U)) {
2649+ switch(utf8String[utf8Idx]) {
2650+ case '\b': encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = '\\'; encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = 'b'; break;
2651+ case '\f': encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = '\\'; encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = 'f'; break;
2652+ case '\n': encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = '\\'; encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = 'n'; break;
2653+ case '\r': encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = '\\'; encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = 'r'; break;
2654+ case '\t': encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = '\\'; encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = 't'; break;
2655+ default: if(JK_EXPECT_F(jk_encode_printf(encodeState, NULL, 0UL, NULL, "\\u%4.4x", utf8String[utf8Idx]))) { return(1); } break;
2656+ }
2657+ } else {
2658+ if(JK_EXPECT_F(utf8String[utf8Idx] == '\"') || JK_EXPECT_F(utf8String[utf8Idx] == '\\') || (JK_EXPECT_F(encodeState->serializeOptionFlags & JKSerializeOptionEscapeForwardSlashes) && JK_EXPECT_F(utf8String[utf8Idx] == '/'))) { encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = '\\'; }
2659+ encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = utf8String[utf8Idx];
2660+ }
2661+ }
2662+ NSCParameterAssert((encodeState->atIndex + 1UL) < encodeState->stringBuffer.bytes.length);
2663+ if(JK_EXPECT_T((encodeState->encodeOption & JKEncodeOptionStringObjTrimQuotes) == 0UL)) { encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = '\"'; }
2664+ jk_encode_updateCache(encodeState, cacheSlot, startingAtIndex, encodeCacheObject);
2665+ return(0);
2666+ }
2667+ }
2668+
2669+ slowUTF8Path:
2670+ {
2671+ CFIndex stringLength = CFStringGetLength((CFStringRef)object);
2672+ CFIndex maxStringUTF8Length = CFStringGetMaximumSizeForEncoding(stringLength, kCFStringEncodingUTF8) + 32L;
2673+
2674+ if(JK_EXPECT_F((size_t)maxStringUTF8Length > encodeState->utf8ConversionBuffer.bytes.length) && JK_EXPECT_F(jk_managedBuffer_resize(&encodeState->utf8ConversionBuffer, maxStringUTF8Length + 1024UL) == NULL)) { jk_encode_error(encodeState, @"Unable to resize temporary buffer."); return(1); }
2675+
2676+ CFIndex usedBytes = 0L, convertedCount = 0L;
2677+ convertedCount = CFStringGetBytes((CFStringRef)object, CFRangeMake(0L, stringLength), kCFStringEncodingUTF8, '?', NO, encodeState->utf8ConversionBuffer.bytes.ptr, encodeState->utf8ConversionBuffer.bytes.length - 16L, &usedBytes);
2678+ if(JK_EXPECT_F(convertedCount != stringLength) || JK_EXPECT_F(usedBytes < 0L)) { jk_encode_error(encodeState, @"An error occurred converting the contents of a NSString to UTF8."); return(1); }
2679+
2680+ if(JK_EXPECT_F((encodeState->atIndex + (maxStringUTF8Length * 2UL) + 256UL) > encodeState->stringBuffer.bytes.length) && JK_EXPECT_F(jk_managedBuffer_resize(&encodeState->stringBuffer, encodeState->atIndex + (maxStringUTF8Length * 2UL) + 1024UL) == NULL)) { jk_encode_error(encodeState, @"Unable to resize temporary buffer."); return(1); }
2681+
2682+ const unsigned char *utf8String = encodeState->utf8ConversionBuffer.bytes.ptr;
2683+
2684+ size_t utf8Idx = 0UL;
2685+ if(JK_EXPECT_T((encodeState->encodeOption & JKEncodeOptionStringObjTrimQuotes) == 0UL)) { encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = '\"'; }
2686+ for(utf8Idx = 0UL; utf8Idx < (size_t)usedBytes; utf8Idx++) {
2687+ NSCParameterAssert(((&encodeState->stringBuffer.bytes.ptr[encodeState->atIndex]) - encodeState->stringBuffer.bytes.ptr) < (ssize_t)encodeState->stringBuffer.bytes.length);
2688+ NSCParameterAssert(encodeState->atIndex < encodeState->stringBuffer.bytes.length);
2689+ NSCParameterAssert((CFIndex)utf8Idx < usedBytes);
2690+ if(JK_EXPECT_F(utf8String[utf8Idx] < 0x20U)) {
2691+ switch(utf8String[utf8Idx]) {
2692+ case '\b': encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = '\\'; encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = 'b'; break;
2693+ case '\f': encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = '\\'; encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = 'f'; break;
2694+ case '\n': encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = '\\'; encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = 'n'; break;
2695+ case '\r': encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = '\\'; encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = 'r'; break;
2696+ case '\t': encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = '\\'; encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = 't'; break;
2697+ default: if(JK_EXPECT_F(jk_encode_printf(encodeState, NULL, 0UL, NULL, "\\u%4.4x", utf8String[utf8Idx]))) { return(1); } break;
2698+ }
2699+ } else {
2700+ if(JK_EXPECT_F(utf8String[utf8Idx] >= 0x80U) && (encodeState->serializeOptionFlags & JKSerializeOptionEscapeUnicode)) {
2701+ const unsigned char *nextValidCharacter = NULL;
2702+ UTF32 u32ch = 0U;
2703+ ConversionResult result;
2704+
2705+ if(JK_EXPECT_F((result = ConvertSingleCodePointInUTF8(&utf8String[utf8Idx], &utf8String[usedBytes], (UTF8 const **)&nextValidCharacter, &u32ch)) != conversionOK)) { jk_encode_error(encodeState, @"Error converting UTF8."); return(1); }
2706+ else {
2707+ utf8Idx = (nextValidCharacter - utf8String) - 1UL;
2708+ if(JK_EXPECT_T(u32ch <= 0xffffU)) { if(JK_EXPECT_F(jk_encode_printf(encodeState, NULL, 0UL, NULL, "\\u%4.4x", u32ch))) { return(1); } }
2709+ else { if(JK_EXPECT_F(jk_encode_printf(encodeState, NULL, 0UL, NULL, "\\u%4.4x\\u%4.4x", (0xd7c0U + (u32ch >> 10)), (0xdc00U + (u32ch & 0x3ffU))))) { return(1); } }
2710+ }
2711+ } else {
2712+ if(JK_EXPECT_F(utf8String[utf8Idx] == '\"') || JK_EXPECT_F(utf8String[utf8Idx] == '\\') || (JK_EXPECT_F(encodeState->serializeOptionFlags & JKSerializeOptionEscapeForwardSlashes) && JK_EXPECT_F(utf8String[utf8Idx] == '/'))) { encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = '\\'; }
2713+ encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = utf8String[utf8Idx];
2714+ }
2715+ }
2716+ }
2717+ NSCParameterAssert((encodeState->atIndex + 1UL) < encodeState->stringBuffer.bytes.length);
2718+ if(JK_EXPECT_T((encodeState->encodeOption & JKEncodeOptionStringObjTrimQuotes) == 0UL)) { encodeState->stringBuffer.bytes.ptr[encodeState->atIndex++] = '\"'; }
2719+ jk_encode_updateCache(encodeState, cacheSlot, startingAtIndex, encodeCacheObject);
2720+ return(0);
2721+ }
2722+ }
2723+ break;
2724+
2725+ case JKClassNumber:
2726+ {
2727+ if(object == (id)kCFBooleanTrue) { return(jk_encode_writen(encodeState, cacheSlot, startingAtIndex, encodeCacheObject, "true", 4UL)); }
2728+ else if(object == (id)kCFBooleanFalse) { return(jk_encode_writen(encodeState, cacheSlot, startingAtIndex, encodeCacheObject, "false", 5UL)); }
2729+
2730+ const char *objCType = [object objCType];
2731+ char anum[256], *aptr = &anum[255];
2732+ int isNegative = 0;
2733+ unsigned long long ullv;
2734+ long long llv;
2735+
2736+ if(JK_EXPECT_F(objCType == NULL) || JK_EXPECT_F(objCType[0] == 0) || JK_EXPECT_F(objCType[1] != 0)) { jk_encode_error(encodeState, @"NSNumber conversion error, unknown type. Type: '%s'", (objCType == NULL) ? "<NULL>" : objCType); return(1); }
2737+
2738+ switch(objCType[0]) {
2739+ case 'c': case 'i': case 's': case 'l': case 'q':
2740+ if(JK_EXPECT_T(CFNumberGetValue((CFNumberRef)object, kCFNumberLongLongType, &llv))) {
2741+ if(llv < 0LL) { ullv = -llv; isNegative = 1; } else { ullv = llv; isNegative = 0; }
2742+ goto convertNumber;
2743+ } else { jk_encode_error(encodeState, @"Unable to get scalar value from number object."); return(1); }
2744+ break;
2745+ case 'C': case 'I': case 'S': case 'L': case 'Q': case 'B':
2746+ if(JK_EXPECT_T(CFNumberGetValue((CFNumberRef)object, kCFNumberLongLongType, &ullv))) {
2747+ convertNumber:
2748+ if(JK_EXPECT_F(ullv < 10ULL)) { *--aptr = ullv + '0'; } else { while(JK_EXPECT_T(ullv > 0ULL)) { *--aptr = (ullv % 10ULL) + '0'; ullv /= 10ULL; NSCParameterAssert(aptr > anum); } }
2749+ if(isNegative) { *--aptr = '-'; }
2750+ NSCParameterAssert(aptr > anum);
2751+ return(jk_encode_writen(encodeState, cacheSlot, startingAtIndex, encodeCacheObject, aptr, &anum[255] - aptr));
2752+ } else { jk_encode_error(encodeState, @"Unable to get scalar value from number object."); return(1); }
2753+ break;
2754+ case 'f': case 'd':
2755+ {
2756+ double dv;
2757+ if(JK_EXPECT_T(CFNumberGetValue((CFNumberRef)object, kCFNumberDoubleType, &dv))) {
2758+ if(JK_EXPECT_F(!isfinite(dv))) { jk_encode_error(encodeState, @"Floating point values must be finite. JSON does not support NaN or Infinity."); return(1); }
2759+ return(jk_encode_printf(encodeState, cacheSlot, startingAtIndex, encodeCacheObject, "%.17g", dv));
2760+ } else { jk_encode_error(encodeState, @"Unable to get floating point value from number object."); return(1); }
2761+ }
2762+ break;
2763+ default: jk_encode_error(encodeState, @"NSNumber conversion error, unknown type. Type: '%c' / 0x%2.2x", objCType[0], objCType[0]); return(1); break;
2764+ }
2765+ }
2766+ break;
2767+
2768+ case JKClassArray:
2769+ {
2770+ int printComma = 0;
2771+ CFIndex arrayCount = CFArrayGetCount((CFArrayRef)object), idx = 0L;
2772+ if(JK_EXPECT_F(jk_encode_write1(encodeState, 1L, "["))) { return(1); }
2773+ if(JK_EXPECT_F(arrayCount > 1020L)) {
2774+ for(id arrayObject in object) { if(JK_EXPECT_T(printComma)) { if(JK_EXPECT_F(jk_encode_write1(encodeState, 0L, ","))) { return(1); } } printComma = 1; if(JK_EXPECT_F(jk_encode_add_atom_to_buffer(encodeState, arrayObject))) { return(1); } }
2775+ } else {
2776+ void *objects[1024];
2777+ CFArrayGetValues((CFArrayRef)object, CFRangeMake(0L, arrayCount), (const void **)objects);
2778+ for(idx = 0L; idx < arrayCount; idx++) { if(JK_EXPECT_T(printComma)) { if(JK_EXPECT_F(jk_encode_write1(encodeState, 0L, ","))) { return(1); } } printComma = 1; if(JK_EXPECT_F(jk_encode_add_atom_to_buffer(encodeState, objects[idx]))) { return(1); } }
2779+ }
2780+ return(jk_encode_write1(encodeState, -1L, "]"));
2781+ }
2782+ break;
2783+
2784+ case JKClassDictionary:
2785+ {
2786+ int printComma = 0;
2787+ CFIndex dictionaryCount = CFDictionaryGetCount((CFDictionaryRef)object), idx = 0L;
2788+ id enumerateObject = JK_EXPECT_F(_jk_encode_prettyPrint) ? [[object allKeys] sortedArrayUsingSelector:@selector(compare:)] : object;
2789+
2790+ if(JK_EXPECT_F(jk_encode_write1(encodeState, 1L, "{"))) { return(1); }
2791+ if(JK_EXPECT_F(_jk_encode_prettyPrint) || JK_EXPECT_F(dictionaryCount > 1020L)) {
2792+ for(id keyObject in enumerateObject) {
2793+ if(JK_EXPECT_T(printComma)) { if(JK_EXPECT_F(jk_encode_write1(encodeState, 0L, ","))) { return(1); } }
2794+ printComma = 1;
2795+ void *keyObjectISA = *((void **)keyObject);
2796+ if(JK_EXPECT_F((keyObjectISA != encodeState->fastClassLookup.stringClass)) && JK_EXPECT_F(([keyObject isKindOfClass:[NSString class]] == NO))) { jk_encode_error(encodeState, @"Key must be a string object."); return(1); }
2797+ if(JK_EXPECT_F(jk_encode_add_atom_to_buffer(encodeState, keyObject))) { return(1); }
2798+ if(JK_EXPECT_F(jk_encode_write1(encodeState, 0L, ":"))) { return(1); }
2799+ if(JK_EXPECT_F(jk_encode_add_atom_to_buffer(encodeState, (void *)CFDictionaryGetValue((CFDictionaryRef)object, keyObject)))) { return(1); }
2800+ }
2801+ } else {
2802+ void *keys[1024], *objects[1024];
2803+ CFDictionaryGetKeysAndValues((CFDictionaryRef)object, (const void **)keys, (const void **)objects);
2804+ for(idx = 0L; idx < dictionaryCount; idx++) {
2805+ if(JK_EXPECT_T(printComma)) { if(JK_EXPECT_F(jk_encode_write1(encodeState, 0L, ","))) { return(1); } }
2806+ printComma = 1;
2807+ void *keyObjectISA = *((void **)keys[idx]);
2808+ if(JK_EXPECT_F(keyObjectISA != encodeState->fastClassLookup.stringClass) && JK_EXPECT_F([(id)keys[idx] isKindOfClass:[NSString class]] == NO)) { jk_encode_error(encodeState, @"Key must be a string object."); return(1); }
2809+ if(JK_EXPECT_F(jk_encode_add_atom_to_buffer(encodeState, keys[idx]))) { return(1); }
2810+ if(JK_EXPECT_F(jk_encode_write1(encodeState, 0L, ":"))) { return(1); }
2811+ if(JK_EXPECT_F(jk_encode_add_atom_to_buffer(encodeState, objects[idx]))) { return(1); }
2812+ }
2813+ }
2814+ return(jk_encode_write1(encodeState, -1L, "}"));
2815+ }
2816+ break;
2817+
2818+ case JKClassNull: return(jk_encode_writen(encodeState, cacheSlot, startingAtIndex, encodeCacheObject, "null", 4UL)); break;
2819+
2820+ default: jk_encode_error(encodeState, @"Unable to serialize object class %@.", NSStringFromClass([object class])); return(1); break;
2821+ }
2822+
2823+ return(0);
2824+}
2825+
2826+
2827+@implementation JKSerializer
2828+
2829++ (id)serializeObject:(id)object options:(JKSerializeOptionFlags)optionFlags encodeOption:(JKEncodeOptionType)encodeOption block:(JKSERIALIZER_BLOCKS_PROTO)block delegate:(id)delegate selector:(SEL)selector error:(NSError **)error
2830+{
2831+ return([[[[self alloc] init] autorelease] serializeObject:object options:optionFlags encodeOption:encodeOption block:block delegate:delegate selector:selector error:error]);
2832+}
2833+
2834+- (id)serializeObject:(id)object options:(JKSerializeOptionFlags)optionFlags encodeOption:(JKEncodeOptionType)encodeOption block:(JKSERIALIZER_BLOCKS_PROTO)block delegate:(id)delegate selector:(SEL)selector error:(NSError **)error
2835+{
2836+#ifndef __BLOCKS__
2837+#pragma unused(block)
2838+#endif
2839+ NSParameterAssert((object != NULL) && (encodeState == NULL) && ((delegate != NULL) ? (block == NULL) : 1) && ((block != NULL) ? (delegate == NULL) : 1) &&
2840+ (((encodeOption & JKEncodeOptionCollectionObj) != 0UL) ? (((encodeOption & JKEncodeOptionStringObj) == 0UL) && ((encodeOption & JKEncodeOptionStringObjTrimQuotes) == 0UL)) : 1) &&
2841+ (((encodeOption & JKEncodeOptionStringObj) != 0UL) ? ((encodeOption & JKEncodeOptionCollectionObj) == 0UL) : 1));
2842+
2843+ id returnObject = NULL;
2844+
2845+ if(encodeState != NULL) { [self releaseState]; }
2846+ if((encodeState = (struct JKEncodeState *)calloc(1UL, sizeof(JKEncodeState))) == NULL) { [NSException raise:NSMallocException format:@"Unable to allocate state structure."]; return(NULL); }
2847+
2848+ if((error != NULL) && (*error != NULL)) { *error = NULL; }
2849+
2850+ if(delegate != NULL) {
2851+ if(selector == NULL) { [NSException raise:NSInvalidArgumentException format:@"The delegate argument is not NULL, but the selector argument is NULL."]; }
2852+ if([delegate respondsToSelector:selector] == NO) { [NSException raise:NSInvalidArgumentException format:@"The serializeUnsupportedClassesUsingDelegate: delegate does not respond to the selector argument."]; }
2853+ encodeState->classFormatterDelegate = delegate;
2854+ encodeState->classFormatterSelector = selector;
2855+ encodeState->classFormatterIMP = (JKClassFormatterIMP)[delegate methodForSelector:selector];
2856+ NSCParameterAssert(encodeState->classFormatterIMP != NULL);
2857+ }
2858+
2859+#ifdef __BLOCKS__
2860+ encodeState->classFormatterBlock = block;
2861+#endif
2862+ encodeState->serializeOptionFlags = optionFlags;
2863+ encodeState->encodeOption = encodeOption;
2864+ encodeState->stringBuffer.roundSizeUpToMultipleOf = (1024UL * 32UL);
2865+ encodeState->utf8ConversionBuffer.roundSizeUpToMultipleOf = 4096UL;
2866+
2867+ unsigned char stackJSONBuffer[JK_JSONBUFFER_SIZE] JK_ALIGNED(64);
2868+ jk_managedBuffer_setToStackBuffer(&encodeState->stringBuffer, stackJSONBuffer, sizeof(stackJSONBuffer));
2869+
2870+ unsigned char stackUTF8Buffer[JK_UTF8BUFFER_SIZE] JK_ALIGNED(64);
2871+ jk_managedBuffer_setToStackBuffer(&encodeState->utf8ConversionBuffer, stackUTF8Buffer, sizeof(stackUTF8Buffer));
2872+
2873+ if(((encodeOption & JKEncodeOptionCollectionObj) != 0UL) && (([object isKindOfClass:[NSArray class]] == NO) && ([object isKindOfClass:[NSDictionary class]] == NO))) { jk_encode_error(encodeState, @"Unable to serialize object class %@, expected a NSArray or NSDictionary.", NSStringFromClass([object class])); goto errorExit; }
2874+ if(((encodeOption & JKEncodeOptionStringObj) != 0UL) && ([object isKindOfClass:[NSString class]] == NO)) { jk_encode_error(encodeState, @"Unable to serialize object class %@, expected a NSString.", NSStringFromClass([object class])); goto errorExit; }
2875+
2876+ if(jk_encode_add_atom_to_buffer(encodeState, object) == 0) {
2877+ BOOL stackBuffer = ((encodeState->stringBuffer.flags & JKManagedBufferMustFree) == 0UL) ? YES : NO;
2878+
2879+ if((encodeState->atIndex < 2UL))
2880+ if((stackBuffer == NO) && ((encodeState->stringBuffer.bytes.ptr = (unsigned char *)reallocf(encodeState->stringBuffer.bytes.ptr, encodeState->atIndex + 16UL)) == NULL)) { jk_encode_error(encodeState, @"Unable to realloc buffer"); goto errorExit; }
2881+
2882+ switch((encodeOption & JKEncodeOptionAsTypeMask)) {
2883+ case JKEncodeOptionAsData:
2884+ if(stackBuffer == YES) { if((returnObject = [(id)CFDataCreate( NULL, encodeState->stringBuffer.bytes.ptr, (CFIndex)encodeState->atIndex) autorelease]) == NULL) { jk_encode_error(encodeState, @"Unable to create NSData object"); } }
2885+ else { if((returnObject = [(id)CFDataCreateWithBytesNoCopy( NULL, encodeState->stringBuffer.bytes.ptr, (CFIndex)encodeState->atIndex, NULL) autorelease]) == NULL) { jk_encode_error(encodeState, @"Unable to create NSData object"); } }
2886+ break;
2887+
2888+ case JKEncodeOptionAsString:
2889+ if(stackBuffer == YES) { if((returnObject = [(id)CFStringCreateWithBytes( NULL, (const UInt8 *)encodeState->stringBuffer.bytes.ptr, (CFIndex)encodeState->atIndex, kCFStringEncodingUTF8, NO) autorelease]) == NULL) { jk_encode_error(encodeState, @"Unable to create NSString object"); } }
2890+ else { if((returnObject = [(id)CFStringCreateWithBytesNoCopy(NULL, (const UInt8 *)encodeState->stringBuffer.bytes.ptr, (CFIndex)encodeState->atIndex, kCFStringEncodingUTF8, NO, NULL) autorelease]) == NULL) { jk_encode_error(encodeState, @"Unable to create NSString object"); } }
2891+ break;
2892+
2893+ default: jk_encode_error(encodeState, @"Unknown encode as type."); break;
2894+ }
2895+
2896+ if((returnObject != NULL) && (stackBuffer == NO)) { encodeState->stringBuffer.flags &= ~JKManagedBufferMustFree; encodeState->stringBuffer.bytes.ptr = NULL; encodeState->stringBuffer.bytes.length = 0UL; }
2897+ }
2898+
2899+errorExit:
2900+ if((encodeState != NULL) && (error != NULL) && (encodeState->error != NULL)) { *error = encodeState->error; encodeState->error = NULL; }
2901+ [self releaseState];
2902+
2903+ return(returnObject);
2904+}
2905+
2906+- (void)releaseState
2907+{
2908+ if(encodeState != NULL) {
2909+ jk_managedBuffer_release(&encodeState->stringBuffer);
2910+ jk_managedBuffer_release(&encodeState->utf8ConversionBuffer);
2911+ free(encodeState); encodeState = NULL;
2912+ }
2913+}
2914+
2915+- (void)dealloc
2916+{
2917+ [self releaseState];
2918+ [super dealloc];
2919+}
2920+
2921+@end
2922+
2923+@implementation NSString (JSONKitSerializing)
2924+
2925+////////////
2926+#pragma mark Methods for serializing a single NSString.
2927+////////////
2928+
2929+// Useful for those who need to serialize just a NSString. Otherwise you would have to do something like [NSArray arrayWithObject:stringToBeJSONSerialized], serializing the array, and then chopping of the extra ^\[.*\]$ square brackets.
2930+
2931+// NSData returning methods...
2932+
2933+- (NSData *)JSONData
2934+{
2935+ return([self JSONDataWithOptions:JKSerializeOptionNone includeQuotes:YES error:NULL]);
2936+}
2937+
2938+- (NSData *)JSONDataWithOptions:(JKSerializeOptionFlags)serializeOptions includeQuotes:(BOOL)includeQuotes error:(NSError **)error
2939+{
2940+ return([JKSerializer serializeObject:self options:serializeOptions encodeOption:(JKEncodeOptionAsData | ((includeQuotes == NO) ? JKEncodeOptionStringObjTrimQuotes : 0UL) | JKEncodeOptionStringObj) block:NULL delegate:NULL selector:NULL error:error]);
2941+}
2942+
2943+// NSString returning methods...
2944+
2945+- (NSString *)JSONString
2946+{
2947+ return([self JSONStringWithOptions:JKSerializeOptionNone includeQuotes:YES error:NULL]);
2948+}
2949+
2950+- (NSString *)JSONStringWithOptions:(JKSerializeOptionFlags)serializeOptions includeQuotes:(BOOL)includeQuotes error:(NSError **)error
2951+{
2952+ return([JKSerializer serializeObject:self options:serializeOptions encodeOption:(JKEncodeOptionAsString | ((includeQuotes == NO) ? JKEncodeOptionStringObjTrimQuotes : 0UL) | JKEncodeOptionStringObj) block:NULL delegate:NULL selector:NULL error:error]);
2953+}
2954+
2955+@end
2956+
2957+@implementation NSArray (JSONKitSerializing)
2958+
2959+// NSData returning methods...
2960+
2961+- (NSData *)JSONData
2962+{
2963+ return([JKSerializer serializeObject:self options:JKSerializeOptionNone encodeOption:(JKEncodeOptionAsData | JKEncodeOptionCollectionObj) block:NULL delegate:NULL selector:NULL error:NULL]);
2964+}
2965+
2966+- (NSData *)JSONDataWithOptions:(JKSerializeOptionFlags)serializeOptions error:(NSError **)error
2967+{
2968+ return([JKSerializer serializeObject:self options:serializeOptions encodeOption:(JKEncodeOptionAsData | JKEncodeOptionCollectionObj) block:NULL delegate:NULL selector:NULL error:error]);
2969+}
2970+
2971+- (NSData *)JSONDataWithOptions:(JKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingDelegate:(id)delegate selector:(SEL)selector error:(NSError **)error
2972+{
2973+ return([JKSerializer serializeObject:self options:serializeOptions encodeOption:(JKEncodeOptionAsData | JKEncodeOptionCollectionObj) block:NULL delegate:delegate selector:selector error:error]);
2974+}
2975+
2976+// NSString returning methods...
2977+
2978+- (NSString *)JSONString
2979+{
2980+ return([JKSerializer serializeObject:self options:JKSerializeOptionNone encodeOption:(JKEncodeOptionAsString | JKEncodeOptionCollectionObj) block:NULL delegate:NULL selector:NULL error:NULL]);
2981+}
2982+
2983+- (NSString *)JSONStringWithOptions:(JKSerializeOptionFlags)serializeOptions error:(NSError **)error
2984+{
2985+ return([JKSerializer serializeObject:self options:serializeOptions encodeOption:(JKEncodeOptionAsString | JKEncodeOptionCollectionObj) block:NULL delegate:NULL selector:NULL error:error]);
2986+}
2987+
2988+- (NSString *)JSONStringWithOptions:(JKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingDelegate:(id)delegate selector:(SEL)selector error:(NSError **)error
2989+{
2990+ return([JKSerializer serializeObject:self options:serializeOptions encodeOption:(JKEncodeOptionAsString | JKEncodeOptionCollectionObj) block:NULL delegate:delegate selector:selector error:error]);
2991+}
2992+
2993+@end
2994+
2995+@implementation NSDictionary (JSONKitSerializing)
2996+
2997+// NSData returning methods...
2998+
2999+- (NSData *)JSONData
3000+{
3001+ return([JKSerializer serializeObject:self options:JKSerializeOptionNone encodeOption:(JKEncodeOptionAsData | JKEncodeOptionCollectionObj) block:NULL delegate:NULL selector:NULL error:NULL]);
3002+}
3003+
3004+- (NSData *)JSONDataWithOptions:(JKSerializeOptionFlags)serializeOptions error:(NSError **)error
3005+{
3006+ return([JKSerializer serializeObject:self options:serializeOptions encodeOption:(JKEncodeOptionAsData | JKEncodeOptionCollectionObj) block:NULL delegate:NULL selector:NULL error:error]);
3007+}
3008+
3009+- (NSData *)JSONDataWithOptions:(JKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingDelegate:(id)delegate selector:(SEL)selector error:(NSError **)error
3010+{
3011+ return([JKSerializer serializeObject:self options:serializeOptions encodeOption:(JKEncodeOptionAsData | JKEncodeOptionCollectionObj) block:NULL delegate:delegate selector:selector error:error]);
3012+}
3013+
3014+// NSString returning methods...
3015+
3016+- (NSString *)JSONString
3017+{
3018+ return([JKSerializer serializeObject:self options:JKSerializeOptionNone encodeOption:(JKEncodeOptionAsString | JKEncodeOptionCollectionObj) block:NULL delegate:NULL selector:NULL error:NULL]);
3019+}
3020+
3021+- (NSString *)JSONStringWithOptions:(JKSerializeOptionFlags)serializeOptions error:(NSError **)error
3022+{
3023+ return([JKSerializer serializeObject:self options:serializeOptions encodeOption:(JKEncodeOptionAsString | JKEncodeOptionCollectionObj) block:NULL delegate:NULL selector:NULL error:error]);
3024+}
3025+
3026+- (NSString *)JSONStringWithOptions:(JKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingDelegate:(id)delegate selector:(SEL)selector error:(NSError **)error
3027+{
3028+ return([JKSerializer serializeObject:self options:serializeOptions encodeOption:(JKEncodeOptionAsString | JKEncodeOptionCollectionObj) block:NULL delegate:delegate selector:selector error:error]);
3029+}
3030+
3031+@end
3032+
3033+
3034+#ifdef __BLOCKS__
3035+
3036+@implementation NSArray (JSONKitSerializingBlockAdditions)
3037+
3038+- (NSData *)JSONDataWithOptions:(JKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingBlock:(id(^)(id object))block error:(NSError **)error
3039+{
3040+ return([JKSerializer serializeObject:self options:serializeOptions encodeOption:(JKEncodeOptionAsData | JKEncodeOptionCollectionObj) block:block delegate:NULL selector:NULL error:error]);
3041+}
3042+
3043+- (NSString *)JSONStringWithOptions:(JKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingBlock:(id(^)(id object))block error:(NSError **)error
3044+{
3045+ return([JKSerializer serializeObject:self options:serializeOptions encodeOption:(JKEncodeOptionAsString | JKEncodeOptionCollectionObj) block:block delegate:NULL selector:NULL error:error]);
3046+}
3047+
3048+@end
3049+
3050+@implementation NSDictionary (JSONKitSerializingBlockAdditions)
3051+
3052+- (NSData *)JSONDataWithOptions:(JKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingBlock:(id(^)(id object))block error:(NSError **)error
3053+{
3054+ return([JKSerializer serializeObject:self options:serializeOptions encodeOption:(JKEncodeOptionAsData | JKEncodeOptionCollectionObj) block:block delegate:NULL selector:NULL error:error]);
3055+}
3056+
3057+- (NSString *)JSONStringWithOptions:(JKSerializeOptionFlags)serializeOptions serializeUnsupportedClassesUsingBlock:(id(^)(id object))block error:(NSError **)error
3058+{
3059+ return([JKSerializer serializeObject:self options:serializeOptions encodeOption:(JKEncodeOptionAsString | JKEncodeOptionCollectionObj) block:block delegate:NULL selector:NULL error:error]);
3060+}
3061+
3062+@end
3063+
3064+#endif // __BLOCKS__
3065+
parsers/test_JSONKit/bin/test-JSONKitnew file

Binary file not shown.

parsers/test_JSONKit/test-JSONKit.xcodeproj/project.pbxprojnew file+252
@@ -0,0 +1,252 @@
1+// !$*UTF8*$!
2+{
3+ archiveVersion = 1;
4+ classes = {
5+ };
6+ objectVersion = 46;
7+ objects = {
8+
9+/* Begin PBXBuildFile section */
10+ 0388E0421D57F15D00BA0899 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 0388E0411D57F15D00BA0899 /* main.m */; };
11+ 0388E04A1D57F16400BA0899 /* JSONKit.m in Sources */ = {isa = PBXBuildFile; fileRef = 0388E0491D57F16400BA0899 /* JSONKit.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
12+/* End PBXBuildFile section */
13+
14+/* Begin PBXCopyFilesBuildPhase section */
15+ 0388E03C1D57F15D00BA0899 /* CopyFiles */ = {
16+ isa = PBXCopyFilesBuildPhase;
17+ buildActionMask = 2147483647;
18+ dstPath = /usr/share/man/man1/;
19+ dstSubfolderSpec = 0;
20+ files = (
21+ );
22+ runOnlyForDeploymentPostprocessing = 1;
23+ };
24+/* End PBXCopyFilesBuildPhase section */
25+
26+/* Begin PBXFileReference section */
27+ 0388E03E1D57F15D00BA0899 /* test-JSONKit */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "test-JSONKit"; sourceTree = BUILT_PRODUCTS_DIR; };
28+ 0388E0411D57F15D00BA0899 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
29+ 0388E0481D57F16400BA0899 /* JSONKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSONKit.h; sourceTree = "<group>"; };
30+ 0388E0491D57F16400BA0899 /* JSONKit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JSONKit.m; sourceTree = "<group>"; };
31+/* End PBXFileReference section */
32+
33+/* Begin PBXFrameworksBuildPhase section */
34+ 0388E03B1D57F15D00BA0899 /* Frameworks */ = {
35+ isa = PBXFrameworksBuildPhase;
36+ buildActionMask = 2147483647;
37+ files = (
38+ );
39+ runOnlyForDeploymentPostprocessing = 0;
40+ };
41+/* End PBXFrameworksBuildPhase section */
42+
43+/* Begin PBXGroup section */
44+ 0388E0351D57F15D00BA0899 = {
45+ isa = PBXGroup;
46+ children = (
47+ 0388E0481D57F16400BA0899 /* JSONKit.h */,
48+ 0388E0491D57F16400BA0899 /* JSONKit.m */,
49+ 0388E0401D57F15D00BA0899 /* test-JSONKit */,
50+ 0388E03F1D57F15D00BA0899 /* Products */,
51+ );
52+ sourceTree = "<group>";
53+ };
54+ 0388E03F1D57F15D00BA0899 /* Products */ = {
55+ isa = PBXGroup;
56+ children = (
57+ 0388E03E1D57F15D00BA0899 /* test-JSONKit */,
58+ );
59+ name = Products;
60+ sourceTree = "<group>";
61+ };
62+ 0388E0401D57F15D00BA0899 /* test-JSONKit */ = {
63+ isa = PBXGroup;
64+ children = (
65+ 0388E0411D57F15D00BA0899 /* main.m */,
66+ );
67+ path = "test-JSONKit";
68+ sourceTree = "<group>";
69+ };
70+/* End PBXGroup section */
71+
72+/* Begin PBXNativeTarget section */
73+ 0388E03D1D57F15D00BA0899 /* test-JSONKit */ = {
74+ isa = PBXNativeTarget;
75+ buildConfigurationList = 0388E0451D57F15D00BA0899 /* Build configuration list for PBXNativeTarget "test-JSONKit" */;
76+ buildPhases = (
77+ 0388E03A1D57F15D00BA0899 /* Sources */,
78+ 0388E03B1D57F15D00BA0899 /* Frameworks */,
79+ 0388E03C1D57F15D00BA0899 /* CopyFiles */,
80+ );
81+ buildRules = (
82+ );
83+ dependencies = (
84+ );
85+ name = "test-JSONKit";
86+ productName = "test-JSONKit";
87+ productReference = 0388E03E1D57F15D00BA0899 /* test-JSONKit */;
88+ productType = "com.apple.product-type.tool";
89+ };
90+/* End PBXNativeTarget section */
91+
92+/* Begin PBXProject section */
93+ 0388E0361D57F15D00BA0899 /* Project object */ = {
94+ isa = PBXProject;
95+ attributes = {
96+ LastUpgradeCheck = 0730;
97+ ORGANIZATIONNAME = "Nicolas Seriot";
98+ TargetAttributes = {
99+ 0388E03D1D57F15D00BA0899 = {
100+ CreatedOnToolsVersion = 7.3;
101+ };
102+ };
103+ };
104+ buildConfigurationList = 0388E0391D57F15D00BA0899 /* Build configuration list for PBXProject "test-JSONKit" */;
105+ compatibilityVersion = "Xcode 3.2";
106+ developmentRegion = English;
107+ hasScannedForEncodings = 0;
108+ knownRegions = (
109+ en,
110+ );
111+ mainGroup = 0388E0351D57F15D00BA0899;
112+ productRefGroup = 0388E03F1D57F15D00BA0899 /* Products */;
113+ projectDirPath = "";
114+ projectRoot = "";
115+ targets = (
116+ 0388E03D1D57F15D00BA0899 /* test-JSONKit */,
117+ );
118+ };
119+/* End PBXProject section */
120+
121+/* Begin PBXSourcesBuildPhase section */
122+ 0388E03A1D57F15D00BA0899 /* Sources */ = {
123+ isa = PBXSourcesBuildPhase;
124+ buildActionMask = 2147483647;
125+ files = (
126+ 0388E04A1D57F16400BA0899 /* JSONKit.m in Sources */,
127+ 0388E0421D57F15D00BA0899 /* main.m in Sources */,
128+ );
129+ runOnlyForDeploymentPostprocessing = 0;
130+ };
131+/* End PBXSourcesBuildPhase section */
132+
133+/* Begin XCBuildConfiguration section */
134+ 0388E0431D57F15D00BA0899 /* Debug */ = {
135+ isa = XCBuildConfiguration;
136+ buildSettings = {
137+ ALWAYS_SEARCH_USER_PATHS = NO;
138+ CLANG_ANALYZER_NONNULL = YES;
139+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
140+ CLANG_CXX_LIBRARY = "libc++";
141+ CLANG_ENABLE_MODULES = YES;
142+ CLANG_ENABLE_OBJC_ARC = YES;
143+ CLANG_WARN_BOOL_CONVERSION = YES;
144+ CLANG_WARN_CONSTANT_CONVERSION = YES;
145+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
146+ CLANG_WARN_EMPTY_BODY = YES;
147+ CLANG_WARN_ENUM_CONVERSION = YES;
148+ CLANG_WARN_INT_CONVERSION = YES;
149+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
150+ CLANG_WARN_UNREACHABLE_CODE = YES;
151+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
152+ CODE_SIGN_IDENTITY = "-";
153+ COPY_PHASE_STRIP = NO;
154+ DEBUG_INFORMATION_FORMAT = dwarf;
155+ ENABLE_STRICT_OBJC_MSGSEND = YES;
156+ ENABLE_TESTABILITY = YES;
157+ GCC_C_LANGUAGE_STANDARD = gnu99;
158+ GCC_DYNAMIC_NO_PIC = NO;
159+ GCC_NO_COMMON_BLOCKS = YES;
160+ GCC_OPTIMIZATION_LEVEL = 0;
161+ GCC_PREPROCESSOR_DEFINITIONS = (
162+ "DEBUG=1",
163+ "$(inherited)",
164+ );
165+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
166+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
167+ GCC_WARN_UNDECLARED_SELECTOR = YES;
168+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
169+ GCC_WARN_UNUSED_FUNCTION = YES;
170+ GCC_WARN_UNUSED_VARIABLE = YES;
171+ MACOSX_DEPLOYMENT_TARGET = 10.11;
172+ MTL_ENABLE_DEBUG_INFO = YES;
173+ ONLY_ACTIVE_ARCH = YES;
174+ SDKROOT = macosx;
175+ };
176+ name = Debug;
177+ };
178+ 0388E0441D57F15D00BA0899 /* Release */ = {
179+ isa = XCBuildConfiguration;
180+ buildSettings = {
181+ ALWAYS_SEARCH_USER_PATHS = NO;
182+ CLANG_ANALYZER_NONNULL = YES;
183+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
184+ CLANG_CXX_LIBRARY = "libc++";
185+ CLANG_ENABLE_MODULES = YES;
186+ CLANG_ENABLE_OBJC_ARC = YES;
187+ CLANG_WARN_BOOL_CONVERSION = YES;
188+ CLANG_WARN_CONSTANT_CONVERSION = YES;
189+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
190+ CLANG_WARN_EMPTY_BODY = YES;
191+ CLANG_WARN_ENUM_CONVERSION = YES;
192+ CLANG_WARN_INT_CONVERSION = YES;
193+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
194+ CLANG_WARN_UNREACHABLE_CODE = YES;
195+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
196+ CODE_SIGN_IDENTITY = "-";
197+ COPY_PHASE_STRIP = NO;
198+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
199+ ENABLE_NS_ASSERTIONS = NO;
200+ ENABLE_STRICT_OBJC_MSGSEND = YES;
201+ GCC_C_LANGUAGE_STANDARD = gnu99;
202+ GCC_NO_COMMON_BLOCKS = YES;
203+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
204+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
205+ GCC_WARN_UNDECLARED_SELECTOR = YES;
206+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
207+ GCC_WARN_UNUSED_FUNCTION = YES;
208+ GCC_WARN_UNUSED_VARIABLE = YES;
209+ MACOSX_DEPLOYMENT_TARGET = 10.11;
210+ MTL_ENABLE_DEBUG_INFO = NO;
211+ SDKROOT = macosx;
212+ };
213+ name = Release;
214+ };
215+ 0388E0461D57F15D00BA0899 /* Debug */ = {
216+ isa = XCBuildConfiguration;
217+ buildSettings = {
218+ PRODUCT_NAME = "$(TARGET_NAME)";
219+ };
220+ name = Debug;
221+ };
222+ 0388E0471D57F15D00BA0899 /* Release */ = {
223+ isa = XCBuildConfiguration;
224+ buildSettings = {
225+ PRODUCT_NAME = "$(TARGET_NAME)";
226+ };
227+ name = Release;
228+ };
229+/* End XCBuildConfiguration section */
230+
231+/* Begin XCConfigurationList section */
232+ 0388E0391D57F15D00BA0899 /* Build configuration list for PBXProject "test-JSONKit" */ = {
233+ isa = XCConfigurationList;
234+ buildConfigurations = (
235+ 0388E0431D57F15D00BA0899 /* Debug */,
236+ 0388E0441D57F15D00BA0899 /* Release */,
237+ );
238+ defaultConfigurationIsVisible = 0;
239+ defaultConfigurationName = Release;
240+ };
241+ 0388E0451D57F15D00BA0899 /* Build configuration list for PBXNativeTarget "test-JSONKit" */ = {
242+ isa = XCConfigurationList;
243+ buildConfigurations = (
244+ 0388E0461D57F15D00BA0899 /* Debug */,
245+ 0388E0471D57F15D00BA0899 /* Release */,
246+ );
247+ defaultConfigurationIsVisible = 0;
248+ };
249+/* End XCConfigurationList section */
250+ };
251+ rootObject = 0388E0361D57F15D00BA0899 /* Project object */;
252+}
parsers/test_JSONKit/test-JSONKit.xcodeproj/project.xcworkspace/contents.xcworkspacedatanew file+7
@@ -0,0 +1,7 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<Workspace
3+ version = "1.0">
4+ <FileRef
5+ location = "self:test-JSONKit.xcodeproj">
6+ </FileRef>
7+</Workspace>
parsers/test_JSONKit/test-JSONKit.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstatenew file

Binary file not shown.

parsers/test_JSONKit/test-JSONKit.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test-JSONKit.xcschemenew file+91
@@ -0,0 +1,91 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<Scheme
3+ LastUpgradeVersion = "0730"
4+ version = "1.3">
5+ <BuildAction
6+ parallelizeBuildables = "YES"
7+ buildImplicitDependencies = "YES">
8+ <BuildActionEntries>
9+ <BuildActionEntry
10+ buildForTesting = "YES"
11+ buildForRunning = "YES"
12+ buildForProfiling = "YES"
13+ buildForArchiving = "YES"
14+ buildForAnalyzing = "YES">
15+ <BuildableReference
16+ BuildableIdentifier = "primary"
17+ BlueprintIdentifier = "0388E03D1D57F15D00BA0899"
18+ BuildableName = "test-JSONKit"
19+ BlueprintName = "test-JSONKit"
20+ ReferencedContainer = "container:test-JSONKit.xcodeproj">
21+ </BuildableReference>
22+ </BuildActionEntry>
23+ </BuildActionEntries>
24+ </BuildAction>
25+ <TestAction
26+ buildConfiguration = "Debug"
27+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
28+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
29+ shouldUseLaunchSchemeArgsEnv = "YES">
30+ <Testables>
31+ </Testables>
32+ <MacroExpansion>
33+ <BuildableReference
34+ BuildableIdentifier = "primary"
35+ BlueprintIdentifier = "0388E03D1D57F15D00BA0899"
36+ BuildableName = "test-JSONKit"
37+ BlueprintName = "test-JSONKit"
38+ ReferencedContainer = "container:test-JSONKit.xcodeproj">
39+ </BuildableReference>
40+ </MacroExpansion>
41+ <AdditionalOptions>
42+ </AdditionalOptions>
43+ </TestAction>
44+ <LaunchAction
45+ buildConfiguration = "Debug"
46+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
47+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
48+ launchStyle = "0"
49+ useCustomWorkingDirectory = "NO"
50+ ignoresPersistentStateOnLaunch = "NO"
51+ debugDocumentVersioning = "YES"
52+ debugServiceExtension = "internal"
53+ allowLocationSimulation = "YES">
54+ <BuildableProductRunnable
55+ runnableDebuggingMode = "0">
56+ <BuildableReference
57+ BuildableIdentifier = "primary"
58+ BlueprintIdentifier = "0388E03D1D57F15D00BA0899"
59+ BuildableName = "test-JSONKit"
60+ BlueprintName = "test-JSONKit"
61+ ReferencedContainer = "container:test-JSONKit.xcodeproj">
62+ </BuildableReference>
63+ </BuildableProductRunnable>
64+ <AdditionalOptions>
65+ </AdditionalOptions>
66+ </LaunchAction>
67+ <ProfileAction
68+ buildConfiguration = "Release"
69+ shouldUseLaunchSchemeArgsEnv = "YES"
70+ savedToolIdentifier = ""
71+ useCustomWorkingDirectory = "NO"
72+ debugDocumentVersioning = "YES">
73+ <BuildableProductRunnable
74+ runnableDebuggingMode = "0">
75+ <BuildableReference
76+ BuildableIdentifier = "primary"
77+ BlueprintIdentifier = "0388E03D1D57F15D00BA0899"
78+ BuildableName = "test-JSONKit"
79+ BlueprintName = "test-JSONKit"
80+ ReferencedContainer = "container:test-JSONKit.xcodeproj">
81+ </BuildableReference>
82+ </BuildableProductRunnable>
83+ </ProfileAction>
84+ <AnalyzeAction
85+ buildConfiguration = "Debug">
86+ </AnalyzeAction>
87+ <ArchiveAction
88+ buildConfiguration = "Release"
89+ revealArchiveInOrganizer = "YES">
90+ </ArchiveAction>
91+</Scheme>
parsers/test_JSONKit/test-JSONKit.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plistnew file+22
@@ -0,0 +1,22 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+<plist version="1.0">
4+<dict>
5+ <key>SchemeUserState</key>
6+ <dict>
7+ <key>test-JSONKit.xcscheme</key>
8+ <dict>
9+ <key>orderHint</key>
10+ <integer>0</integer>
11+ </dict>
12+ </dict>
13+ <key>SuppressBuildableAutocreation</key>
14+ <dict>
15+ <key>0388E03D1D57F15D00BA0899</key>
16+ <dict>
17+ <key>primary</key>
18+ <true/>
19+ </dict>
20+ </dict>
21+</dict>
22+</plist>
parsers/test_JSONKit/test-JSONKit/main.mnew file+73
@@ -0,0 +1,73 @@
1+//
2+// main.m
3+// test-JSONKit
4+//
5+// Created by nst on 08/08/16.
6+// Copyright © 2016 Nicolas Seriot. All rights reserved.
7+//
8+
9+#import <Foundation/Foundation.h>
10+#import "JSONKit.h" // https://github.com/johnezang/JSONKit
11+
12+#include <stdio.h>
13+#include <stdlib.h>
14+#include <sys/stat.h>
15+#include <dirent.h>
16+#include <stdio.h>
17+#include <string.h>
18+
19+typedef enum testStatus {ERROR, PASS, FAIL} TestStatus;
20+
21+TestStatus test_file(char* filename, int printParsingResults) {
22+
23+ NSString *path = [NSString stringWithCString:filename encoding:NSUTF8StringEncoding];
24+
25+ //NSLog(@"--- %@", path);
26+
27+// if([path hasSuffix:@"n_structure_100000_opening_arrays.json"]) return ERROR;
28+// if([path hasSuffix:@"n_structure_empty.json"]) return ERROR;
29+
30+ NSData *data = [NSData dataWithContentsOfFile:path];
31+
32+ JSONDecoder *decoder = [JSONDecoder decoderWithParseOptions:JKParseOptionNone];
33+
34+ NSError *error = nil;
35+ id o = [decoder objectWithData:data error:&error];
36+
37+ if (printParsingResults) {
38+ NSLog(@"--------------------------------\n");
39+ NSLog(@"-- file: %@\n", path);
40+ NSLog(@"-- contents: %@\n", data);
41+ NSLog(@"-- parsed: %d\n", o != NULL);
42+ if(o != NULL) {
43+ NSLog(@"-- o: %@", o);
44+ }
45+ }
46+
47+ // if (value == NULL) {
48+ // fprintf(stderr, "Unable to parse data\n");
49+ // free(file_contents);
50+ // return 1;
51+ // }
52+
53+ return o != nil ? PASS : FAIL;
54+}
55+
56+int main(int argc, const char * argv[]) {
57+ @autoreleasepool {
58+
59+ const char* path = argv[1];
60+
61+ int printParsingResults = 0;
62+
63+ int result = test_file(path, printParsingResults);
64+
65+ if (result == PASS) {
66+ return 0;
67+ } else {
68+ return 1;
69+ }
70+
71+ }
72+ return 0;
73+}
parsers/test_Lua_JSON/JSON.luanew file+1451
@@ -0,0 +1,1451 @@
1+-- -*- coding: utf-8 -*-
2+--
3+-- Simple JSON encoding and decoding in pure Lua.
4+--
5+-- Copyright 2010-2016 Jeffrey Friedl
6+-- http://regex.info/blog/
7+-- Latest version: http://regex.info/blog/lua/json
8+--
9+-- This code is released under a Creative Commons CC-BY "Attribution" License:
10+-- http://creativecommons.org/licenses/by/3.0/deed.en_US
11+--
12+-- It can be used for any purpose so long as the copyright notice above,
13+-- the web-page links above, and the 'AUTHOR_NOTE' string below are
14+-- maintained. Enjoy.
15+--
16+local VERSION = 20160916.19 -- version history at end of file
17+local AUTHOR_NOTE = "-[ JSON.lua package by Jeffrey Friedl (http://regex.info/blog/lua/json) version 20160916.19 ]-"
18+
19+--
20+-- The 'AUTHOR_NOTE' variable exists so that information about the source
21+-- of the package is maintained even in compiled versions. It's also
22+-- included in OBJDEF below mostly to quiet warnings about unused variables.
23+--
24+local OBJDEF = {
25+ VERSION = VERSION,
26+ AUTHOR_NOTE = AUTHOR_NOTE,
27+}
28+
29+
30+--
31+-- Simple JSON encoding and decoding in pure Lua.
32+-- JSON definition: http://www.json.org/
33+--
34+--
35+-- JSON = assert(loadfile "JSON.lua")() -- one-time load of the routines
36+--
37+-- local lua_value = JSON:decode(raw_json_text)
38+--
39+-- local raw_json_text = JSON:encode(lua_table_or_value)
40+-- local pretty_json_text = JSON:encode_pretty(lua_table_or_value) -- "pretty printed" version for human readability
41+--
42+--
43+--
44+-- DECODING (from a JSON string to a Lua table)
45+--
46+--
47+-- JSON = assert(loadfile "JSON.lua")() -- one-time load of the routines
48+--
49+-- local lua_value = JSON:decode(raw_json_text)
50+--
51+-- If the JSON text is for an object or an array, e.g.
52+-- { "what": "books", "count": 3 }
53+-- or
54+-- [ "Larry", "Curly", "Moe" ]
55+--
56+-- the result is a Lua table, e.g.
57+-- { what = "books", count = 3 }
58+-- or
59+-- { "Larry", "Curly", "Moe" }
60+--
61+--
62+-- The encode and decode routines accept an optional second argument,
63+-- "etc", which is not used during encoding or decoding, but upon error
64+-- is passed along to error handlers. It can be of any type (including nil).
65+--
66+--
67+--
68+-- ERROR HANDLING
69+--
70+-- With most errors during decoding, this code calls
71+--
72+-- JSON:onDecodeError(message, text, location, etc)
73+--
74+-- with a message about the error, and if known, the JSON text being
75+-- parsed and the byte count where the problem was discovered. You can
76+-- replace the default JSON:onDecodeError() with your own function.
77+--
78+-- The default onDecodeError() merely augments the message with data
79+-- about the text and the location if known (and if a second 'etc'
80+-- argument had been provided to decode(), its value is tacked onto the
81+-- message as well), and then calls JSON.assert(), which itself defaults
82+-- to Lua's built-in assert(), and can also be overridden.
83+--
84+-- For example, in an Adobe Lightroom plugin, you might use something like
85+--
86+-- function JSON:onDecodeError(message, text, location, etc)
87+-- LrErrors.throwUserError("Internal Error: invalid JSON data")
88+-- end
89+--
90+-- or even just
91+--
92+-- function JSON.assert(message)
93+-- LrErrors.throwUserError("Internal Error: " .. message)
94+-- end
95+--
96+-- If JSON:decode() is passed a nil, this is called instead:
97+--
98+-- JSON:onDecodeOfNilError(message, nil, nil, etc)
99+--
100+-- and if JSON:decode() is passed HTML instead of JSON, this is called:
101+--
102+-- JSON:onDecodeOfHTMLError(message, text, nil, etc)
103+--
104+-- The use of the fourth 'etc' argument allows stronger coordination
105+-- between decoding and error reporting, especially when you provide your
106+-- own error-handling routines. Continuing with the the Adobe Lightroom
107+-- plugin example:
108+--
109+-- function JSON:onDecodeError(message, text, location, etc)
110+-- local note = "Internal Error: invalid JSON data"
111+-- if type(etc) = 'table' and etc.photo then
112+-- note = note .. " while processing for " .. etc.photo:getFormattedMetadata('fileName')
113+-- end
114+-- LrErrors.throwUserError(note)
115+-- end
116+--
117+-- :
118+-- :
119+--
120+-- for i, photo in ipairs(photosToProcess) do
121+-- :
122+-- :
123+-- local data = JSON:decode(someJsonText, { photo = photo })
124+-- :
125+-- :
126+-- end
127+--
128+--
129+--
130+--
131+--
132+-- DECODING AND STRICT TYPES
133+--
134+-- Because both JSON objects and JSON arrays are converted to Lua tables,
135+-- it's not normally possible to tell which original JSON type a
136+-- particular Lua table was derived from, or guarantee decode-encode
137+-- round-trip equivalency.
138+--
139+-- However, if you enable strictTypes, e.g.
140+--
141+-- JSON = assert(loadfile "JSON.lua")() --load the routines
142+-- JSON.strictTypes = true
143+--
144+-- then the Lua table resulting from the decoding of a JSON object or
145+-- JSON array is marked via Lua metatable, so that when re-encoded with
146+-- JSON:encode() it ends up as the appropriate JSON type.
147+--
148+-- (This is not the default because other routines may not work well with
149+-- tables that have a metatable set, for example, Lightroom API calls.)
150+--
151+--
152+-- ENCODING (from a lua table to a JSON string)
153+--
154+-- JSON = assert(loadfile "JSON.lua")() -- one-time load of the routines
155+--
156+-- local raw_json_text = JSON:encode(lua_table_or_value)
157+-- local pretty_json_text = JSON:encode_pretty(lua_table_or_value) -- "pretty printed" version for human readability
158+-- local custom_pretty = JSON:encode(lua_table_or_value, etc, { pretty = true, indent = "| ", align_keys = false })
159+--
160+-- On error during encoding, this code calls:
161+--
162+-- JSON:onEncodeError(message, etc)
163+--
164+-- which you can override in your local JSON object.
165+--
166+-- The 'etc' in the error call is the second argument to encode()
167+-- and encode_pretty(), or nil if it wasn't provided.
168+--
169+--
170+-- ENCODING OPTIONS
171+--
172+-- An optional third argument, a table of options, can be provided to encode().
173+--
174+-- encode_options = {
175+-- -- options for making "pretty" human-readable JSON (see "PRETTY-PRINTING" below)
176+-- pretty = true,
177+-- indent = " ",
178+-- align_keys = false,
179+--
180+-- -- other output-related options
181+-- null = "\0", -- see "ENCODING JSON NULL VALUES" below
182+-- stringsAreUtf8 = false, -- see "HANDLING UNICODE LINE AND PARAGRAPH SEPARATORS FOR JAVA" below
183+-- }
184+--
185+-- json_string = JSON:encode(mytable, etc, encode_options)
186+--
187+--
188+--
189+-- For reference, the defaults are:
190+--
191+-- pretty = false
192+-- null = nil,
193+-- stringsAreUtf8 = false,
194+--
195+--
196+--
197+-- PRETTY-PRINTING
198+--
199+-- Enabling the 'pretty' encode option helps generate human-readable JSON.
200+--
201+-- pretty = JSON:encode(val, etc, {
202+-- pretty = true,
203+-- indent = " ",
204+-- align_keys = false,
205+-- })
206+--
207+-- encode_pretty() is also provided: it's identical to encode() except
208+-- that encode_pretty() provides a default options table if none given in the call:
209+--
210+-- { pretty = true, align_keys = false, indent = " " }
211+--
212+-- For example, if
213+--
214+-- JSON:encode(data)
215+--
216+-- produces:
217+--
218+-- {"city":"Kyoto","climate":{"avg_temp":16,"humidity":"high","snowfall":"minimal"},"country":"Japan","wards":11}
219+--
220+-- then
221+--
222+-- JSON:encode_pretty(data)
223+--
224+-- produces:
225+--
226+-- {
227+-- "city": "Kyoto",
228+-- "climate": {
229+-- "avg_temp": 16,
230+-- "humidity": "high",
231+-- "snowfall": "minimal"
232+-- },
233+-- "country": "Japan",
234+-- "wards": 11
235+-- }
236+--
237+-- The following three lines return identical results:
238+-- JSON:encode_pretty(data)
239+-- JSON:encode_pretty(data, nil, { pretty = true, align_keys = false, indent = " " })
240+-- JSON:encode (data, nil, { pretty = true, align_keys = false, indent = " " })
241+--
242+-- An example of setting your own indent string:
243+--
244+-- JSON:encode_pretty(data, nil, { pretty = true, indent = "| " })
245+--
246+-- produces:
247+--
248+-- {
249+-- | "city": "Kyoto",
250+-- | "climate": {
251+-- | | "avg_temp": 16,
252+-- | | "humidity": "high",
253+-- | | "snowfall": "minimal"
254+-- | },
255+-- | "country": "Japan",
256+-- | "wards": 11
257+-- }
258+--
259+-- An example of setting align_keys to true:
260+--
261+-- JSON:encode_pretty(data, nil, { pretty = true, indent = " ", align_keys = true })
262+--
263+-- produces:
264+--
265+-- {
266+-- "city": "Kyoto",
267+-- "climate": {
268+-- "avg_temp": 16,
269+-- "humidity": "high",
270+-- "snowfall": "minimal"
271+-- },
272+-- "country": "Japan",
273+-- "wards": 11
274+-- }
275+--
276+-- which I must admit is kinda ugly, sorry. This was the default for
277+-- encode_pretty() prior to version 20141223.14.
278+--
279+--
280+-- HANDLING UNICODE LINE AND PARAGRAPH SEPARATORS FOR JAVA
281+--
282+-- If the 'stringsAreUtf8' encode option is set to true, consider Lua strings not as a sequence of bytes,
283+-- but as a sequence of UTF-8 characters.
284+--
285+-- Currently, the only practical effect of setting this option is that Unicode LINE and PARAGRAPH
286+-- separators, if found in a string, are encoded with a JSON escape instead of being dumped as is.
287+-- The JSON is valid either way, but encoding this way, apparently, allows the resulting JSON
288+-- to also be valid Java.
289+--
290+-- AMBIGUOUS SITUATIONS DURING THE ENCODING
291+--
292+-- During the encode, if a Lua table being encoded contains both string
293+-- and numeric keys, it fits neither JSON's idea of an object, nor its
294+-- idea of an array. To get around this, when any string key exists (or
295+-- when non-positive numeric keys exist), numeric keys are converted to
296+-- strings.
297+--
298+-- For example,
299+-- JSON:encode({ "one", "two", "three", SOMESTRING = "some string" }))
300+-- produces the JSON object
301+-- {"1":"one","2":"two","3":"three","SOMESTRING":"some string"}
302+--
303+-- To prohibit this conversion and instead make it an error condition, set
304+-- JSON.noKeyConversion = true
305+--
306+--
307+-- ENCODING JSON NULL VALUES
308+--
309+-- Lua tables completely omit keys whose value is nil, so without special handling there's
310+-- no way to get a field in a JSON object with a null value. For example
311+-- JSON:encode({ username = "admin", password = nil })
312+-- produces
313+-- {"username":"admin"}
314+--
315+-- In order to actually produce
316+-- {"username":"admin", "password":null}
317+-- one can include a string value for a "null" field in the options table passed to encode()....
318+-- any Lua table entry with that value becomes null in the JSON output:
319+-- JSON:encode({ username = "admin", password = "xyzzy" }, nil, { null = "xyzzy" })
320+-- produces
321+-- {"username":"admin", "password":null}
322+--
323+-- Just be sure to use a string that is otherwise unlikely to appear in your data.
324+-- The string "\0" (a string with one null byte) may well be appropriate for many applications.
325+--
326+-- The "null" options also applies to Lua tables that become JSON arrays.
327+-- JSON:encode({ "one", "two", nil, nil })
328+-- produces
329+-- ["one","two"]
330+-- while
331+-- NULL = "\0"
332+-- JSON:encode({ "one", "two", NULL, NULL}, nil, { null = NULL })
333+-- produces
334+-- ["one","two",null,null]
335+--
336+--
337+--
338+--
339+-- HANDLING LARGE AND/OR PRECISE NUMBERS
340+--
341+--
342+-- Without special handling, numbers in JSON can lose precision in Lua.
343+-- For example:
344+--
345+-- T = JSON:decode('{ "small":12345, "big":12345678901234567890123456789, "precise":9876.67890123456789012345 }')
346+--
347+-- print("small: ", type(T.small), T.small)
348+-- print("big: ", type(T.big), T.big)
349+-- print("precise: ", type(T.precise), T.precise)
350+--
351+-- produces
352+--
353+-- small: number 12345
354+-- big: number 1.2345678901235e+28
355+-- precise: number 9876.6789012346
356+--
357+-- Precision is lost with both 'big' and 'precise'.
358+--
359+-- This package offers ways to try to handle this better (for some definitions of "better")...
360+--
361+-- The most precise method is by setting the global:
362+--
363+-- JSON.decodeNumbersAsObjects = true
364+--
365+-- When this is set, numeric JSON data is encoded into Lua in a form that preserves the exact
366+-- JSON numeric presentation when re-encoded back out to JSON, or accessed in Lua as a string.
367+--
368+-- (This is done by encoding the numeric data with a Lua table/metatable that returns
369+-- the possibly-imprecise numeric form when accessed numerically, but the original precise
370+-- representation when accessed as a string. You can also explicitly access
371+-- via JSON:forceString() and JSON:forceNumber())
372+--
373+-- Consider the example above, with this option turned on:
374+--
375+-- JSON.decodeNumbersAsObjects = true
376+--
377+-- T = JSON:decode('{ "small":12345, "big":12345678901234567890123456789, "precise":9876.67890123456789012345 }')
378+--
379+-- print("small: ", type(T.small), T.small)
380+-- print("big: ", type(T.big), T.big)
381+-- print("precise: ", type(T.precise), T.precise)
382+--
383+-- This now produces:
384+--
385+-- small: table 12345
386+-- big: table 12345678901234567890123456789
387+-- precise: table 9876.67890123456789012345
388+--
389+-- However, within Lua you can still use the values (e.g. T.precise in the example above) in numeric
390+-- contexts. In such cases you'll get the possibly-imprecise numeric version, but in string contexts
391+-- and when the data finds its way to this package's encode() function, the original full-precision
392+-- representation is used.
393+--
394+-- Even without using the JSON.decodeNumbersAsObjects option, you can encode numbers
395+-- in your Lua table that retain high precision upon encoding to JSON, by using the JSON:asNumber()
396+-- function:
397+--
398+-- T = {
399+-- imprecise = 123456789123456789.123456789123456789,
400+-- precise = JSON:asNumber("123456789123456789.123456789123456789")
401+-- }
402+--
403+-- print(JSON:encode_pretty(T))
404+--
405+-- This produces:
406+--
407+-- {
408+-- "precise": 123456789123456789.123456789123456789,
409+-- "imprecise": 1.2345678912346e+17
410+-- }
411+--
412+--
413+--
414+-- A different way to handle big/precise JSON numbers is to have decode() merely return
415+-- the exact string representation of the number instead of the number itself.
416+-- This approach might be useful when the numbers are merely some kind of opaque
417+-- object identifier and you want to work with them in Lua as strings anyway.
418+--
419+-- This approach is enabled by setting
420+--
421+-- JSON.decodeIntegerStringificationLength = 10
422+--
423+-- The value is the number of digits (of the integer part of the number) at which to stringify numbers.
424+--
425+-- Consider our previous example with this option set to 10:
426+--
427+-- JSON.decodeIntegerStringificationLength = 10
428+--
429+-- T = JSON:decode('{ "small":12345, "big":12345678901234567890123456789, "precise":9876.67890123456789012345 }')
430+--
431+-- print("small: ", type(T.small), T.small)
432+-- print("big: ", type(T.big), T.big)
433+-- print("precise: ", type(T.precise), T.precise)
434+--
435+-- This produces:
436+--
437+-- small: number 12345
438+-- big: string 12345678901234567890123456789
439+-- precise: number 9876.6789012346
440+--
441+-- The long integer of the 'big' field is at least JSON.decodeIntegerStringificationLength digits
442+-- in length, so it's converted not to a Lua integer but to a Lua string. Using a value of 0 or 1 ensures
443+-- that all JSON numeric data becomes strings in Lua.
444+--
445+-- Note that unlike
446+-- JSON.decodeNumbersAsObjects = true
447+-- this stringification is simple and unintelligent: the JSON number simply becomes a Lua string, and that's the end of it.
448+-- If the string is then converted back to JSON, it's still a string. After running the code above, adding
449+-- print(JSON:encode(T))
450+-- produces
451+-- {"big":"12345678901234567890123456789","precise":9876.6789012346,"small":12345}
452+-- which is unlikely to be desired.
453+--
454+-- There's a comparable option for the length of the decimal part of a number:
455+--
456+-- JSON.decodeDecimalStringificationLength
457+--
458+-- This can be used alone or in conjunction with
459+--
460+-- JSON.decodeIntegerStringificationLength
461+--
462+-- to trip stringification on precise numbers with at least JSON.decodeIntegerStringificationLength digits after
463+-- the decimal point.
464+--
465+-- This example:
466+--
467+-- JSON.decodeIntegerStringificationLength = 10
468+-- JSON.decodeDecimalStringificationLength = 5
469+--
470+-- T = JSON:decode('{ "small":12345, "big":12345678901234567890123456789, "precise":9876.67890123456789012345 }')
471+--
472+-- print("small: ", type(T.small), T.small)
473+-- print("big: ", type(T.big), T.big)
474+-- print("precise: ", type(T.precise), T.precise)
475+--
476+-- produces:
477+--
478+-- small: number 12345
479+-- big: string 12345678901234567890123456789
480+-- precise: string 9876.67890123456789012345
481+--
482+--
483+--
484+--
485+--
486+-- SUMMARY OF METHODS YOU CAN OVERRIDE IN YOUR LOCAL LUA JSON OBJECT
487+--
488+-- assert
489+-- onDecodeError
490+-- onDecodeOfNilError
491+-- onDecodeOfHTMLError
492+-- onEncodeError
493+--
494+-- If you want to create a separate Lua JSON object with its own error handlers,
495+-- you can reload JSON.lua or use the :new() method.
496+--
497+---------------------------------------------------------------------------
498+
499+local default_pretty_indent = " "
500+local default_pretty_options = { pretty = true, align_keys = false, indent = default_pretty_indent }
501+
502+local isArray = { __tostring = function() return "JSON array" end } isArray.__index = isArray
503+local isObject = { __tostring = function() return "JSON object" end } isObject.__index = isObject
504+
505+function OBJDEF:newArray(tbl)
506+ return setmetatable(tbl or {}, isArray)
507+end
508+
509+function OBJDEF:newObject(tbl)
510+ return setmetatable(tbl or {}, isObject)
511+end
512+
513+
514+
515+
516+local function getnum(op)
517+ return type(op) == 'number' and op or op.N
518+end
519+
520+local isNumber = {
521+ __tostring = function(T) return T.S end,
522+ __unm = function(op) return getnum(op) end,
523+
524+ __concat = function(op1, op2) return tostring(op1) .. tostring(op2) end,
525+ __add = function(op1, op2) return getnum(op1) + getnum(op2) end,
526+ __sub = function(op1, op2) return getnum(op1) - getnum(op2) end,
527+ __mul = function(op1, op2) return getnum(op1) * getnum(op2) end,
528+ __div = function(op1, op2) return getnum(op1) / getnum(op2) end,
529+ __mod = function(op1, op2) return getnum(op1) % getnum(op2) end,
530+ __pow = function(op1, op2) return getnum(op1) ^ getnum(op2) end,
531+ __lt = function(op1, op2) return getnum(op1) < getnum(op2) end,
532+ __eq = function(op1, op2) return getnum(op1) == getnum(op2) end,
533+ __le = function(op1, op2) return getnum(op1) <= getnum(op2) end,
534+}
535+isNumber.__index = isNumber
536+
537+function OBJDEF:asNumber(item)
538+
539+ if getmetatable(item) == isNumber then
540+ -- it's already a JSON number object.
541+ return item
542+ elseif type(item) == 'table' and type(item.S) == 'string' and type(item.N) == 'number' then
543+ -- it's a number-object table that lost its metatable, so give it one
544+ return setmetatable(item, isNumber)
545+ else
546+ -- the normal situation... given a number or a string representation of a number....
547+ local holder = {
548+ S = tostring(item), -- S is the representation of the number as a string, which remains precise
549+ N = tonumber(item), -- N is the number as a Lua number.
550+ }
551+ return setmetatable(holder, isNumber)
552+ end
553+end
554+
555+--
556+-- Given an item that might be a normal string or number, or might be an 'isNumber' object defined above,
557+-- return the string version. This shouldn't be needed often because the 'isNumber' object should autoconvert
558+-- to a string in most cases, but it's here to allow it to be forced when needed.
559+--
560+function OBJDEF:forceString(item)
561+ if type(item) == 'table' and type(item.S) == 'string' then
562+ return item.S
563+ else
564+ return tostring(item)
565+ end
566+end
567+
568+--
569+-- Given an item that might be a normal string or number, or might be an 'isNumber' object defined above,
570+-- return the numeric version.
571+--
572+function OBJDEF:forceNumber(item)
573+ if type(item) == 'table' and type(item.N) == 'number' then
574+ return item.N
575+ else
576+ return tonumber(item)
577+ end
578+end
579+
580+
581+local function unicode_codepoint_as_utf8(codepoint)
582+ --
583+ -- codepoint is a number
584+ --
585+ if codepoint <= 127 then
586+ return string.char(codepoint)
587+
588+ elseif codepoint <= 2047 then
589+ --
590+ -- 110yyyxx 10xxxxxx <-- useful notation from http://en.wikipedia.org/wiki/Utf8
591+ --
592+ local highpart = math.floor(codepoint / 0x40)
593+ local lowpart = codepoint - (0x40 * highpart)
594+ return string.char(0xC0 + highpart,
595+ 0x80 + lowpart)
596+
597+ elseif codepoint <= 65535 then
598+ --
599+ -- 1110yyyy 10yyyyxx 10xxxxxx
600+ --
601+ local highpart = math.floor(codepoint / 0x1000)
602+ local remainder = codepoint - 0x1000 * highpart
603+ local midpart = math.floor(remainder / 0x40)
604+ local lowpart = remainder - 0x40 * midpart
605+
606+ highpart = 0xE0 + highpart
607+ midpart = 0x80 + midpart
608+ lowpart = 0x80 + lowpart
609+
610+ --
611+ -- Check for an invalid character (thanks Andy R. at Adobe).
612+ -- See table 3.7, page 93, in http://www.unicode.org/versions/Unicode5.2.0/ch03.pdf#G28070
613+ --
614+ if ( highpart == 0xE0 and midpart < 0xA0 ) or
615+ ( highpart == 0xED and midpart > 0x9F ) or
616+ ( highpart == 0xF0 and midpart < 0x90 ) or
617+ ( highpart == 0xF4 and midpart > 0x8F )
618+ then
619+ return "?"
620+ else
621+ return string.char(highpart,
622+ midpart,
623+ lowpart)
624+ end
625+
626+ else
627+ --
628+ -- 11110zzz 10zzyyyy 10yyyyxx 10xxxxxx
629+ --
630+ local highpart = math.floor(codepoint / 0x40000)
631+ local remainder = codepoint - 0x40000 * highpart
632+ local midA = math.floor(remainder / 0x1000)
633+ remainder = remainder - 0x1000 * midA
634+ local midB = math.floor(remainder / 0x40)
635+ local lowpart = remainder - 0x40 * midB
636+
637+ return string.char(0xF0 + highpart,
638+ 0x80 + midA,
639+ 0x80 + midB,
640+ 0x80 + lowpart)
641+ end
642+end
643+
644+function OBJDEF:onDecodeError(message, text, location, etc)
645+ if text then
646+ if location then
647+ message = string.format("%s at char %d of: %s", message, location, text)
648+ else
649+ message = string.format("%s: %s", message, text)
650+ end
651+ end
652+
653+ if etc ~= nil then
654+ message = message .. " (" .. OBJDEF:encode(etc) .. ")"
655+ end
656+
657+ if self.assert then
658+ self.assert(false, message)
659+ else
660+ assert(false, message)
661+ end
662+end
663+
664+OBJDEF.onDecodeOfNilError = OBJDEF.onDecodeError
665+OBJDEF.onDecodeOfHTMLError = OBJDEF.onDecodeError
666+
667+function OBJDEF:onEncodeError(message, etc)
668+ if etc ~= nil then
669+ message = message .. " (" .. OBJDEF:encode(etc) .. ")"
670+ end
671+
672+ if self.assert then
673+ self.assert(false, message)
674+ else
675+ assert(false, message)
676+ end
677+end
678+
679+local function grok_number(self, text, start, options)
680+ --
681+ -- Grab the integer part
682+ --
683+ local integer_part = text:match('^-?[1-9]%d*', start)
684+ or text:match("^-?0", start)
685+
686+ if not integer_part then
687+ self:onDecodeError("expected number", text, start, options.etc)
688+ end
689+
690+ local i = start + integer_part:len()
691+
692+ --
693+ -- Grab an optional decimal part
694+ --
695+ local decimal_part = text:match('^%.%d+', i) or ""
696+
697+ i = i + decimal_part:len()
698+
699+ --
700+ -- Grab an optional exponential part
701+ --
702+ local exponent_part = text:match('^[eE][-+]?%d+', i) or ""
703+
704+ i = i + exponent_part:len()
705+
706+ local full_number_text = integer_part .. decimal_part .. exponent_part
707+
708+ if options.decodeNumbersAsObjects then
709+ return OBJDEF:asNumber(full_number_text), i
710+ end
711+
712+ --
713+ -- If we're told to stringify under certain conditions, so do.
714+ -- We punt a bit when there's an exponent by just stringifying no matter what.
715+ -- I suppose we should really look to see whether the exponent is actually big enough one
716+ -- way or the other to trip stringification, but I'll be lazy about it until someone asks.
717+ --
718+ if (options.decodeIntegerStringificationLength
719+ and
720+ (integer_part:len() >= options.decodeIntegerStringificationLength or exponent_part:len() > 0))
721+
722+ or
723+
724+ (options.decodeDecimalStringificationLength
725+ and
726+ (decimal_part:len() >= options.decodeDecimalStringificationLength or exponent_part:len() > 0))
727+ then
728+ return full_number_text, i -- this returns the exact string representation seen in the original JSON
729+ end
730+
731+
732+
733+ local as_number = tonumber(full_number_text)
734+
735+ if not as_number then
736+ self:onDecodeError("bad number", text, start, options.etc)
737+ end
738+
739+ return as_number, i
740+end
741+
742+
743+local function grok_string(self, text, start, options)
744+
745+ if text:sub(start,start) ~= '"' then
746+ self:onDecodeError("expected string's opening quote", text, start, options.etc)
747+ end
748+
749+ local i = start + 1 -- +1 to bypass the initial quote
750+ local text_len = text:len()
751+ local VALUE = ""
752+ while i <= text_len do
753+ local c = text:sub(i,i)
754+ if c == '"' then
755+ return VALUE, i + 1
756+ end
757+ if c ~= '\\' then
758+ VALUE = VALUE .. c
759+ i = i + 1
760+ elseif text:match('^\\b', i) then
761+ VALUE = VALUE .. "\b"
762+ i = i + 2
763+ elseif text:match('^\\f', i) then
764+ VALUE = VALUE .. "\f"
765+ i = i + 2
766+ elseif text:match('^\\n', i) then
767+ VALUE = VALUE .. "\n"
768+ i = i + 2
769+ elseif text:match('^\\r', i) then
770+ VALUE = VALUE .. "\r"
771+ i = i + 2
772+ elseif text:match('^\\t', i) then
773+ VALUE = VALUE .. "\t"
774+ i = i + 2
775+ else
776+ local hex = text:match('^\\u([0123456789aAbBcCdDeEfF][0123456789aAbBcCdDeEfF][0123456789aAbBcCdDeEfF][0123456789aAbBcCdDeEfF])', i)
777+ if hex then
778+ i = i + 6 -- bypass what we just read
779+
780+ -- We have a Unicode codepoint. It could be standalone, or if in the proper range and
781+ -- followed by another in a specific range, it'll be a two-code surrogate pair.
782+ local codepoint = tonumber(hex, 16)
783+ if codepoint >= 0xD800 and codepoint <= 0xDBFF then
784+ -- it's a hi surrogate... see whether we have a following low
785+ local lo_surrogate = text:match('^\\u([dD][cdefCDEF][0123456789aAbBcCdDeEfF][0123456789aAbBcCdDeEfF])', i)
786+ if lo_surrogate then
787+ i = i + 6 -- bypass the low surrogate we just read
788+ codepoint = 0x2400 + (codepoint - 0xD800) * 0x400 + tonumber(lo_surrogate, 16)
789+ else
790+ -- not a proper low, so we'll just leave the first codepoint as is and spit it out.
791+ end
792+ end
793+ VALUE = VALUE .. unicode_codepoint_as_utf8(codepoint)
794+
795+ else
796+
797+ -- just pass through what's escaped
798+ VALUE = VALUE .. text:match('^\\(.)', i)
799+ i = i + 2
800+ end
801+ end
802+ end
803+
804+ self:onDecodeError("unclosed string", text, start, options.etc)
805+end
806+
807+local function skip_whitespace(text, start)
808+
809+ local _, match_end = text:find("^[ \n\r\t]+", start) -- [http://www.ietf.org/rfc/rfc4627.txt] Section 2
810+ if match_end then
811+ return match_end + 1
812+ else
813+ return start
814+ end
815+end
816+
817+local grok_one -- assigned later
818+
819+local function grok_object(self, text, start, options)
820+
821+ if text:sub(start,start) ~= '{' then
822+ self:onDecodeError("expected '{'", text, start, options.etc)
823+ end
824+
825+ local i = skip_whitespace(text, start + 1) -- +1 to skip the '{'
826+
827+ local VALUE = self.strictTypes and self:newObject { } or { }
828+
829+ if text:sub(i,i) == '}' then
830+ return VALUE, i + 1
831+ end
832+ local text_len = text:len()
833+ while i <= text_len do
834+ local key, new_i = grok_string(self, text, i, options)
835+
836+ i = skip_whitespace(text, new_i)
837+
838+ if text:sub(i, i) ~= ':' then
839+ self:onDecodeError("expected colon", text, i, options.etc)
840+ end
841+
842+ i = skip_whitespace(text, i + 1)
843+
844+ local new_val, new_i = grok_one(self, text, i, options)
845+
846+ VALUE[key] = new_val
847+
848+ --
849+ -- Expect now either '}' to end things, or a ',' to allow us to continue.
850+ --
851+ i = skip_whitespace(text, new_i)
852+
853+ local c = text:sub(i,i)
854+
855+ if c == '}' then
856+ return VALUE, i + 1
857+ end
858+
859+ if text:sub(i, i) ~= ',' then
860+ self:onDecodeError("expected comma or '}'", text, i, options.etc)
861+ end
862+
863+ i = skip_whitespace(text, i + 1)
864+ end
865+
866+ self:onDecodeError("unclosed '{'", text, start, options.etc)
867+end
868+
869+local function grok_array(self, text, start, options)
870+ if text:sub(start,start) ~= '[' then
871+ self:onDecodeError("expected '['", text, start, options.etc)
872+ end
873+
874+ local i = skip_whitespace(text, start + 1) -- +1 to skip the '['
875+ local VALUE = self.strictTypes and self:newArray { } or { }
876+ if text:sub(i,i) == ']' then
877+ return VALUE, i + 1
878+ end
879+
880+ local VALUE_INDEX = 1
881+
882+ local text_len = text:len()
883+ while i <= text_len do
884+ local val, new_i = grok_one(self, text, i, options)
885+
886+ -- can't table.insert(VALUE, val) here because it's a no-op if val is nil
887+ VALUE[VALUE_INDEX] = val
888+ VALUE_INDEX = VALUE_INDEX + 1
889+
890+ i = skip_whitespace(text, new_i)
891+
892+ --
893+ -- Expect now either ']' to end things, or a ',' to allow us to continue.
894+ --
895+ local c = text:sub(i,i)
896+ if c == ']' then
897+ return VALUE, i + 1
898+ end
899+ if text:sub(i, i) ~= ',' then
900+ self:onDecodeError("expected comma or '['", text, i, options.etc)
901+ end
902+ i = skip_whitespace(text, i + 1)
903+ end
904+ self:onDecodeError("unclosed '['", text, start, options.etc)
905+end
906+
907+
908+grok_one = function(self, text, start, options)
909+ -- Skip any whitespace
910+ start = skip_whitespace(text, start)
911+
912+ if start > text:len() then
913+ self:onDecodeError("unexpected end of string", text, nil, options.etc)
914+ end
915+
916+ if text:find('^"', start) then
917+ return grok_string(self, text, start, options.etc)
918+
919+ elseif text:find('^[-0123456789 ]', start) then
920+ return grok_number(self, text, start, options)
921+
922+ elseif text:find('^%{', start) then
923+ return grok_object(self, text, start, options)
924+
925+ elseif text:find('^%[', start) then
926+ return grok_array(self, text, start, options)
927+
928+ elseif text:find('^true', start) then
929+ return true, start + 4
930+
931+ elseif text:find('^false', start) then
932+ return false, start + 5
933+
934+ elseif text:find('^null', start) then
935+ return nil, start + 4
936+
937+ else
938+ self:onDecodeError("can't parse JSON", text, start, options.etc)
939+ end
940+end
941+
942+function OBJDEF:decode(text, etc, options)
943+ --
944+ -- If the user didn't pass in a table of decode options, make an empty one.
945+ --
946+ if type(options) ~= 'table' then
947+ options = {}
948+ end
949+
950+ --
951+ -- If they passed in an 'etc' argument, stuff it into the options.
952+ -- (If not, any 'etc' field in the options they passed in remains to be used)
953+ --
954+ if etc ~= nil then
955+ options.etc = etc
956+ end
957+
958+
959+ if type(self) ~= 'table' or self.__index ~= OBJDEF then
960+ OBJDEF:onDecodeError("JSON:decode must be called in method format", nil, nil, options.etc)
961+ end
962+
963+ if text == nil then
964+ self:onDecodeOfNilError(string.format("nil passed to JSON:decode()"), nil, nil, options.etc)
965+ elseif type(text) ~= 'string' then
966+ self:onDecodeError(string.format("expected string argument to JSON:decode(), got %s", type(text)), nil, nil, options.etc)
967+ end
968+
969+ if text:match('^%s*$') then
970+ return nil
971+ end
972+
973+ if text:match('^%s*<') then
974+ -- Can't be JSON... we'll assume it's HTML
975+ self:onDecodeOfHTMLError(string.format("html passed to JSON:decode()"), text, nil, options.etc)
976+ end
977+
978+ --
979+ -- Ensure that it's not UTF-32 or UTF-16.
980+ -- Those are perfectly valid encodings for JSON (as per RFC 4627 section 3),
981+ -- but this package can't handle them.
982+ --
983+ if text:sub(1,1):byte() == 0 or (text:len() >= 2 and text:sub(2,2):byte() == 0) then
984+ self:onDecodeError("JSON package groks only UTF-8, sorry", text, nil, options.etc)
985+ end
986+
987+ --
988+ -- apply global options
989+ --
990+ if options.decodeNumbersAsObjects == nil then
991+ options.decodeNumbersAsObjects = self.decodeNumbersAsObjects
992+ end
993+ if options.decodeIntegerStringificationLength == nil then
994+ options.decodeIntegerStringificationLength = self.decodeIntegerStringificationLength
995+ end
996+ if options.decodeDecimalStringificationLength == nil then
997+ options.decodeDecimalStringificationLength = self.decodeDecimalStringificationLength
998+ end
999+
1000+ local success, value = pcall(grok_one, self, text, 1, options)
1001+
1002+ if success then
1003+ return value
1004+ else
1005+ -- if JSON:onDecodeError() didn't abort out of the pcall, we'll have received the error message here as "value", so pass it along as an assert.
1006+ if self.assert then
1007+ self.assert(false, value)
1008+ else
1009+ assert(false, value)
1010+ end
1011+ -- and if we're still here, return a nil and throw the error message on as a second arg
1012+ return nil, value
1013+ end
1014+end
1015+
1016+local function backslash_replacement_function(c)
1017+ if c == "\n" then
1018+ return "\\n"
1019+ elseif c == "\r" then
1020+ return "\\r"
1021+ elseif c == "\t" then
1022+ return "\\t"
1023+ elseif c == "\b" then
1024+ return "\\b"
1025+ elseif c == "\f" then
1026+ return "\\f"
1027+ elseif c == '"' then
1028+ return '\\"'
1029+ elseif c == '\\' then
1030+ return '\\\\'
1031+ else
1032+ return string.format("\\u%04x", c:byte())
1033+ end
1034+end
1035+
1036+local chars_to_be_escaped_in_JSON_string
1037+ = '['
1038+ .. '"' -- class sub-pattern to match a double quote
1039+ .. '%\\' -- class sub-pattern to match a backslash
1040+ .. '%z' -- class sub-pattern to match a null
1041+ .. '\001' .. '-' .. '\031' -- class sub-pattern to match control characters
1042+ .. ']'
1043+
1044+
1045+local LINE_SEPARATOR_as_utf8 = unicode_codepoint_as_utf8(0x2028)
1046+local PARAGRAPH_SEPARATOR_as_utf8 = unicode_codepoint_as_utf8(0x2029)
1047+local function json_string_literal(value, options)
1048+ local newval = value:gsub(chars_to_be_escaped_in_JSON_string, backslash_replacement_function)
1049+ if options.stringsAreUtf8 then
1050+ --
1051+ -- This feels really ugly to just look into a string for the sequence of bytes that we know to be a particular utf8 character,
1052+ -- but utf8 was designed purposefully to make this kind of thing possible. Still, feels dirty.
1053+ -- I'd rather decode the byte stream into a character stream, but it's not technically needed so
1054+ -- not technically worth it.
1055+ --
1056+ newval = newval:gsub(LINE_SEPARATOR_as_utf8, '\\u2028'):gsub(PARAGRAPH_SEPARATOR_as_utf8,'\\u2029')
1057+ end
1058+ return '"' .. newval .. '"'
1059+end
1060+
1061+local function object_or_array(self, T, etc)
1062+ --
1063+ -- We need to inspect all the keys... if there are any strings, we'll convert to a JSON
1064+ -- object. If there are only numbers, it's a JSON array.
1065+ --
1066+ -- If we'll be converting to a JSON object, we'll want to sort the keys so that the
1067+ -- end result is deterministic.
1068+ --
1069+ local string_keys = { }
1070+ local number_keys = { }
1071+ local number_keys_must_be_strings = false
1072+ local maximum_number_key
1073+
1074+ for key in pairs(T) do
1075+ if type(key) == 'string' then
1076+ table.insert(string_keys, key)
1077+ elseif type(key) == 'number' then
1078+ table.insert(number_keys, key)
1079+ if key <= 0 or key >= math.huge then
1080+ number_keys_must_be_strings = true
1081+ elseif not maximum_number_key or key > maximum_number_key then
1082+ maximum_number_key = key
1083+ end
1084+ else
1085+ self:onEncodeError("can't encode table with a key of type " .. type(key), etc)
1086+ end
1087+ end
1088+
1089+ if #string_keys == 0 and not number_keys_must_be_strings then
1090+ --
1091+ -- An empty table, or a numeric-only array
1092+ --
1093+ if #number_keys > 0 then
1094+ return nil, maximum_number_key -- an array
1095+ elseif tostring(T) == "JSON array" then
1096+ return nil
1097+ elseif tostring(T) == "JSON object" then
1098+ return { }
1099+ else
1100+ -- have to guess, so we'll pick array, since empty arrays are likely more common than empty objects
1101+ return nil
1102+ end
1103+ end
1104+
1105+ table.sort(string_keys)
1106+
1107+ local map
1108+ if #number_keys > 0 then
1109+ --
1110+ -- If we're here then we have either mixed string/number keys, or numbers inappropriate for a JSON array
1111+ -- It's not ideal, but we'll turn the numbers into strings so that we can at least create a JSON object.
1112+ --
1113+
1114+ if self.noKeyConversion then
1115+ self:onEncodeError("a table with both numeric and string keys could be an object or array; aborting", etc)
1116+ end
1117+
1118+ --
1119+ -- Have to make a shallow copy of the source table so we can remap the numeric keys to be strings
1120+ --
1121+ map = { }
1122+ for key, val in pairs(T) do
1123+ map[key] = val
1124+ end
1125+
1126+ table.sort(number_keys)
1127+
1128+ --
1129+ -- Throw numeric keys in there as strings
1130+ --
1131+ for _, number_key in ipairs(number_keys) do
1132+ local string_key = tostring(number_key)
1133+ if map[string_key] == nil then
1134+ table.insert(string_keys , string_key)
1135+ map[string_key] = T[number_key]
1136+ else
1137+ self:onEncodeError("conflict converting table with mixed-type keys into a JSON object: key " .. number_key .. " exists both as a string and a number.", etc)
1138+ end
1139+ end
1140+ end
1141+
1142+ return string_keys, nil, map
1143+end
1144+
1145+--
1146+-- Encode
1147+--
1148+-- 'options' is nil, or a table with possible keys:
1149+--
1150+-- pretty -- If true, return a pretty-printed version.
1151+--
1152+-- indent -- A string (usually of spaces) used to indent each nested level.
1153+--
1154+-- align_keys -- If true, align all the keys when formatting a table.
1155+--
1156+-- null -- If this exists with a string value, table elements with this value are output as JSON null.
1157+--
1158+-- stringsAreUtf8 -- If true, consider Lua strings not as a sequence of bytes, but as a sequence of UTF-8 characters.
1159+-- (Currently, the only practical effect of setting this option is that Unicode LINE and PARAGRAPH
1160+-- separators, if found in a string, are encoded with a JSON escape instead of as raw UTF-8.
1161+-- The JSON is valid either way, but encoding this way, apparently, allows the resulting JSON
1162+-- to also be valid Java.)
1163+--
1164+--
1165+local encode_value -- must predeclare because it calls itself
1166+function encode_value(self, value, parents, etc, options, indent, for_key)
1167+
1168+ --
1169+ -- keys in a JSON object can never be null, so we don't even consider options.null when converting a key value
1170+ --
1171+ if value == nil or (not for_key and options and options.null and value == options.null) then
1172+ return 'null'
1173+
1174+ elseif type(value) == 'string' then
1175+ return json_string_literal(value, options)
1176+
1177+ elseif type(value) == 'number' then
1178+ if value ~= value then
1179+ --
1180+ -- NaN (Not a Number).
1181+ -- JSON has no NaN, so we have to fudge the best we can. This should really be a package option.
1182+ --
1183+ return "null"
1184+ elseif value >= math.huge then
1185+ --
1186+ -- Positive infinity. JSON has no INF, so we have to fudge the best we can. This should
1187+ -- really be a package option. Note: at least with some implementations, positive infinity
1188+ -- is both ">= math.huge" and "<= -math.huge", which makes no sense but that's how it is.
1189+ -- Negative infinity is properly "<= -math.huge". So, we must be sure to check the ">="
1190+ -- case first.
1191+ --
1192+ return "1e+9999"
1193+ elseif value <= -math.huge then
1194+ --
1195+ -- Negative infinity.
1196+ -- JSON has no INF, so we have to fudge the best we can. This should really be a package option.
1197+ --
1198+ return "-1e+9999"
1199+ else
1200+ return tostring(value)
1201+ end
1202+
1203+ elseif type(value) == 'boolean' then
1204+ return tostring(value)
1205+
1206+ elseif type(value) ~= 'table' then
1207+ self:onEncodeError("can't convert " .. type(value) .. " to JSON", etc)
1208+
1209+ elseif getmetatable(value) == isNumber then
1210+ return tostring(value)
1211+ else
1212+ --
1213+ -- A table to be converted to either a JSON object or array.
1214+ --
1215+ local T = value
1216+
1217+ if type(options) ~= 'table' then
1218+ options = {}
1219+ end
1220+ if type(indent) ~= 'string' then
1221+ indent = ""
1222+ end
1223+
1224+ if parents[T] then
1225+ self:onEncodeError("table " .. tostring(T) .. " is a child of itself", etc)
1226+ else
1227+ parents[T] = true
1228+ end
1229+
1230+ local result_value
1231+
1232+ local object_keys, maximum_number_key, map = object_or_array(self, T, etc)
1233+ if maximum_number_key then
1234+ --
1235+ -- An array...
1236+ --
1237+ local ITEMS = { }
1238+ for i = 1, maximum_number_key do
1239+ table.insert(ITEMS, encode_value(self, T[i], parents, etc, options, indent))
1240+ end
1241+
1242+ if options.pretty then
1243+ result_value = "[ " .. table.concat(ITEMS, ", ") .. " ]"
1244+ else
1245+ result_value = "[" .. table.concat(ITEMS, ",") .. "]"
1246+ end
1247+
1248+ elseif object_keys then
1249+ --
1250+ -- An object
1251+ --
1252+ local TT = map or T
1253+
1254+ if options.pretty then
1255+
1256+ local KEYS = { }
1257+ local max_key_length = 0
1258+ for _, key in ipairs(object_keys) do
1259+ local encoded = encode_value(self, tostring(key), parents, etc, options, indent, true)
1260+ if options.align_keys then
1261+ max_key_length = math.max(max_key_length, #encoded)
1262+ end
1263+ table.insert(KEYS, encoded)
1264+ end
1265+ local key_indent = indent .. tostring(options.indent or "")
1266+ local subtable_indent = key_indent .. string.rep(" ", max_key_length) .. (options.align_keys and " " or "")
1267+ local FORMAT = "%s%" .. string.format("%d", max_key_length) .. "s: %s"
1268+
1269+ local COMBINED_PARTS = { }
1270+ for i, key in ipairs(object_keys) do
1271+ local encoded_val = encode_value(self, TT[key], parents, etc, options, subtable_indent)
1272+ table.insert(COMBINED_PARTS, string.format(FORMAT, key_indent, KEYS[i], encoded_val))
1273+ end
1274+ result_value = "{\n" .. table.concat(COMBINED_PARTS, ",\n") .. "\n" .. indent .. "}"
1275+
1276+ else
1277+
1278+ local PARTS = { }
1279+ for _, key in ipairs(object_keys) do
1280+ local encoded_val = encode_value(self, TT[key], parents, etc, options, indent)
1281+ local encoded_key = encode_value(self, tostring(key), parents, etc, options, indent, true)
1282+ table.insert(PARTS, string.format("%s:%s", encoded_key, encoded_val))
1283+ end
1284+ result_value = "{" .. table.concat(PARTS, ",") .. "}"
1285+
1286+ end
1287+ else
1288+ --
1289+ -- An empty array/object... we'll treat it as an array, though it should really be an option
1290+ --
1291+ result_value = "[]"
1292+ end
1293+
1294+ parents[T] = false
1295+ return result_value
1296+ end
1297+end
1298+
1299+
1300+function OBJDEF:encode(value, etc, options)
1301+ if type(self) ~= 'table' or self.__index ~= OBJDEF then
1302+ OBJDEF:onEncodeError("JSON:encode must be called in method format", etc)
1303+ end
1304+
1305+ --
1306+ -- If the user didn't pass in a table of decode options, make an empty one.
1307+ --
1308+ if type(options) ~= 'table' then
1309+ options = {}
1310+ end
1311+
1312+ return encode_value(self, value, {}, etc, options)
1313+end
1314+
1315+function OBJDEF:encode_pretty(value, etc, options)
1316+ if type(self) ~= 'table' or self.__index ~= OBJDEF then
1317+ OBJDEF:onEncodeError("JSON:encode_pretty must be called in method format", etc)
1318+ end
1319+
1320+ --
1321+ -- If the user didn't pass in a table of decode options, use the default pretty ones
1322+ --
1323+ if type(options) ~= 'table' then
1324+ options = default_pretty_options
1325+ end
1326+
1327+ return encode_value(self, value, {}, etc, options)
1328+end
1329+
1330+function OBJDEF.__tostring()
1331+ return "JSON encode/decode package"
1332+end
1333+
1334+OBJDEF.__index = OBJDEF
1335+
1336+function OBJDEF:new(args)
1337+ local new = { }
1338+
1339+ if args then
1340+ for key, val in pairs(args) do
1341+ new[key] = val
1342+ end
1343+ end
1344+
1345+ return setmetatable(new, OBJDEF)
1346+end
1347+
1348+return OBJDEF:new()
1349+
1350+--
1351+-- Version history:
1352+--
1353+-- 20160916.19 Fixed the isNumber.__index assignment (thanks to Jack Taylor)
1354+--
1355+-- 20160730.18 Added JSON:forceString() and JSON:forceNumber()
1356+--
1357+-- 20160728.17 Added concatenation to the metatable for JSON:asNumber()
1358+--
1359+-- 20160709.16 Could crash if not passed an options table (thanks jarno heikkinen <jarnoh@capturemonkey.com>).
1360+--
1361+-- Made JSON:asNumber() a bit more resilient to being passed the results of itself.
1362+--
1363+-- 20160526.15 Added the ability to easily encode null values in JSON, via the new "null" encoding option.
1364+-- (Thanks to Adam B for bringing up the issue.)
1365+--
1366+-- Added some support for very large numbers and precise floats via
1367+-- JSON.decodeNumbersAsObjects
1368+-- JSON.decodeIntegerStringificationLength
1369+-- JSON.decodeDecimalStringificationLength
1370+--
1371+-- Added the "stringsAreUtf8" encoding option. (Hat tip to http://lua-users.org/wiki/JsonModules )
1372+--
1373+-- 20141223.14 The encode_pretty() routine produced fine results for small datasets, but isn't really
1374+-- appropriate for anything large, so with help from Alex Aulbach I've made the encode routines
1375+-- more flexible, and changed the default encode_pretty() to be more generally useful.
1376+--
1377+-- Added a third 'options' argument to the encode() and encode_pretty() routines, to control
1378+-- how the encoding takes place.
1379+--
1380+-- Updated docs to add assert() call to the loadfile() line, just as good practice so that
1381+-- if there is a problem loading JSON.lua, the appropriate error message will percolate up.
1382+--
1383+-- 20140920.13 Put back (in a way that doesn't cause warnings about unused variables) the author string,
1384+-- so that the source of the package, and its version number, are visible in compiled copies.
1385+--
1386+-- 20140911.12 Minor lua cleanup.
1387+-- Fixed internal reference to 'JSON.noKeyConversion' to reference 'self' instead of 'JSON'.
1388+-- (Thanks to SmugMug's David Parry for these.)
1389+--
1390+-- 20140418.11 JSON nulls embedded within an array were being ignored, such that
1391+-- ["1",null,null,null,null,null,"seven"],
1392+-- would return
1393+-- {1,"seven"}
1394+-- It's now fixed to properly return
1395+-- {1, nil, nil, nil, nil, nil, "seven"}
1396+-- Thanks to "haddock" for catching the error.
1397+--
1398+-- 20140116.10 The user's JSON.assert() wasn't always being used. Thanks to "blue" for the heads up.
1399+--
1400+-- 20131118.9 Update for Lua 5.3... it seems that tostring(2/1) produces "2.0" instead of "2",
1401+-- and this caused some problems.
1402+--
1403+-- 20131031.8 Unified the code for encode() and encode_pretty(); they had been stupidly separate,
1404+-- and had of course diverged (encode_pretty didn't get the fixes that encode got, so
1405+-- sometimes produced incorrect results; thanks to Mattie for the heads up).
1406+--
1407+-- Handle encoding tables with non-positive numeric keys (unlikely, but possible).
1408+--
1409+-- If a table has both numeric and string keys, or its numeric keys are inappropriate
1410+-- (such as being non-positive or infinite), the numeric keys are turned into
1411+-- string keys appropriate for a JSON object. So, as before,
1412+-- JSON:encode({ "one", "two", "three" })
1413+-- produces the array
1414+-- ["one","two","three"]
1415+-- but now something with mixed key types like
1416+-- JSON:encode({ "one", "two", "three", SOMESTRING = "some string" }))
1417+-- instead of throwing an error produces an object:
1418+-- {"1":"one","2":"two","3":"three","SOMESTRING":"some string"}
1419+--
1420+-- To maintain the prior throw-an-error semantics, set
1421+-- JSON.noKeyConversion = true
1422+--
1423+-- 20131004.7 Release under a Creative Commons CC-BY license, which I should have done from day one, sorry.
1424+--
1425+-- 20130120.6 Comment update: added a link to the specific page on my blog where this code can
1426+-- be found, so that folks who come across the code outside of my blog can find updates
1427+-- more easily.
1428+--
1429+-- 20111207.5 Added support for the 'etc' arguments, for better error reporting.
1430+--
1431+-- 20110731.4 More feedback from David Kolf on how to make the tests for Nan/Infinity system independent.
1432+--
1433+-- 20110730.3 Incorporated feedback from David Kolf at http://lua-users.org/wiki/JsonModules:
1434+--
1435+-- * When encoding lua for JSON, Sparse numeric arrays are now handled by
1436+-- spitting out full arrays, such that
1437+-- JSON:encode({"one", "two", [10] = "ten"})
1438+-- returns
1439+-- ["one","two",null,null,null,null,null,null,null,"ten"]
1440+--
1441+-- In 20100810.2 and earlier, only up to the first non-null value would have been retained.
1442+--
1443+-- * When encoding lua for JSON, numeric value NaN gets spit out as null, and infinity as "1+e9999".
1444+-- Version 20100810.2 and earlier created invalid JSON in both cases.
1445+--
1446+-- * Unicode surrogate pairs are now detected when decoding JSON.
1447+--
1448+-- 20100810.2 added some checking to ensure that an invalid Unicode character couldn't leak in to the UTF-8 encoding
1449+--
1450+-- 20100731.1 initial public release
1451+--
parsers/test_Lua_JSON/test_JSON.luanew file+22
@@ -0,0 +1,22 @@
1+-- http://regex.info/blog/lua/json
2+JSON = (loadfile "test_Lua_JSON/JSON.lua")() -- one-time load of the routines
3+
4+function readAll(file)
5+ local f = io.open(file, "rb")
6+ local content = f:read("*all")
7+ f:close()
8+ return content
9+end
10+
11+local data = readAll(arg[1])
12+
13+local lua_value = JSON:decode(data)
14+
15+if lua_value == nil then
16+ print ("Error:", err)
17+ os.exit(1)
18+end
19+
20+print ("--", lua_value )
21+
22+os.exit(0)
parsers/test_ObjCNSJSONSerializer/bin/test_ObjCNSJSONSerializernew file

Binary file not shown.

parsers/test_ObjCNSJSONSerializer/test_ObjCNSJSONSerializer.xcodeproj/project.pbxprojnew file+246
@@ -0,0 +1,246 @@
1+// !$*UTF8*$!
2+{
3+ archiveVersion = 1;
4+ classes = {
5+ };
6+ objectVersion = 46;
7+ objects = {
8+
9+/* Begin PBXBuildFile section */
10+ 03A27D3B1D796BB600B2D016 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 03A27D3A1D796BB600B2D016 /* main.m */; };
11+/* End PBXBuildFile section */
12+
13+/* Begin PBXCopyFilesBuildPhase section */
14+ 03A27D351D796BB600B2D016 /* CopyFiles */ = {
15+ isa = PBXCopyFilesBuildPhase;
16+ buildActionMask = 2147483647;
17+ dstPath = /usr/share/man/man1/;
18+ dstSubfolderSpec = 0;
19+ files = (
20+ );
21+ runOnlyForDeploymentPostprocessing = 1;
22+ };
23+/* End PBXCopyFilesBuildPhase section */
24+
25+/* Begin PBXFileReference section */
26+ 03A27D371D796BB600B2D016 /* test_ObjCNSJSONSerializer */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = test_ObjCNSJSONSerializer; sourceTree = BUILT_PRODUCTS_DIR; };
27+ 03A27D3A1D796BB600B2D016 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
28+/* End PBXFileReference section */
29+
30+/* Begin PBXFrameworksBuildPhase section */
31+ 03A27D341D796BB600B2D016 /* Frameworks */ = {
32+ isa = PBXFrameworksBuildPhase;
33+ buildActionMask = 2147483647;
34+ files = (
35+ );
36+ runOnlyForDeploymentPostprocessing = 0;
37+ };
38+/* End PBXFrameworksBuildPhase section */
39+
40+/* Begin PBXGroup section */
41+ 03A27D2E1D796BB600B2D016 = {
42+ isa = PBXGroup;
43+ children = (
44+ 03A27D391D796BB600B2D016 /* test_ObjCNSJSONSerializer */,
45+ 03A27D381D796BB600B2D016 /* Products */,
46+ );
47+ sourceTree = "<group>";
48+ };
49+ 03A27D381D796BB600B2D016 /* Products */ = {
50+ isa = PBXGroup;
51+ children = (
52+ 03A27D371D796BB600B2D016 /* test_ObjCNSJSONSerializer */,
53+ );
54+ name = Products;
55+ sourceTree = "<group>";
56+ };
57+ 03A27D391D796BB600B2D016 /* test_ObjCNSJSONSerializer */ = {
58+ isa = PBXGroup;
59+ children = (
60+ 03A27D3A1D796BB600B2D016 /* main.m */,
61+ );
62+ path = test_ObjCNSJSONSerializer;
63+ sourceTree = "<group>";
64+ };
65+/* End PBXGroup section */
66+
67+/* Begin PBXNativeTarget section */
68+ 03A27D361D796BB600B2D016 /* test_ObjCNSJSONSerializer */ = {
69+ isa = PBXNativeTarget;
70+ buildConfigurationList = 03A27D3E1D796BB600B2D016 /* Build configuration list for PBXNativeTarget "test_ObjCNSJSONSerializer" */;
71+ buildPhases = (
72+ 03A27D331D796BB600B2D016 /* Sources */,
73+ 03A27D341D796BB600B2D016 /* Frameworks */,
74+ 03A27D351D796BB600B2D016 /* CopyFiles */,
75+ );
76+ buildRules = (
77+ );
78+ dependencies = (
79+ );
80+ name = test_ObjCNSJSONSerializer;
81+ productName = test_ObjCNSJSONSerializer;
82+ productReference = 03A27D371D796BB600B2D016 /* test_ObjCNSJSONSerializer */;
83+ productType = "com.apple.product-type.tool";
84+ };
85+/* End PBXNativeTarget section */
86+
87+/* Begin PBXProject section */
88+ 03A27D2F1D796BB600B2D016 /* Project object */ = {
89+ isa = PBXProject;
90+ attributes = {
91+ LastUpgradeCheck = 0730;
92+ ORGANIZATIONNAME = Swissquote;
93+ TargetAttributes = {
94+ 03A27D361D796BB600B2D016 = {
95+ CreatedOnToolsVersion = 7.3.1;
96+ };
97+ };
98+ };
99+ buildConfigurationList = 03A27D321D796BB600B2D016 /* Build configuration list for PBXProject "test_ObjCNSJSONSerializer" */;
100+ compatibilityVersion = "Xcode 3.2";
101+ developmentRegion = English;
102+ hasScannedForEncodings = 0;
103+ knownRegions = (
104+ en,
105+ );
106+ mainGroup = 03A27D2E1D796BB600B2D016;
107+ productRefGroup = 03A27D381D796BB600B2D016 /* Products */;
108+ projectDirPath = "";
109+ projectRoot = "";
110+ targets = (
111+ 03A27D361D796BB600B2D016 /* test_ObjCNSJSONSerializer */,
112+ );
113+ };
114+/* End PBXProject section */
115+
116+/* Begin PBXSourcesBuildPhase section */
117+ 03A27D331D796BB600B2D016 /* Sources */ = {
118+ isa = PBXSourcesBuildPhase;
119+ buildActionMask = 2147483647;
120+ files = (
121+ 03A27D3B1D796BB600B2D016 /* main.m in Sources */,
122+ );
123+ runOnlyForDeploymentPostprocessing = 0;
124+ };
125+/* End PBXSourcesBuildPhase section */
126+
127+/* Begin XCBuildConfiguration section */
128+ 03A27D3C1D796BB600B2D016 /* Debug */ = {
129+ isa = XCBuildConfiguration;
130+ buildSettings = {
131+ ALWAYS_SEARCH_USER_PATHS = NO;
132+ CLANG_ANALYZER_NONNULL = YES;
133+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
134+ CLANG_CXX_LIBRARY = "libc++";
135+ CLANG_ENABLE_MODULES = YES;
136+ CLANG_ENABLE_OBJC_ARC = YES;
137+ CLANG_WARN_BOOL_CONVERSION = YES;
138+ CLANG_WARN_CONSTANT_CONVERSION = YES;
139+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
140+ CLANG_WARN_EMPTY_BODY = YES;
141+ CLANG_WARN_ENUM_CONVERSION = YES;
142+ CLANG_WARN_INT_CONVERSION = YES;
143+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
144+ CLANG_WARN_UNREACHABLE_CODE = YES;
145+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
146+ CODE_SIGN_IDENTITY = "-";
147+ COPY_PHASE_STRIP = NO;
148+ DEBUG_INFORMATION_FORMAT = dwarf;
149+ ENABLE_STRICT_OBJC_MSGSEND = YES;
150+ ENABLE_TESTABILITY = YES;
151+ GCC_C_LANGUAGE_STANDARD = gnu99;
152+ GCC_DYNAMIC_NO_PIC = NO;
153+ GCC_NO_COMMON_BLOCKS = YES;
154+ GCC_OPTIMIZATION_LEVEL = 0;
155+ GCC_PREPROCESSOR_DEFINITIONS = (
156+ "DEBUG=1",
157+ "$(inherited)",
158+ );
159+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
160+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
161+ GCC_WARN_UNDECLARED_SELECTOR = YES;
162+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
163+ GCC_WARN_UNUSED_FUNCTION = YES;
164+ GCC_WARN_UNUSED_VARIABLE = YES;
165+ MACOSX_DEPLOYMENT_TARGET = 10.11;
166+ MTL_ENABLE_DEBUG_INFO = YES;
167+ ONLY_ACTIVE_ARCH = YES;
168+ SDKROOT = macosx;
169+ };
170+ name = Debug;
171+ };
172+ 03A27D3D1D796BB600B2D016 /* Release */ = {
173+ isa = XCBuildConfiguration;
174+ buildSettings = {
175+ ALWAYS_SEARCH_USER_PATHS = NO;
176+ CLANG_ANALYZER_NONNULL = YES;
177+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
178+ CLANG_CXX_LIBRARY = "libc++";
179+ CLANG_ENABLE_MODULES = YES;
180+ CLANG_ENABLE_OBJC_ARC = YES;
181+ CLANG_WARN_BOOL_CONVERSION = YES;
182+ CLANG_WARN_CONSTANT_CONVERSION = YES;
183+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
184+ CLANG_WARN_EMPTY_BODY = YES;
185+ CLANG_WARN_ENUM_CONVERSION = YES;
186+ CLANG_WARN_INT_CONVERSION = YES;
187+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
188+ CLANG_WARN_UNREACHABLE_CODE = YES;
189+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
190+ CODE_SIGN_IDENTITY = "-";
191+ COPY_PHASE_STRIP = NO;
192+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
193+ ENABLE_NS_ASSERTIONS = NO;
194+ ENABLE_STRICT_OBJC_MSGSEND = YES;
195+ GCC_C_LANGUAGE_STANDARD = gnu99;
196+ GCC_NO_COMMON_BLOCKS = YES;
197+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
198+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
199+ GCC_WARN_UNDECLARED_SELECTOR = YES;
200+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
201+ GCC_WARN_UNUSED_FUNCTION = YES;
202+ GCC_WARN_UNUSED_VARIABLE = YES;
203+ MACOSX_DEPLOYMENT_TARGET = 10.11;
204+ MTL_ENABLE_DEBUG_INFO = NO;
205+ SDKROOT = macosx;
206+ };
207+ name = Release;
208+ };
209+ 03A27D3F1D796BB600B2D016 /* Debug */ = {
210+ isa = XCBuildConfiguration;
211+ buildSettings = {
212+ PRODUCT_NAME = "$(TARGET_NAME)";
213+ };
214+ name = Debug;
215+ };
216+ 03A27D401D796BB600B2D016 /* Release */ = {
217+ isa = XCBuildConfiguration;
218+ buildSettings = {
219+ PRODUCT_NAME = "$(TARGET_NAME)";
220+ };
221+ name = Release;
222+ };
223+/* End XCBuildConfiguration section */
224+
225+/* Begin XCConfigurationList section */
226+ 03A27D321D796BB600B2D016 /* Build configuration list for PBXProject "test_ObjCNSJSONSerializer" */ = {
227+ isa = XCConfigurationList;
228+ buildConfigurations = (
229+ 03A27D3C1D796BB600B2D016 /* Debug */,
230+ 03A27D3D1D796BB600B2D016 /* Release */,
231+ );
232+ defaultConfigurationIsVisible = 0;
233+ defaultConfigurationName = Release;
234+ };
235+ 03A27D3E1D796BB600B2D016 /* Build configuration list for PBXNativeTarget "test_ObjCNSJSONSerializer" */ = {
236+ isa = XCConfigurationList;
237+ buildConfigurations = (
238+ 03A27D3F1D796BB600B2D016 /* Debug */,
239+ 03A27D401D796BB600B2D016 /* Release */,
240+ );
241+ defaultConfigurationIsVisible = 0;
242+ };
243+/* End XCConfigurationList section */
244+ };
245+ rootObject = 03A27D2F1D796BB600B2D016 /* Project object */;
246+}
parsers/test_ObjCNSJSONSerializer/test_ObjCNSJSONSerializer.xcodeproj/project.xcworkspace/contents.xcworkspacedatanew file+7
@@ -0,0 +1,7 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<Workspace
3+ version = "1.0">
4+ <FileRef
5+ location = "self:test_ObjCNSJSONSerializer.xcodeproj">
6+ </FileRef>
7+</Workspace>
parsers/test_ObjCNSJSONSerializer/test_ObjCNSJSONSerializer.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstatenew file

Binary file not shown.

parsers/test_ObjCNSJSONSerializer/test_ObjCNSJSONSerializer.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test_ObjCNSJSONSerializer.xcschemenew file+97
@@ -0,0 +1,97 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<Scheme
3+ LastUpgradeVersion = "0730"
4+ version = "1.3">
5+ <BuildAction
6+ parallelizeBuildables = "YES"
7+ buildImplicitDependencies = "YES">
8+ <BuildActionEntries>
9+ <BuildActionEntry
10+ buildForTesting = "YES"
11+ buildForRunning = "YES"
12+ buildForProfiling = "YES"
13+ buildForArchiving = "YES"
14+ buildForAnalyzing = "YES">
15+ <BuildableReference
16+ BuildableIdentifier = "primary"
17+ BlueprintIdentifier = "03A27D361D796BB600B2D016"
18+ BuildableName = "test_ObjCNSJSONSerializer"
19+ BlueprintName = "test_ObjCNSJSONSerializer"
20+ ReferencedContainer = "container:test_ObjCNSJSONSerializer.xcodeproj">
21+ </BuildableReference>
22+ </BuildActionEntry>
23+ </BuildActionEntries>
24+ </BuildAction>
25+ <TestAction
26+ buildConfiguration = "Debug"
27+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
28+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
29+ shouldUseLaunchSchemeArgsEnv = "YES">
30+ <Testables>
31+ </Testables>
32+ <MacroExpansion>
33+ <BuildableReference
34+ BuildableIdentifier = "primary"
35+ BlueprintIdentifier = "03A27D361D796BB600B2D016"
36+ BuildableName = "test_ObjCNSJSONSerializer"
37+ BlueprintName = "test_ObjCNSJSONSerializer"
38+ ReferencedContainer = "container:test_ObjCNSJSONSerializer.xcodeproj">
39+ </BuildableReference>
40+ </MacroExpansion>
41+ <AdditionalOptions>
42+ </AdditionalOptions>
43+ </TestAction>
44+ <LaunchAction
45+ buildConfiguration = "Debug"
46+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
47+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
48+ launchStyle = "0"
49+ useCustomWorkingDirectory = "NO"
50+ ignoresPersistentStateOnLaunch = "NO"
51+ debugDocumentVersioning = "YES"
52+ debugServiceExtension = "internal"
53+ allowLocationSimulation = "YES">
54+ <BuildableProductRunnable
55+ runnableDebuggingMode = "0">
56+ <BuildableReference
57+ BuildableIdentifier = "primary"
58+ BlueprintIdentifier = "03A27D361D796BB600B2D016"
59+ BuildableName = "test_ObjCNSJSONSerializer"
60+ BlueprintName = "test_ObjCNSJSONSerializer"
61+ ReferencedContainer = "container:test_ObjCNSJSONSerializer.xcodeproj">
62+ </BuildableReference>
63+ </BuildableProductRunnable>
64+ <CommandLineArguments>
65+ <CommandLineArgument
66+ argument = "/Users/nst/Projects/dropbox/JSON/test_cases/i_number_neg_int_huge_exp.json "
67+ isEnabled = "YES">
68+ </CommandLineArgument>
69+ </CommandLineArguments>
70+ <AdditionalOptions>
71+ </AdditionalOptions>
72+ </LaunchAction>
73+ <ProfileAction
74+ buildConfiguration = "Release"
75+ shouldUseLaunchSchemeArgsEnv = "YES"
76+ savedToolIdentifier = ""
77+ useCustomWorkingDirectory = "NO"
78+ debugDocumentVersioning = "YES">
79+ <BuildableProductRunnable
80+ runnableDebuggingMode = "0">
81+ <BuildableReference
82+ BuildableIdentifier = "primary"
83+ BlueprintIdentifier = "03A27D361D796BB600B2D016"
84+ BuildableName = "test_ObjCNSJSONSerializer"
85+ BlueprintName = "test_ObjCNSJSONSerializer"
86+ ReferencedContainer = "container:test_ObjCNSJSONSerializer.xcodeproj">
87+ </BuildableReference>
88+ </BuildableProductRunnable>
89+ </ProfileAction>
90+ <AnalyzeAction
91+ buildConfiguration = "Debug">
92+ </AnalyzeAction>
93+ <ArchiveAction
94+ buildConfiguration = "Release"
95+ revealArchiveInOrganizer = "YES">
96+ </ArchiveAction>
97+</Scheme>
parsers/test_ObjCNSJSONSerializer/test_ObjCNSJSONSerializer.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plistnew file+22
@@ -0,0 +1,22 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+<plist version="1.0">
4+<dict>
5+ <key>SchemeUserState</key>
6+ <dict>
7+ <key>test_ObjCNSJSONSerializer.xcscheme</key>
8+ <dict>
9+ <key>orderHint</key>
10+ <integer>0</integer>
11+ </dict>
12+ </dict>
13+ <key>SuppressBuildableAutocreation</key>
14+ <dict>
15+ <key>03A27D361D796BB600B2D016</key>
16+ <dict>
17+ <key>primary</key>
18+ <true/>
19+ </dict>
20+ </dict>
21+</dict>
22+</plist>
parsers/test_ObjCNSJSONSerializer/test_ObjCNSJSONSerializer/a.outnew file

Binary file not shown.

parsers/test_ObjCNSJSONSerializer/test_ObjCNSJSONSerializer/a.out.dSYM/Contents/Info.plistnew file+20
@@ -0,0 +1,20 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+<plist version="1.0">
4+ <dict>
5+ <key>CFBundleDevelopmentRegion</key>
6+ <string>English</string>
7+ <key>CFBundleIdentifier</key>
8+ <string>com.apple.xcode.dsym.a.out</string>
9+ <key>CFBundleInfoDictionaryVersion</key>
10+ <string>6.0</string>
11+ <key>CFBundlePackageType</key>
12+ <string>dSYM</string>
13+ <key>CFBundleSignature</key>
14+ <string>????</string>
15+ <key>CFBundleShortVersionString</key>
16+ <string>1.0</string>
17+ <key>CFBundleVersion</key>
18+ <string>1</string>
19+ </dict>
20+</plist>
parsers/test_ObjCNSJSONSerializer/test_ObjCNSJSONSerializer/a.out.dSYM/Contents/Resources/DWARF/a.outnew file

Binary file not shown.

parsers/test_ObjCNSJSONSerializer/test_ObjCNSJSONSerializer/findings_dir/plot_datanew file+1
@@ -0,0 +1 @@
1+# unix_time, cycles_done, cur_path, paths_total, pending_total, pending_favs, map_size, unique_crashes, unique_hangs, max_depth, execs_per_sec
parsers/test_ObjCNSJSONSerializer/test_ObjCNSJSONSerializer/main.mnew file+32
@@ -0,0 +1,32 @@
1+//
2+// main.m
3+// test_ObjCNSJSONSerializer
4+//
5+// Created by Nicolas Seriot on 02/09/16.
6+// Copyright © 2016 Swissquote. All rights reserved.
7+//
8+
9+#import <Foundation/Foundation.h>
10+
11+int main(int argc, const char * argv[]) {
12+ @autoreleasepool {
13+
14+ if ([[NSProcessInfo processInfo].arguments count] != 2) {
15+ NSLog(@"Usage: ./%@ file.json", [NSProcessInfo processInfo].arguments[0]);
16+ return 1;
17+ }
18+
19+ NSString *path = [NSProcessInfo processInfo].arguments[1];
20+ NSURL *url = [NSURL fileURLWithPath:path];
21+ NSData *data = [NSData dataWithContentsOfURL:url];
22+
23+ id o = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
24+
25+ if (o == nil) {
26+ return 1;
27+ } else {
28+ NSLog(@"-- %@", o);
29+ }
30+ }
31+ return 0;
32+}
parsers/test_SBJSON/SBJson4.hnew file+35
@@ -0,0 +1,35 @@
1+/*
2+ Copyright (C) 2009-2011 Stig Brautaset. All rights reserved.
3+
4+ Redistribution and use in source and binary forms, with or without
5+ modification, are permitted provided that the following conditions are met:
6+
7+ * Redistributions of source code must retain the above copyright notice, this
8+ list of conditions and the following disclaimer.
9+
10+ * Redistributions in binary form must reproduce the above copyright notice,
11+ this list of conditions and the following disclaimer in the documentation
12+ and/or other materials provided with the distribution.
13+
14+ * Neither the name of the author nor the names of its contributors may be used
15+ to endorse or promote products derived from this software without specific
16+ prior written permission.
17+
18+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
22+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28+ */
29+
30+#import "SBJson4Writer.h"
31+#import "SBJson4StreamParser.h"
32+#import "SBJson4Parser.h"
33+#import "SBJson4StreamWriter.h"
34+#import "SBJson4StreamTokeniser.h"
35+
parsers/test_SBJSON/SBJson4Parser.hnew file+248
@@ -0,0 +1,248 @@
1+/*
2+ Copyright (c) 2010-2013, Stig Brautaset.
3+ All rights reserved.
4+
5+ Redistribution and use in source and binary forms, with or without
6+ modification, are permitted provided that the following conditions are
7+ met:
8+
9+ Redistributions of source code must retain the above copyright
10+ notice, this list of conditions and the following disclaimer.
11+
12+ Redistributions in binary form must reproduce the above copyright
13+ notice, this list of conditions and the following disclaimer in the
14+ documentation and/or other materials provided with the distribution.
15+
16+ Neither the name of the the author nor the names of its contributors
17+ may be used to endorse or promote products derived from this software
18+ without specific prior written permission.
19+
20+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
21+ IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22+ TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23+ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31+ */
32+
33+#import <Foundation/Foundation.h>
34+#import "SBJson4StreamParser.h"
35+
36+/**
37+ Block called when the parser has parsed an item. This could be once
38+ for each root document parsed, or once for each unwrapped root array element.
39+
40+ @param item contains the parsed item.
41+ @param stop set to YES if you want the parser to stop
42+ */
43+typedef void (^SBJson4ValueBlock)(id item, BOOL* stop);
44+
45+/**
46+ Block called if an error occurs.
47+ @param error the error.
48+ */
49+typedef void (^SBJson4ErrorBlock)(NSError* error);
50+
51+/**
52+ Block used to process parsed tokens as they are encountered. You can use this
53+ to transform strings containing dates into NSDate, for example.
54+ @param item the parsed token
55+ @param path the JSON Path of the token
56+ */
57+typedef id (^SBJson4ProcessBlock)(id item, NSString* path);
58+
59+
60+/**
61+ Parse one or more chunks of JSON data.
62+
63+ Using this class directly you can reduce the apparent latency for each
64+ download/parse cycle of documents over a slow connection. You can start
65+ parsing *and return chunks of the parsed document* before the entire
66+ document is downloaded.
67+
68+ Using this class is also useful to parse huge documents on disk
69+ bit by bit so you don't have to keep them all in memory.
70+
71+ JSON is mapped to Objective-C types in the following way:
72+
73+ - null -> NSNull
74+ - string -> NSString
75+ - array -> NSMutableArray
76+ - object -> NSMutableDictionary
77+ - true -> NSNumber's -numberWithBool:YES
78+ - false -> NSNumber's -numberWithBool:NO
79+ - number -> NSNumber
80+
81+ Since Objective-C doesn't have a dedicated class for boolean values,
82+ these turns into NSNumber instances. However, since these are
83+ initialised with the -initWithBool: method they round-trip back to JSON
84+ properly. In other words, they won't silently suddenly become 0 or 1;
85+ they'll be represented as 'true' and 'false' again.
86+
87+ Integers are parsed into either a `long long` or `unsigned long long`
88+ type if they fit, else a `double` is used. All real & exponential numbers
89+ are represented using a `double`. Previous versions of this library used
90+ an NSDecimalNumber in some cases, but this is no longer the case.
91+
92+ The default behaviour is that your passed-in block is only called once the
93+ entire input is parsed. If you set supportManyDocuments to YES and your input
94+ contains multiple (whitespace limited) JSON documents your block will be called
95+ for each document:
96+
97+ SBJson4ValueBlock block = ^(id v, BOOL *stop) {
98+ BOOL isArray = [v isKindOfClass:[NSArray class]];
99+ NSLog(@"Found: %@", isArray ? @"Array" : @"Object");
100+ };
101+
102+ SBJson4ErrorBlock eh = ^(NSError* err) {
103+ NSLog(@"OOPS: %@", err);
104+ };
105+
106+ id parser = [SBJson4Parser multiRootParserWithBlock:block
107+ errorHandler:eh];
108+
109+ // Note that this input contains multiple top-level JSON documents
110+ id data = [@"[]{}" dataWithEncoding:NSUTF8StringEncoding];
111+ [parser parse:data];
112+ [parser parse:data];
113+
114+ The above example will print:
115+
116+ - Found: Array
117+ - Found: Object
118+ - Found: Array
119+ - Found: Object
120+
121+ Often you won't have control over the input you're parsing, so can't make use
122+ of this feature. But, all is not lost: if you are parsing a long array you can
123+ get the same effect by setting rootArrayItems to YES:
124+
125+ id parser = [SBJson4Parser unwrapRootArrayParserWithBlock:block
126+ errorHandler:eh];
127+
128+ // Note that this input contains A SINGLE top-level document
129+ id data = [@"[[],{},[],{}]" dataWithEncoding:NSUTF8StringEncoding];
130+ [parser parse:data];
131+
132+ @note Stream based parsing does mean that you lose some of the correctness
133+ verification you would have with a parser that considered the entire input
134+ before returning an answer. It is technically possible to have some parts
135+ of a document returned *as if they were correct* but then encounter an error
136+ in a later part of the document. You should keep this in mind when
137+ considering whether it would suit your application.
138+
139+
140+*/
141+@interface SBJson4Parser : NSObject
142+
143+/**
144+ Create a JSON Parser.
145+
146+ This can be used to create a parser that accepts only one document, or one that parses
147+ many documents any
148+
149+ @param block Called for each element. Set *stop to `YES` if you have seen
150+ enough and would like to skip the rest of the elements.
151+
152+ @param allowMultiRoot Indicate that you are expecting multiple whitespace-separated
153+ JSON documents, similar to what Twitter uses.
154+
155+ @param unwrapRootArray If set the parser will pretend an root array does not exist
156+ and the enumerator block will be called once for each item in it. This option
157+ does nothing if the the JSON has an object at its root.
158+
159+ @param eh Called if the parser encounters an error.
160+
161+ @see -unwrapRootArrayParserWithBlock:errorHandler:
162+ @see -multiRootParserWithBlock:errorHandler:
163+ @see -initWithBlock:processBlock:multiRoot:unwrapRootArray:maxDepth:errorHandler:
164+
165+ */
166++ (id)parserWithBlock:(SBJson4ValueBlock)block
167+ allowMultiRoot:(BOOL)allowMultiRoot
168+ unwrapRootArray:(BOOL)unwrapRootArray
169+ errorHandler:(SBJson4ErrorBlock)eh;
170+
171+
172+/**
173+ Create a JSON Parser that parses multiple whitespace separated documents.
174+ This is useful for something like Twitter's feed, which gives you one JSON
175+ document per line.
176+
177+ @param block Called for each element. Set *stop to `YES` if you have seen
178+ enough and would like to skip the rest of the elements.
179+
180+ @param eh Called if the parser encounters an error.
181+
182+ @see +unwrapRootArrayParserWithBlock:errorHandler:
183+ @see +parserWithBlock:allowMultiRoot:unwrapRootArray:errorHandler:
184+ @see -initWithBlock:processBlock:multiRoot:unwrapRootArray:maxDepth:errorHandler:
185+ */
186++ (id)multiRootParserWithBlock:(SBJson4ValueBlock)block
187+ errorHandler:(SBJson4ErrorBlock)eh;
188+
189+/**
190+ Create a JSON Parser that parses a huge array and calls for the value block for
191+ each element in the outermost array.
192+
193+ @param block Called for each element. Set *stop to `YES` if you have seen
194+ enough and would like to skip the rest of the elements.
195+
196+ @param eh Called if the parser encounters an error.
197+
198+ @see +multiRootParserWithBlock:errorHandler:
199+ @see +parserWithBlock:allowMultiRoot:unwrapRootArray:errorHandler:
200+ @see -initWithBlock:processBlock:multiRoot:unwrapRootArray:maxDepth:errorHandler:
201+ */
202++ (id)unwrapRootArrayParserWithBlock:(SBJson4ValueBlock)block
203+ errorHandler:(SBJson4ErrorBlock)eh;
204+
205+/**
206+ Create a JSON Parser.
207+
208+ @param block Called for each element. Set *stop to `YES` if you have seen
209+ enough and would like to skip the rest of the elements.
210+
211+ @param processBlock A block that allows you to process individual values before being
212+ returned.
213+
214+ @param multiRoot Indicate that you are expecting multiple whitespace-separated
215+ JSON documents, similar to what Twitter uses.
216+
217+ @param unwrapRootArray If set the parser will pretend an root array does not exist
218+ and the enumerator block will be called once for each item in it. This option
219+ does nothing if the the JSON has an object at its root.
220+
221+ @param maxDepth The max recursion depth of the parser. Defaults to 32.
222+
223+ @param eh Called if the parser encounters an error.
224+
225+ */
226+- (id)initWithBlock:(SBJson4ValueBlock)block
227+ processBlock:(SBJson4ProcessBlock)processBlock
228+ multiRoot:(BOOL)multiRoot
229+ unwrapRootArray:(BOOL)unwrapRootArray
230+ maxDepth:(NSUInteger)maxDepth
231+ errorHandler:(SBJson4ErrorBlock)eh;
232+
233+/**
234+ Parse some JSON
235+
236+ The JSON is assumed to be UTF8 encoded. This can be a full JSON document, or a part of one.
237+
238+ @param data An NSData object containing the next chunk of JSON
239+
240+ @return
241+ - SBJson4ParserComplete if a full document was found
242+ - SBJson4ParserWaitingForData if a partial document was found and more data is required to complete it
243+ - SBJson4ParserError if an error occurred.
244+
245+ */
246+- (SBJson4ParserStatus)parse:(NSData*)data;
247+
248+@end
parsers/test_SBJSON/SBJson4Parser.mnew file+287
@@ -0,0 +1,287 @@
1+/*
2+ Copyright (c) 2010-2013, Stig Brautaset.
3+ All rights reserved.
4+
5+ Redistribution and use in source and binary forms, with or without
6+ modification, are permitted provided that the following conditions are
7+ met:
8+
9+ Redistributions of source code must retain the above copyright
10+ notice, this list of conditions and the following disclaimer.
11+
12+ Redistributions in binary form must reproduce the above copyright
13+ notice, this list of conditions and the following disclaimer in the
14+ documentation and/or other materials provided with the distribution.
15+
16+ Neither the name of the the author nor the names of its contributors
17+ may be used to endorse or promote products derived from this software
18+ without specific prior written permission.
19+
20+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
21+ IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22+ TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23+ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31+ */
32+
33+#if !__has_feature(objc_arc)
34+#error "This source file must be compiled with ARC enabled!"
35+#endif
36+
37+#import "SBJson4Parser.h"
38+
39+@interface SBJson4Parser () <SBJson4StreamParserDelegate>
40+
41+- (void)pop;
42+
43+@end
44+
45+typedef enum {
46+ SBJson4ChunkNone,
47+ SBJson4ChunkArray,
48+ SBJson4ChunkObject,
49+} SBJson4ChunkType;
50+
51+@implementation SBJson4Parser {
52+ SBJson4StreamParser *_parser;
53+ NSUInteger depth;
54+ NSMutableArray *array;
55+ NSMutableDictionary *dict;
56+ NSMutableArray *keyStack;
57+ NSMutableArray *stack;
58+ NSMutableArray *path;
59+ SBJson4ProcessBlock processBlock;
60+ SBJson4ErrorBlock errorHandler;
61+ SBJson4ValueBlock valueBlock;
62+ SBJson4ChunkType currentType;
63+ BOOL supportManyDocuments;
64+ BOOL supportPartialDocuments;
65+ NSUInteger _maxDepth;
66+}
67+
68+#pragma mark Housekeeping
69+
70+- (id)init {
71+ @throw @"Not Implemented";
72+}
73+
74++ (id)multiRootParserWithBlock:(SBJson4ValueBlock)block errorHandler:(SBJson4ErrorBlock)eh {
75+ return [self parserWithBlock:block
76+ allowMultiRoot:YES
77+ unwrapRootArray:NO
78+ errorHandler:eh];
79+}
80+
81++ (id)unwrapRootArrayParserWithBlock:(SBJson4ValueBlock)block errorHandler:(SBJson4ErrorBlock)eh {
82+ return [self parserWithBlock:block
83+ allowMultiRoot:NO
84+ unwrapRootArray:YES
85+ errorHandler:eh];
86+}
87+
88++ (id)parserWithBlock:(SBJson4ValueBlock)block
89+ allowMultiRoot:(BOOL)allowMultiRoot
90+ unwrapRootArray:(BOOL)unwrapRootArray
91+ errorHandler:(SBJson4ErrorBlock)eh {
92+
93+ return [[self alloc] initWithBlock:block
94+ processBlock:nil
95+ multiRoot:allowMultiRoot
96+ unwrapRootArray:unwrapRootArray
97+ maxDepth:32
98+ errorHandler:eh];
99+}
100+
101+- (id)initWithBlock:(SBJson4ValueBlock)block
102+ processBlock:(SBJson4ProcessBlock)initialProcessBlock
103+ multiRoot:(BOOL)multiRoot
104+ unwrapRootArray:(BOOL)unwrapRootArray
105+ maxDepth:(NSUInteger)maxDepth
106+ errorHandler:(SBJson4ErrorBlock)eh {
107+
108+ self = [super init];
109+ if (self) {
110+ _parser = [[SBJson4StreamParser alloc] init];
111+ _parser.delegate = self;
112+
113+ supportManyDocuments = multiRoot;
114+ supportPartialDocuments = unwrapRootArray;
115+
116+ valueBlock = block;
117+ keyStack = [[NSMutableArray alloc] initWithCapacity:32];
118+ stack = [[NSMutableArray alloc] initWithCapacity:32];
119+ if (initialProcessBlock)
120+ path = [[NSMutableArray alloc] initWithCapacity:32];
121+ processBlock = initialProcessBlock;
122+ errorHandler = eh ? eh : ^(NSError*err) { NSLog(@"%@", err); };
123+ currentType = SBJson4ChunkNone;
124+ _maxDepth = maxDepth;
125+ }
126+ return self;
127+}
128+
129+
130+#pragma mark Private methods
131+
132+- (void)pop {
133+ [stack removeLastObject];
134+ array = nil;
135+ dict = nil;
136+ currentType = SBJson4ChunkNone;
137+
138+ id value = [stack lastObject];
139+
140+ if ([value isKindOfClass:[NSArray class]]) {
141+ array = value;
142+ currentType = SBJson4ChunkArray;
143+ } else if ([value isKindOfClass:[NSDictionary class]]) {
144+ dict = value;
145+ currentType = SBJson4ChunkObject;
146+ }
147+}
148+
149+- (void)parserFound:(id)obj isValue:(BOOL)isValue {
150+ NSParameterAssert(obj);
151+
152+ if(processBlock&&path) {
153+ if(isValue) {
154+ obj = processBlock(obj,[NSString stringWithFormat:@"%@.%@",[self pathString],[keyStack lastObject]]);
155+ }
156+ else {
157+ [path removeLastObject];
158+ }
159+ }
160+
161+ switch (currentType) {
162+ case SBJson4ChunkArray:
163+ [array addObject:obj];
164+ break;
165+
166+ case SBJson4ChunkObject:
167+ NSParameterAssert(keyStack.count);
168+ [dict setObject:obj forKey:[keyStack lastObject]];
169+ [keyStack removeLastObject];
170+ break;
171+
172+ case SBJson4ChunkNone: {
173+ __block BOOL stop = NO;
174+ valueBlock(obj, &stop);
175+ if (stop) [_parser stop];
176+ }
177+ break;
178+
179+ default:
180+ break;
181+ }
182+}
183+
184+
185+#pragma mark Delegate methods
186+
187+- (void)parserFoundObjectStart {
188+ ++depth;
189+ if (depth > _maxDepth)
190+ [self maxDepthError];
191+
192+ if (path)
193+ [self addToPath];
194+ dict = [NSMutableDictionary new];
195+ [stack addObject:dict];
196+ currentType = SBJson4ChunkObject;
197+}
198+
199+- (void)parserFoundObjectKey:(NSString *)key_ {
200+ [keyStack addObject:key_];
201+}
202+
203+- (void)parserFoundObjectEnd {
204+ depth--;
205+ id value = dict;
206+ [self pop];
207+ [self parserFound:value isValue:NO ];
208+}
209+
210+- (void)parserFoundArrayStart {
211+ depth++;
212+ if (depth > _maxDepth)
213+ [self maxDepthError];
214+
215+ if (depth > 1 || !supportPartialDocuments) {
216+ if(path)
217+ [self addToPath];
218+ array = [NSMutableArray new];
219+ [stack addObject:array];
220+ currentType = SBJson4ChunkArray;
221+ }
222+}
223+
224+- (void)parserFoundArrayEnd {
225+ depth--;
226+ if (depth > 1 || !supportPartialDocuments) {
227+ id value = array;
228+ [self pop];
229+ [self parserFound:value isValue:NO ];
230+ }
231+}
232+
233+- (void)maxDepthError {
234+ id ui = @{ NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Input depth exceeds max depth of %lu", (unsigned long)_maxDepth]};
235+ errorHandler([NSError errorWithDomain:@"org.sbjson.parser" code:3 userInfo:ui]);
236+ [_parser stop];
237+}
238+
239+- (void)parserFoundBoolean:(BOOL)x {
240+ [self parserFound:[NSNumber numberWithBool:x] isValue:YES ];
241+}
242+
243+- (void)parserFoundNull {
244+ [self parserFound:[NSNull null] isValue:YES ];
245+}
246+
247+- (void)parserFoundNumber:(NSNumber *)num {
248+ [self parserFound:num isValue:YES ];
249+}
250+
251+- (void)parserFoundString:(NSString *)string {
252+ [self parserFound:string isValue:YES ];
253+}
254+
255+- (void)parserFoundError:(NSError *)err {
256+ errorHandler(err);
257+}
258+
259+- (void)addToPath {
260+ if([path count]==0)
261+ [path addObject:@"$"];
262+ else if([[stack lastObject] isKindOfClass:[NSArray class]])
263+ [path addObject:@([[stack lastObject] count])];
264+ else
265+ [path addObject:[keyStack lastObject]];
266+}
267+
268+- (NSString *)pathString {
269+ NSMutableString *pathString = [NSMutableString stringWithString:@"$"];
270+ for(NSUInteger i=1;i<[path count];i++) {
271+ if([[path objectAtIndex:i] isKindOfClass:[NSNumber class]])
272+ [pathString appendString:[NSString stringWithFormat:@"[%@]",[path objectAtIndex:i]]];
273+ else
274+ [pathString appendString:[NSString stringWithFormat:@".%@",[path objectAtIndex:i]]];
275+ }
276+ return pathString;
277+}
278+
279+- (BOOL)parserShouldSupportManyDocuments {
280+ return supportManyDocuments;
281+}
282+
283+- (SBJson4ParserStatus)parse:(NSData *)data {
284+ return [_parser parse:data];
285+}
286+
287+@end
parsers/test_SBJSON/SBJson4StreamParser.hnew file+131
@@ -0,0 +1,131 @@
1+/*
2+ Copyright (c) 2010-2013, Stig Brautaset.
3+ All rights reserved.
4+
5+ Redistribution and use in source and binary forms, with or without
6+ modification, are permitted provided that the following conditions are
7+ met:
8+
9+ Redistributions of source code must retain the above copyright
10+ notice, this list of conditions and the following disclaimer.
11+
12+ Redistributions in binary form must reproduce the above copyright
13+ notice, this list of conditions and the following disclaimer in the
14+ documentation and/or other materials provided with the distribution.
15+
16+ Neither the name of the the author nor the names of its contributors
17+ may be used to endorse or promote products derived from this software
18+ without specific prior written permission.
19+
20+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
21+ IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22+ TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23+ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31+ */
32+
33+#import <Foundation/Foundation.h>
34+
35+@class SBJson4StreamParser;
36+@class SBJson4StreamParserState;
37+
38+typedef enum {
39+ SBJson4ParserComplete,
40+ SBJson4ParserStopped,
41+ SBJson4ParserWaitingForData,
42+ SBJson4ParserError,
43+} SBJson4ParserStatus;
44+
45+
46+/**
47+ Delegate for interacting directly with the low-level parser
48+
49+ You will most likely find it much more convenient to use the SBJson4Parser instead.
50+ */
51+@protocol SBJson4StreamParserDelegate < NSObject >
52+
53+/// Called when object start is found
54+- (void)parserFoundObjectStart;
55+
56+/// Called when object key is found
57+- (void)parserFoundObjectKey:(NSString *)key;
58+
59+/// Called when object end is found
60+- (void)parserFoundObjectEnd;
61+
62+/// Called when array start is found
63+- (void)parserFoundArrayStart;
64+
65+/// Called when array end is found
66+- (void)parserFoundArrayEnd;
67+
68+/// Called when a boolean value is found
69+- (void)parserFoundBoolean:(BOOL)x;
70+
71+/// Called when a null value is found
72+- (void)parserFoundNull;
73+
74+/// Called when a number is found
75+- (void)parserFoundNumber:(NSNumber *)num;
76+
77+/// Called when a string is found
78+- (void)parserFoundString:(NSString *)string;
79+
80+/// Called when an error occurs
81+- (void)parserFoundError:(NSError *)err;
82+
83+@optional
84+
85+/// Called to determine whether to allow multiple whitespace-separated documents
86+- (BOOL)parserShouldSupportManyDocuments;
87+
88+@end
89+
90+/**
91+ Low-level Stream parser
92+
93+ You most likely want to use the SBJson4Parser instead, but if you
94+ really need low-level access to tokens one-by-one you can use this class.
95+ */
96+@interface SBJson4StreamParser : NSObject
97+
98+@property (nonatomic, weak) SBJson4StreamParserState *state; // Private
99+
100+/**
101+ Delegate to receive messages
102+
103+ The object set here receives a series of messages as the parser breaks down the JSON stream
104+ into valid tokens.
105+
106+ Usually this should be an instance of SBJson4Parser, but you can
107+ substitute your own implementation of the SBJson4StreamParserDelegate protocol if you need to.
108+ */
109+@property (nonatomic, weak) id<SBJson4StreamParserDelegate> delegate;
110+
111+/**
112+ Parse some JSON
113+
114+ The JSON is assumed to be UTF8 encoded. This can be a full JSON document, or a part of one.
115+
116+ @param data An NSData object containing the next chunk of JSON
117+
118+ @return
119+ - SBJson4ParserComplete if a full document was found
120+ - SBJson4ParserWaitingForData if a partial document was found and more data is required to complete it
121+ - SBJson4ParserError if an error occurred.
122+
123+ */
124+- (SBJson4ParserStatus)parse:(NSData*)data;
125+
126+/**
127+ Call this to cause parsing to stop.
128+ */
129+- (void)stop;
130+
131+@end
parsers/test_SBJSON/SBJson4StreamParser.mnew file+317
@@ -0,0 +1,317 @@
1+/*
2+ Copyright (c) 2010, Stig Brautaset.
3+ All rights reserved.
4+
5+ Redistribution and use in source and binary forms, with or without
6+ modification, are permitted provided that the following conditions are
7+ met:
8+
9+ Redistributions of source code must retain the above copyright
10+ notice, this list of conditions and the following disclaimer.
11+
12+ Redistributions in binary form must reproduce the above copyright
13+ notice, this list of conditions and the following disclaimer in the
14+ documentation and/or other materials provided with the distribution.
15+
16+ Neither the name of the the author nor the names of its contributors
17+ may be used to endorse or promote products derived from this software
18+ without specific prior written permission.
19+
20+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
21+ IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22+ TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23+ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31+ */
32+
33+#if !__has_feature(objc_arc)
34+#error "This source file must be compiled with ARC enabled!"
35+#endif
36+
37+#import "SBJson4StreamParser.h"
38+#import "SBJson4StreamTokeniser.h"
39+#import "SBJson4StreamParserState.h"
40+
41+#define SBStringIsSurrogateHighCharacter(character) ((character >= 0xD800UL) && (character <= 0xDBFFUL))
42+
43+@implementation SBJson4StreamParser {
44+@private
45+ SBJson4StreamTokeniser *tokeniser;
46+ BOOL stopped;
47+ NSMutableArray *_stateStack;
48+}
49+
50+#pragma mark Housekeeping
51+
52+- (id)init {
53+ self = [super init];
54+ if (self) {
55+ _stateStack = [[NSMutableArray alloc] initWithCapacity:32];
56+ _state = [SBJson4StreamParserStateStart sharedInstance];
57+ tokeniser = [[SBJson4StreamTokeniser alloc] init];
58+ }
59+ return self;
60+}
61+
62+
63+#pragma mark Methods
64+
65+- (NSString*)tokenName:(sbjson4_token_t)token {
66+ switch (token) {
67+ case sbjson4_token_array_open:
68+ return @"start of array";
69+
70+ case sbjson4_token_array_close:
71+ return @"end of array";
72+
73+ case sbjson4_token_integer:
74+ case sbjson4_token_real:
75+ return @"number";
76+
77+ case sbjson4_token_string:
78+ case sbjson4_token_encoded:
79+ return @"string";
80+
81+ case sbjson4_token_bool:
82+ return @"boolean";
83+
84+ case sbjson4_token_null:
85+ return @"null";
86+
87+ case sbjson4_token_entry_sep:
88+ return @"key-value separator";
89+
90+ case sbjson4_token_value_sep:
91+ return @"value separator";
92+
93+ case sbjson4_token_object_open:
94+ return @"start of object";
95+
96+ case sbjson4_token_object_close:
97+ return @"end of object";
98+
99+ case sbjson4_token_eof:
100+ case sbjson4_token_error:
101+ break;
102+ }
103+ NSAssert(NO, @"Should not get here");
104+ return @"<aaiiie!>";
105+}
106+
107+- (void)handleObjectStart {
108+ [_delegate parserFoundObjectStart];
109+ [_stateStack addObject:_state];
110+ _state = [SBJson4StreamParserStateObjectStart sharedInstance];
111+}
112+
113+- (void)handleObjectEnd: (sbjson4_token_t) tok {
114+ _state = [_stateStack lastObject];
115+ [_stateStack removeLastObject];
116+ [_state parser:self shouldTransitionTo:tok];
117+ [_delegate parserFoundObjectEnd];
118+}
119+
120+- (void)handleArrayStart {
121+ [_delegate parserFoundArrayStart];
122+ [_stateStack addObject:_state];
123+ _state = [SBJson4StreamParserStateArrayStart sharedInstance];
124+}
125+
126+- (void)handleArrayEnd: (sbjson4_token_t) tok {
127+ _state = [_stateStack lastObject];
128+ [_stateStack removeLastObject];
129+ [_state parser:self shouldTransitionTo:tok];
130+ [_delegate parserFoundArrayEnd];
131+}
132+
133+- (void) handleTokenNotExpectedHere: (sbjson4_token_t) tok {
134+ NSString *tokenName = [self tokenName:tok];
135+ NSString *stateName = [_state name];
136+
137+ _state = [SBJson4StreamParserStateError sharedInstance];
138+ id ui = @{ NSLocalizedDescriptionKey : [NSString stringWithFormat:@"Token '%@' not expected %@", tokenName, stateName]};
139+ [_delegate parserFoundError:[NSError errorWithDomain:@"org.sbjson.parser" code:2 userInfo:ui]];
140+}
141+
142+- (SBJson4ParserStatus)parse:(NSData *)data_ {
143+ @autoreleasepool {
144+ [tokeniser appendData:data_];
145+
146+ for (;;) {
147+
148+ if (stopped)
149+ return SBJson4ParserStopped;
150+
151+ if ([_state isError])
152+ return SBJson4ParserError;
153+
154+ char *token;
155+ NSUInteger token_len;
156+ sbjson4_token_t tok = [tokeniser getToken:&token length:&token_len];
157+
158+ switch (tok) {
159+ case sbjson4_token_eof:
160+ return [_state parserShouldReturn:self];
161+
162+ case sbjson4_token_error:
163+ _state = [SBJson4StreamParserStateError sharedInstance];
164+ [_delegate parserFoundError:[NSError errorWithDomain:@"org.sbjson.parser" code:3
165+ userInfo:@{NSLocalizedDescriptionKey : tokeniser.error}]];
166+ return SBJson4ParserError;
167+
168+ default:
169+
170+ if (![_state parser:self shouldAcceptToken:tok]) {
171+ [self handleTokenNotExpectedHere: tok];
172+ return SBJson4ParserError;
173+ }
174+
175+ switch (tok) {
176+ case sbjson4_token_object_open:
177+ [self handleObjectStart];
178+ break;
179+
180+ case sbjson4_token_object_close:
181+ [self handleObjectEnd: tok];
182+ break;
183+
184+ case sbjson4_token_array_open:
185+ [self handleArrayStart];
186+ break;
187+
188+ case sbjson4_token_array_close:
189+ [self handleArrayEnd: tok];
190+ break;
191+
192+ case sbjson4_token_value_sep:
193+ case sbjson4_token_entry_sep:
194+ [_state parser:self shouldTransitionTo:tok];
195+ break;
196+
197+ case sbjson4_token_bool:
198+ [_delegate parserFoundBoolean:token[0] == 't'];
199+ [_state parser:self shouldTransitionTo:tok];
200+ break;
201+
202+
203+ case sbjson4_token_null:
204+ [_delegate parserFoundNull];
205+ [_state parser:self shouldTransitionTo:tok];
206+ break;
207+
208+ case sbjson4_token_integer: {
209+ const int UNSIGNED_LONG_LONG_MAX_DIGITS = 20;
210+ if (token_len <= UNSIGNED_LONG_LONG_MAX_DIGITS) {
211+ if (*token == '-')
212+ [_delegate parserFoundNumber:@(strtoll(token, NULL, 10))];
213+ else
214+ [_delegate parserFoundNumber:@(strtoull(token, NULL, 10))];
215+
216+ [_state parser:self shouldTransitionTo:tok];
217+ break;
218+ }
219+ }
220+ // FALL THROUGH
221+
222+ case sbjson4_token_real: {
223+ [_delegate parserFoundNumber:@(strtod(token, NULL))];
224+ [_state parser:self shouldTransitionTo:tok];
225+ break;
226+ }
227+
228+ case sbjson4_token_string: {
229+ NSString *string = [[NSString alloc] initWithBytes:token length:token_len encoding:NSUTF8StringEncoding];
230+ if ([_state needKey])
231+ [_delegate parserFoundObjectKey:string];
232+ else
233+ [_delegate parserFoundString:string];
234+ [_state parser:self shouldTransitionTo:tok];
235+ break;
236+ }
237+
238+ case sbjson4_token_encoded: {
239+ NSString *string = [self decodeStringToken:token length:token_len];
240+ if ([_state needKey])
241+ [_delegate parserFoundObjectKey:string];
242+ else
243+ [_delegate parserFoundString:string];
244+ [_state parser:self shouldTransitionTo:tok];
245+ break;
246+ }
247+
248+ default:
249+ break;
250+ }
251+ break;
252+ }
253+ }
254+ return SBJson4ParserComplete;
255+ }
256+}
257+
258+- (unichar)decodeHexQuad:(char *)quad {
259+ unichar ch = 0;
260+ for (NSUInteger i = 0; i < 4; i++) {
261+ int c = quad[i];
262+ ch *= 16;
263+ switch (c) {
264+ case '0' ... '9': ch += c - '0'; break;
265+ case 'a' ... 'f': ch += 10 + c - 'a'; break;
266+ case 'A' ... 'F': ch += 10 + c - 'A'; break;
267+ default: @throw @"FUT FUT FUT";
268+ }
269+ }
270+ return ch;
271+}
272+
273+- (NSString*)decodeStringToken:(char*)bytes length:(NSUInteger)len {
274+ NSMutableData *buf = [NSMutableData dataWithCapacity:len];
275+ for (NSUInteger i = 0; i < len;) {
276+ switch ((unsigned char)bytes[i]) {
277+ case '\\': {
278+ switch ((unsigned char)bytes[++i]) {
279+ case '"': [buf appendBytes:"\"" length:1]; i++; break;
280+ case '/': [buf appendBytes:"/" length:1]; i++; break;
281+ case '\\': [buf appendBytes:"\\" length:1]; i++; break;
282+ case 'b': [buf appendBytes:"\b" length:1]; i++; break;
283+ case 'f': [buf appendBytes:"\f" length:1]; i++; break;
284+ case 'n': [buf appendBytes:"\n" length:1]; i++; break;
285+ case 'r': [buf appendBytes:"\r" length:1]; i++; break;
286+ case 't': [buf appendBytes:"\t" length:1]; i++; break;
287+ case 'u': {
288+ unichar hi = [self decodeHexQuad:bytes + i + 1];
289+ i += 5;
290+ if (SBStringIsSurrogateHighCharacter(hi)) {
291+ // Skip past \u that we know is there..
292+ unichar lo = [self decodeHexQuad:bytes + i + 2];
293+ i += 6;
294+ [buf appendData:[[NSString stringWithFormat:@"%C%C", hi, lo] dataUsingEncoding:NSUTF8StringEncoding]];
295+ } else {
296+ [buf appendData:[[NSString stringWithFormat:@"%C", hi] dataUsingEncoding:NSUTF8StringEncoding]];
297+ }
298+ break;
299+ }
300+ default: @throw @"FUT FUT FUT";
301+ }
302+ break;
303+ }
304+ default:
305+ [buf appendBytes:bytes + i length:1];
306+ i++;
307+ break;
308+ }
309+ }
310+ return [[NSString alloc] initWithData:buf encoding:NSUTF8StringEncoding];
311+}
312+
313+- (void)stop {
314+ stopped = YES;
315+}
316+
317+@end
parsers/test_SBJSON/SBJson4StreamParserState.hnew file+82
@@ -0,0 +1,82 @@
1+/*
2+ Copyright (c) 2010, Stig Brautaset.
3+ All rights reserved.
4+
5+ Redistribution and use in source and binary forms, with or without
6+ modification, are permitted provided that the following conditions are
7+ met:
8+
9+ Redistributions of source code must retain the above copyright
10+ notice, this list of conditions and the following disclaimer.
11+
12+ Redistributions in binary form must reproduce the above copyright
13+ notice, this list of conditions and the following disclaimer in the
14+ documentation and/or other materials provided with the distribution.
15+
16+ Neither the name of the the author nor the names of its contributors
17+ may be used to endorse or promote products derived from this software
18+ without specific prior written permission.
19+
20+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
21+ IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22+ TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23+ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31+ */
32+
33+#import <Foundation/Foundation.h>
34+
35+#import "SBJson4StreamTokeniser.h"
36+#import "SBJson4StreamParser.h"
37+
38+@interface SBJson4StreamParserState : NSObject
39++ (id)sharedInstance;
40+
41+- (BOOL)parser:(SBJson4StreamParser *)parser shouldAcceptToken:(sbjson4_token_t)token;
42+- (SBJson4ParserStatus)parserShouldReturn:(SBJson4StreamParser *)parser;
43+- (void)parser:(SBJson4StreamParser *)parser shouldTransitionTo:(sbjson4_token_t)tok;
44+- (BOOL)needKey;
45+- (BOOL)isError;
46+
47+- (NSString*)name;
48+
49+@end
50+
51+@interface SBJson4StreamParserStateStart : SBJson4StreamParserState
52+@end
53+
54+@interface SBJson4StreamParserStateComplete : SBJson4StreamParserState
55+@end
56+
57+@interface SBJson4StreamParserStateError : SBJson4StreamParserState
58+@end
59+
60+@interface SBJson4StreamParserStateObjectStart : SBJson4StreamParserState
61+@end
62+
63+@interface SBJson4StreamParserStateObjectGotKey : SBJson4StreamParserState
64+@end
65+
66+@interface SBJson4StreamParserStateObjectSeparator : SBJson4StreamParserState
67+@end
68+
69+@interface SBJson4StreamParserStateObjectGotValue : SBJson4StreamParserState
70+@end
71+
72+@interface SBJson4StreamParserStateObjectNeedKey : SBJson4StreamParserState
73+@end
74+
75+@interface SBJson4StreamParserStateArrayStart : SBJson4StreamParserState
76+@end
77+
78+@interface SBJson4StreamParserStateArrayGotValue : SBJson4StreamParserState
79+@end
80+
81+@interface SBJson4StreamParserStateArrayNeedValue : SBJson4StreamParserState
82+@end
parsers/test_SBJSON/SBJson4StreamParserState.mnew file+355
@@ -0,0 +1,355 @@
1+/*
2+ Copyright (c) 2010-2013, Stig Brautaset.
3+ All rights reserved.
4+
5+ Redistribution and use in source and binary forms, with or without
6+ modification, are permitted provided that the following conditions are
7+ met:
8+
9+ Redistributions of source code must retain the above copyright
10+ notice, this list of conditions and the following disclaimer.
11+
12+ Redistributions in binary form must reproduce the above copyright
13+ notice, this list of conditions and the following disclaimer in the
14+ documentation and/or other materials provided with the distribution.
15+
16+ Neither the name of the the author nor the names of its contributors
17+ may be used to endorse or promote products derived from this software
18+ without specific prior written permission.
19+
20+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
21+ IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22+ TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23+ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31+ */
32+
33+#if !__has_feature(objc_arc)
34+#error "This source file must be compiled with ARC enabled!"
35+#endif
36+
37+#import "SBJson4StreamParserState.h"
38+
39+#define SINGLETON \
40++ (id)sharedInstance { \
41+ static id state = nil; \
42+ if (!state) { \
43+ @synchronized(self) { \
44+ if (!state) state = [[self alloc] init]; \
45+ } \
46+ } \
47+ return state; \
48+}
49+
50+@implementation SBJson4StreamParserState
51+
52++ (id)sharedInstance { return nil; }
53+
54+- (BOOL)parser:(SBJson4StreamParser *)parser shouldAcceptToken:(sbjson4_token_t)token {
55+ return NO;
56+}
57+
58+- (SBJson4ParserStatus)parserShouldReturn:(SBJson4StreamParser *)parser {
59+ return SBJson4ParserWaitingForData;
60+}
61+
62+- (void)parser:(SBJson4StreamParser *)parser shouldTransitionTo:(sbjson4_token_t)tok {}
63+
64+- (BOOL)needKey {
65+ return NO;
66+}
67+
68+- (NSString*)name {
69+ return @"<aaiie!>";
70+}
71+
72+- (BOOL)isError {
73+ return NO;
74+}
75+
76+@end
77+
78+#pragma mark -
79+
80+@implementation SBJson4StreamParserStateStart
81+
82+SINGLETON
83+
84+- (BOOL)parser:(SBJson4StreamParser *)parser shouldAcceptToken:(sbjson4_token_t)token {
85+ return token == sbjson4_token_array_open || token == sbjson4_token_object_open;
86+}
87+
88+- (void)parser:(SBJson4StreamParser *)parser shouldTransitionTo:(sbjson4_token_t)tok {
89+
90+ SBJson4StreamParserState *state = nil;
91+ switch (tok) {
92+ case sbjson4_token_array_open:
93+ state = [SBJson4StreamParserStateArrayStart sharedInstance];
94+ break;
95+
96+ case sbjson4_token_object_open:
97+ state = [SBJson4StreamParserStateObjectStart sharedInstance];
98+ break;
99+
100+ case sbjson4_token_array_close:
101+ case sbjson4_token_object_close:
102+ if ([parser.delegate respondsToSelector:@selector(parserShouldSupportManyDocuments)] && [parser.delegate parserShouldSupportManyDocuments])
103+ state = parser.state;
104+ else
105+ state = [SBJson4StreamParserStateComplete sharedInstance];
106+ break;
107+
108+ case sbjson4_token_eof:
109+ return;
110+
111+ default:
112+ state = [SBJson4StreamParserStateError sharedInstance];
113+ break;
114+ }
115+
116+
117+ parser.state = state;
118+}
119+
120+- (NSString*)name { return @"before outer-most array or object"; }
121+
122+@end
123+
124+#pragma mark -
125+
126+@implementation SBJson4StreamParserStateComplete
127+
128+SINGLETON
129+
130+- (NSString*)name { return @"after outer-most array or object"; }
131+
132+- (SBJson4ParserStatus)parserShouldReturn:(SBJson4StreamParser *)parser {
133+ return SBJson4ParserComplete;
134+}
135+
136+@end
137+
138+#pragma mark -
139+
140+@implementation SBJson4StreamParserStateError
141+
142+SINGLETON
143+
144+- (NSString*)name { return @"in error"; }
145+
146+- (SBJson4ParserStatus)parserShouldReturn:(SBJson4StreamParser *)parser {
147+ return SBJson4ParserError;
148+}
149+
150+- (BOOL)isError {
151+ return YES;
152+}
153+
154+@end
155+
156+#pragma mark -
157+
158+@implementation SBJson4StreamParserStateObjectStart
159+
160+SINGLETON
161+
162+- (NSString*)name { return @"at beginning of object"; }
163+
164+- (BOOL)parser:(SBJson4StreamParser *)parser shouldAcceptToken:(sbjson4_token_t)token {
165+ switch (token) {
166+ case sbjson4_token_object_close:
167+ case sbjson4_token_string:
168+ case sbjson4_token_encoded:
169+ return YES;
170+ default:
171+ return NO;
172+ }
173+}
174+
175+- (void)parser:(SBJson4StreamParser *)parser shouldTransitionTo:(sbjson4_token_t)tok {
176+ parser.state = [SBJson4StreamParserStateObjectGotKey sharedInstance];
177+}
178+
179+- (BOOL)needKey {
180+ return YES;
181+}
182+
183+@end
184+
185+#pragma mark -
186+
187+@implementation SBJson4StreamParserStateObjectGotKey
188+
189+SINGLETON
190+
191+- (NSString*)name { return @"after object key"; }
192+
193+- (BOOL)parser:(SBJson4StreamParser *)parser shouldAcceptToken:(sbjson4_token_t)token {
194+ return token == sbjson4_token_entry_sep;
195+}
196+
197+- (void)parser:(SBJson4StreamParser *)parser shouldTransitionTo:(sbjson4_token_t)tok {
198+ parser.state = [SBJson4StreamParserStateObjectSeparator sharedInstance];
199+}
200+
201+@end
202+
203+#pragma mark -
204+
205+@implementation SBJson4StreamParserStateObjectSeparator
206+
207+SINGLETON
208+
209+- (NSString*)name { return @"as object value"; }
210+
211+- (BOOL)parser:(SBJson4StreamParser *)parser shouldAcceptToken:(sbjson4_token_t)token {
212+ switch (token) {
213+ case sbjson4_token_object_open:
214+ case sbjson4_token_array_open:
215+ case sbjson4_token_bool:
216+ case sbjson4_token_null:
217+ case sbjson4_token_integer:
218+ case sbjson4_token_real:
219+ case sbjson4_token_string:
220+ case sbjson4_token_encoded:
221+ return YES;
222+
223+ default:
224+ return NO;
225+ }
226+}
227+
228+- (void)parser:(SBJson4StreamParser *)parser shouldTransitionTo:(sbjson4_token_t)tok {
229+ parser.state = [SBJson4StreamParserStateObjectGotValue sharedInstance];
230+}
231+
232+@end
233+
234+#pragma mark -
235+
236+@implementation SBJson4StreamParserStateObjectGotValue
237+
238+SINGLETON
239+
240+- (NSString*)name { return @"after object value"; }
241+
242+- (BOOL)parser:(SBJson4StreamParser *)parser shouldAcceptToken:(sbjson4_token_t)token {
243+ switch (token) {
244+ case sbjson4_token_object_close:
245+ case sbjson4_token_value_sep:
246+ return YES;
247+
248+ default:
249+ return NO;
250+ }
251+}
252+
253+- (void)parser:(SBJson4StreamParser *)parser shouldTransitionTo:(sbjson4_token_t)tok {
254+ parser.state = [SBJson4StreamParserStateObjectNeedKey sharedInstance];
255+}
256+
257+
258+@end
259+
260+#pragma mark -
261+
262+@implementation SBJson4StreamParserStateObjectNeedKey
263+
264+SINGLETON
265+
266+- (NSString*)name { return @"in place of object key"; }
267+
268+- (BOOL)parser:(SBJson4StreamParser *)parser shouldAcceptToken:(sbjson4_token_t)token {
269+ return sbjson4_token_string == token || sbjson4_token_encoded == token;
270+}
271+
272+- (void)parser:(SBJson4StreamParser *)parser shouldTransitionTo:(sbjson4_token_t)tok {
273+ parser.state = [SBJson4StreamParserStateObjectGotKey sharedInstance];
274+}
275+
276+- (BOOL)needKey {
277+ return YES;
278+}
279+
280+@end
281+
282+#pragma mark -
283+
284+@implementation SBJson4StreamParserStateArrayStart
285+
286+SINGLETON
287+
288+- (NSString*)name { return @"at array start"; }
289+
290+- (BOOL)parser:(SBJson4StreamParser *)parser shouldAcceptToken:(sbjson4_token_t)token {
291+ switch (token) {
292+ case sbjson4_token_object_close:
293+ case sbjson4_token_entry_sep:
294+ case sbjson4_token_value_sep:
295+ return NO;
296+
297+ default:
298+ return YES;
299+ }
300+}
301+
302+- (void)parser:(SBJson4StreamParser *)parser shouldTransitionTo:(sbjson4_token_t)tok {
303+ parser.state = [SBJson4StreamParserStateArrayGotValue sharedInstance];
304+}
305+
306+@end
307+
308+#pragma mark -
309+
310+@implementation SBJson4StreamParserStateArrayGotValue
311+
312+SINGLETON
313+
314+- (NSString*)name { return @"after array value"; }
315+
316+
317+- (BOOL)parser:(SBJson4StreamParser *)parser shouldAcceptToken:(sbjson4_token_t)token {
318+ return token == sbjson4_token_array_close || token == sbjson4_token_value_sep;
319+}
320+
321+- (void)parser:(SBJson4StreamParser *)parser shouldTransitionTo:(sbjson4_token_t)tok {
322+ if (tok == sbjson4_token_value_sep)
323+ parser.state = [SBJson4StreamParserStateArrayNeedValue sharedInstance];
324+}
325+
326+@end
327+
328+#pragma mark -
329+
330+@implementation SBJson4StreamParserStateArrayNeedValue
331+
332+SINGLETON
333+
334+- (NSString*)name { return @"as array value"; }
335+
336+
337+- (BOOL)parser:(SBJson4StreamParser *)parser shouldAcceptToken:(sbjson4_token_t)token {
338+ switch (token) {
339+ case sbjson4_token_array_close:
340+ case sbjson4_token_entry_sep:
341+ case sbjson4_token_object_close:
342+ case sbjson4_token_value_sep:
343+ return NO;
344+
345+ default:
346+ return YES;
347+ }
348+}
349+
350+- (void)parser:(SBJson4StreamParser *)parser shouldTransitionTo:(sbjson4_token_t)tok {
351+ parser.state = [SBJson4StreamParserStateArrayGotValue sharedInstance];
352+}
353+
354+@end
355+
parsers/test_SBJSON/SBJson4StreamTokeniser.hnew file+40
@@ -0,0 +1,40 @@
1+//
2+// Created by SuperPappi on 09/01/2013.
3+//
4+// To change the template use AppCode | Preferences | File Templates.
5+//
6+
7+#import <Foundation/Foundation.h>
8+
9+typedef enum {
10+ sbjson4_token_error = -1,
11+ sbjson4_token_eof,
12+
13+ sbjson4_token_array_open,
14+ sbjson4_token_array_close,
15+ sbjson4_token_value_sep,
16+
17+ sbjson4_token_object_open,
18+ sbjson4_token_object_close,
19+ sbjson4_token_entry_sep,
20+
21+ sbjson4_token_bool,
22+ sbjson4_token_null,
23+
24+ sbjson4_token_integer,
25+ sbjson4_token_real,
26+
27+ sbjson4_token_string,
28+ sbjson4_token_encoded,
29+} sbjson4_token_t;
30+
31+
32+@interface SBJson4StreamTokeniser : NSObject
33+
34+@property (nonatomic, readonly, copy) NSString *error;
35+
36+- (void)appendData:(NSData*)data_;
37+- (sbjson4_token_t)getToken:(char**)tok length:(NSUInteger*)len;
38+
39+@end
40+
parsers/test_SBJSON/SBJson4StreamTokeniser.mnew file+395
@@ -0,0 +1,395 @@
1+//
2+// Created by SuperPappi on 09/01/2013.
3+//
4+// To change the template use AppCode | Preferences | File Templates.
5+//
6+
7+
8+#import "SBJson4StreamTokeniser.h"
9+
10+#define SBStringIsIllegalSurrogateHighCharacter(character) (((character) >= 0xD800UL) && ((character) <= 0xDFFFUL))
11+#define SBStringIsSurrogateLowCharacter(character) ((character >= 0xDC00UL) && (character <= 0xDFFFUL))
12+#define SBStringIsSurrogateHighCharacter(character) ((character >= 0xD800UL) && (character <= 0xDBFFUL))
13+
14+@implementation SBJson4StreamTokeniser {
15+ NSMutableData *data;
16+ const char *bytes;
17+ NSUInteger index;
18+ NSUInteger offset;
19+}
20+
21+- (void)setError:(NSString *)error {
22+ _error = [NSString stringWithFormat:@"%@ at index %lu", error, (unsigned long)(offset + index)];
23+}
24+
25+- (void)appendData:(NSData *)data_ {
26+ if (!data) {
27+ data = [data_ mutableCopy];
28+
29+ } else if (index) {
30+ // Discard data we've already parsed
31+ [data replaceBytesInRange:NSMakeRange(0, index) withBytes:"" length:0];
32+ [data appendData:data_];
33+
34+ // Add to the offset for reporting
35+ offset += index;
36+
37+ // Reset index to point to current position
38+ index = 0u;
39+
40+ }
41+ else {
42+ [data appendData:data_];
43+ }
44+
45+ bytes = [data bytes];
46+}
47+
48+- (void)skipWhitespace {
49+ while (index < data.length) {
50+ switch (bytes[index]) {
51+ case ' ':
52+ case '\t':
53+ case '\r':
54+ case '\n':
55+ index++;
56+ break;
57+ default:
58+ return;
59+ }
60+ }
61+}
62+
63+- (BOOL)getUnichar:(unichar *)ch {
64+ if ([self haveRemainingCharacters:1]) {
65+ *ch = (unichar) bytes[index];
66+ return YES;
67+ }
68+ return NO;
69+}
70+
71+- (BOOL)haveOneMoreCharacter {
72+ return [self haveRemainingCharacters:1];
73+}
74+
75+- (BOOL)haveRemainingCharacters:(NSUInteger)length {
76+ return data.length - index >= length;
77+}
78+
79+- (sbjson4_token_t)match:(char *)str retval:(sbjson4_token_t)tok token:(char **)token length:(NSUInteger *)length {
80+ NSUInteger len = strlen(str);
81+ if ([self haveRemainingCharacters:len]) {
82+ if (!memcmp(bytes + index, str, len)) {
83+ *token = str;
84+ *length = len;
85+ index += len;
86+ return tok;
87+ }
88+ [self setError: [NSString stringWithFormat:@"Expected '%s' after initial '%.1s'", str, str]];
89+ return sbjson4_token_error;
90+ }
91+
92+ return sbjson4_token_eof;
93+}
94+
95+- (BOOL)decodeHexQuad:(unichar*)quad {
96+ unichar tmp = 0;
97+
98+ for (int i = 0; i < 4; i++, index++) {
99+ unichar c = (unichar)bytes[index];
100+ tmp *= 16;
101+ switch (c) {
102+ case '0' ... '9':
103+ tmp += c - '0';
104+ break;
105+
106+ case 'a' ... 'f':
107+ tmp += 10 + c - 'a';
108+ break;
109+
110+ case 'A' ... 'F':
111+ tmp += 10 + c - 'A';
112+ break;
113+
114+ default:
115+ return NO;
116+ }
117+ }
118+ *quad = tmp;
119+ return YES;
120+}
121+
122+- (sbjson4_token_t)getStringToken:(char **)token length:(NSUInteger *)length {
123+
124+ // Skip initial "
125+ index++;
126+
127+ NSUInteger string_start = index;
128+ sbjson4_token_t tok = sbjson4_token_string;
129+
130+ for (;;) {
131+ if (![self haveOneMoreCharacter])
132+ return sbjson4_token_eof;
133+
134+ switch (bytes[index]) {
135+ case 0 ... 0x1F:
136+ [self setError:[NSString stringWithFormat:@"Unescaped control character [0x%0.2X] in string", bytes[index]]];
137+ return sbjson4_token_error;
138+
139+ case '"':
140+ *token = (char *)(bytes + string_start);
141+ *length = index - string_start;
142+ index++;
143+ return tok;
144+
145+ case '\\':
146+ tok = sbjson4_token_encoded;
147+ index++;
148+ if (![self haveOneMoreCharacter])
149+ return sbjson4_token_eof;
150+
151+ if (bytes[index] == 'u') {
152+ index++;
153+ if (![self haveRemainingCharacters:4])
154+ return sbjson4_token_eof;
155+
156+ unichar hi;
157+ if (![self decodeHexQuad:&hi]) {
158+ [self setError:@"Invalid hex quad"];
159+ return sbjson4_token_error;
160+ }
161+
162+ if (SBStringIsSurrogateHighCharacter(hi)) {
163+ if (![self haveRemainingCharacters:6])
164+ return sbjson4_token_eof;
165+
166+ unichar lo;
167+ if (bytes[index++] != '\\' || bytes[index++] != 'u' || ![self decodeHexQuad:&lo]) {
168+ [self setError:@"Missing low character in surrogate pair"];
169+ return sbjson4_token_error;
170+ }
171+
172+ if (!SBStringIsSurrogateLowCharacter(lo)) {
173+ [self setError:@"Invalid low character in surrogate pair"];
174+ return sbjson4_token_error;
175+ }
176+
177+ } else if (SBStringIsIllegalSurrogateHighCharacter(hi)) {
178+ [self setError:@"Invalid high character in surrogate pair"];
179+ return sbjson4_token_error;
180+
181+ }
182+
183+
184+ } else {
185+ switch (bytes[index]) {
186+ case '\\':
187+ case '/':
188+ case '"':
189+ case 'b':
190+ case 'n':
191+ case 'r':
192+ case 't':
193+ case 'f':
194+ index++;
195+ break;
196+
197+ default:
198+ [self setError:[NSString stringWithFormat:@"Illegal escape character [%x]", bytes[index]]];
199+ return sbjson4_token_error;
200+ }
201+ }
202+
203+ break;
204+
205+ default:
206+ index++;
207+ break;
208+ }
209+ }
210+}
211+
212+- (sbjson4_token_t)getNumberToken:(char **)token length:(NSUInteger *)length {
213+ NSUInteger num_start = index;
214+ if (bytes[index] == '-') {
215+ index++;
216+
217+ if (![self haveOneMoreCharacter])
218+ return sbjson4_token_eof;
219+ }
220+
221+ sbjson4_token_t tok = sbjson4_token_integer;
222+ if (bytes[index] == '0') {
223+ index++;
224+
225+ if (![self haveOneMoreCharacter])
226+ return sbjson4_token_eof;
227+
228+ if (isdigit(bytes[index])) {
229+ [self setError:@"Leading zero is illegal in number"];
230+ return sbjson4_token_error;
231+ }
232+ }
233+
234+ while (isdigit(bytes[index])) {
235+ index++;
236+ if (![self haveOneMoreCharacter])
237+ return sbjson4_token_eof;
238+ }
239+
240+ if (![self haveOneMoreCharacter])
241+ return sbjson4_token_eof;
242+
243+
244+ if (bytes[index] == '.') {
245+ index++;
246+ tok = sbjson4_token_real;
247+
248+ if (![self haveOneMoreCharacter])
249+ return sbjson4_token_eof;
250+
251+ NSUInteger fraction_start = index;
252+ while (isdigit(bytes[index])) {
253+ index++;
254+ if (![self haveOneMoreCharacter])
255+ return sbjson4_token_eof;
256+ }
257+
258+ if (fraction_start == index) {
259+ [self setError:@"No digits after decimal point"];
260+ return sbjson4_token_error;
261+ }
262+ }
263+
264+ if (bytes[index] == 'e' || bytes[index] == 'E') {
265+ index++;
266+ tok = sbjson4_token_real;
267+
268+ if (![self haveOneMoreCharacter])
269+ return sbjson4_token_eof;
270+
271+ if (bytes[index] == '-' || bytes[index] == '+') {
272+ index++;
273+ if (![self haveOneMoreCharacter])
274+ return sbjson4_token_eof;
275+ }
276+
277+ NSUInteger exp_start = index;
278+ while (isdigit(bytes[index])) {
279+ index++;
280+ if (![self haveOneMoreCharacter])
281+ return sbjson4_token_eof;
282+ }
283+
284+ if (exp_start == index) {
285+ [self setError:@"No digits in exponent"];
286+ return sbjson4_token_error;
287+ }
288+
289+ }
290+
291+ if (num_start + 1 == index && bytes[num_start] == '-') {
292+ [self setError:@"No digits after initial minus"];
293+ return sbjson4_token_error;
294+ }
295+
296+ *token = (char *)(bytes + num_start);
297+ *length = index - num_start;
298+ return tok;
299+}
300+
301+
302+- (sbjson4_token_t)getToken:(char **)token length:(NSUInteger *)length {
303+ [self skipWhitespace];
304+ NSUInteger copyOfIndex = index;
305+
306+ unichar ch;
307+ if (![self getUnichar:&ch])
308+ return sbjson4_token_eof;
309+
310+ sbjson4_token_t tok;
311+ switch (ch) {
312+ case '{': {
313+ index++;
314+ tok = sbjson4_token_object_open;
315+ break;
316+ }
317+ case '}': {
318+ index++;
319+ tok = sbjson4_token_object_close;
320+ break;
321+
322+ }
323+ case '[': {
324+ index++;
325+ tok = sbjson4_token_array_open;
326+ break;
327+
328+ }
329+ case ']': {
330+ index++;
331+ tok = sbjson4_token_array_close;
332+ break;
333+
334+ }
335+ case 't': {
336+ tok = [self match:"true" retval:sbjson4_token_bool token:token length:length];
337+ break;
338+
339+ }
340+ case 'f': {
341+ tok = [self match:"false" retval:sbjson4_token_bool token:token length:length];
342+ break;
343+
344+ }
345+ case 'n': {
346+ tok = [self match:"null" retval:sbjson4_token_null token:token length:length];
347+ break;
348+
349+ }
350+ case ',': {
351+ index++;
352+ tok = sbjson4_token_value_sep;
353+ break;
354+
355+ }
356+ case ':': {
357+ index++;
358+ tok = sbjson4_token_entry_sep;
359+ break;
360+
361+ }
362+ case '"': {
363+ tok = [self getStringToken:token length:length];
364+ break;
365+
366+ }
367+ case '-':
368+ case '0' ... '9': {
369+ tok = [self getNumberToken:token length:length];
370+ break;
371+
372+ }
373+ case '+': {
374+ self.error = @"Leading + is illegal in number";
375+ tok = sbjson4_token_error;
376+ break;
377+
378+ }
379+ default: {
380+ self.error = [NSString stringWithFormat:@"Illegal start of token [%c]", ch];
381+ tok = sbjson4_token_error;
382+ break;
383+ }
384+ }
385+
386+ if (tok == sbjson4_token_eof) {
387+ // We ran out of bytes before we could finish parsing the current token.
388+ // Back up to the start & wait for more data.
389+ index = copyOfIndex;
390+ }
391+
392+ return tok;
393+}
394+
395+@end
parsers/test_SBJSON/SBJson4StreamWriter.hnew file+210
@@ -0,0 +1,210 @@
1+/*
2+ Copyright (c) 2010, Stig Brautaset.
3+ All rights reserved.
4+
5+ Redistribution and use in source and binary forms, with or without
6+ modification, are permitted provided that the following conditions are
7+ met:
8+
9+ Redistributions of source code must retain the above copyright
10+ notice, this list of conditions and the following disclaimer.
11+
12+ Redistributions in binary form must reproduce the above copyright
13+ notice, this list of conditions and the following disclaimer in the
14+ documentation and/or other materials provided with the distribution.
15+
16+ Neither the name of the the author nor the names of its contributors
17+ may be used to endorse or promote products derived from this software
18+ without specific prior written permission.
19+
20+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
21+ IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22+ TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23+ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31+ */
32+
33+#import <Foundation/Foundation.h>
34+
35+/// Enable JSON writing for non-native objects
36+@interface NSObject (SBProxyForJson)
37+
38+/**
39+ Allows generation of JSON for otherwise unsupported classes.
40+
41+ If you have a custom class that you want to create a JSON representation
42+ for you can implement this method in your class. It should return a
43+ representation of your object defined in terms of objects that can be
44+ translated into JSON. For example, a Person object might implement it like this:
45+
46+ - (id)proxyForJson {
47+ return [NSDictionary dictionaryWithObjectsAndKeys:
48+ name, @"name",
49+ phone, @"phone",
50+ email, @"email",
51+ nil];
52+ }
53+
54+ */
55+- (id)proxyForJson;
56+
57+@end
58+
59+@class SBJson4StreamWriter;
60+
61+@protocol SBJson4StreamWriterDelegate
62+
63+- (void)writer:(SBJson4StreamWriter *)writer appendBytes:(const void *)bytes length:(NSUInteger)length;
64+
65+@end
66+
67+@class SBJson4StreamWriterState;
68+
69+/**
70+ The Stream Writer class.
71+
72+ Accepts a stream of messages and writes JSON of these to its delegate object.
73+
74+ This class provides a range of high-, mid- and low-level methods. You can mix
75+ and match calls to these. For example, you may want to call -writeArrayOpen
76+ to start an array and then repeatedly call -writeObject: with various objects
77+ before finishing off with a -writeArrayClose call.
78+
79+ Objective-C types are mapped to JSON types in the following way:
80+
81+ - NSNull -> null
82+ - NSString -> string
83+ - NSArray -> array
84+ - NSDictionary -> object
85+ - NSNumber's -initWithBool:YES -> true
86+ - NSNumber's -initWithBool:NO -> false
87+ - NSNumber -> number
88+
89+ NSNumber instances created with the -numberWithBool: method are
90+ converted into the JSON boolean "true" and "false" values, and vice
91+ versa. Any other NSNumber instances are converted to a JSON number the
92+ way you would expect.
93+
94+ @warning: In JSON the keys of an object must be strings. NSDictionary
95+ keys need not be, but attempting to convert an NSDictionary with
96+ non-string keys into JSON will throw an exception.*
97+
98+ */
99+
100+@interface SBJson4StreamWriter : NSObject {
101+ NSMutableDictionary *cache;
102+}
103+
104+@property (nonatomic, weak) SBJson4StreamWriterState *state; // Internal
105+@property (nonatomic, readonly, strong) NSMutableArray *stateStack; // Internal
106+
107+/**
108+ delegate to receive JSON output
109+ Delegate that will receive messages with output.
110+ */
111+@property (nonatomic, weak) id<SBJson4StreamWriterDelegate> delegate;
112+
113+/**
114+ The maximum depth.
115+
116+ Defaults to 512. If the input is nested deeper than this the input will be deemed to be
117+ malicious and the parser returns nil, signalling an error. ("Nested too deep".) You can
118+ turn off this security feature by setting the maxDepth value to 0.
119+ */
120+@property(nonatomic) NSUInteger maxDepth;
121+
122+/**
123+ Whether we are generating human-readable (multi line) JSON.
124+
125+ Set whether or not to generate human-readable JSON. The default is NO, which produces
126+ JSON without any whitespace between tokens. If set to YES, generates human-readable
127+ JSON with line breaks after each array value and dictionary key/value pair, indented two
128+ spaces per nesting level.
129+ */
130+@property(nonatomic) BOOL humanReadable;
131+
132+/**
133+ Whether or not to sort the dictionary keys in the output.
134+
135+ If this is set to YES, the dictionary keys in the JSON output will be in sorted order.
136+ (This is useful if you need to compare two structures, for example.) The default is NO.
137+ */
138+@property(nonatomic) BOOL sortKeys;
139+
140+/**
141+ An optional comparator to be used if sortKeys is YES.
142+
143+ If this is nil, sorting will be done via @selector(compare:).
144+ */
145+@property (nonatomic, copy) NSComparator sortKeysComparator;
146+
147+/// Contains the error description after an error has occurred.
148+@property (nonatomic, copy) NSString *error;
149+
150+/**
151+ Write an NSDictionary to the JSON stream.
152+ @return YES if successful, or NO on failure
153+ */
154+- (BOOL)writeObject:(NSDictionary*)dict;
155+
156+/**
157+ Write an NSArray to the JSON stream.
158+ @return YES if successful, or NO on failure
159+ */
160+- (BOOL)writeArray:(NSArray *)array;
161+
162+/**
163+ Start writing an Object to the stream
164+ @return YES if successful, or NO on failure
165+*/
166+- (BOOL)writeObjectOpen;
167+
168+/**
169+ Close the current object being written
170+ @return YES if successful, or NO on failure
171+*/
172+- (BOOL)writeObjectClose;
173+
174+/** Start writing an Array to the stream
175+ @return YES if successful, or NO on failure
176+*/
177+- (BOOL)writeArrayOpen;
178+
179+/** Close the current Array being written
180+ @return YES if successful, or NO on failure
181+*/
182+- (BOOL)writeArrayClose;
183+
184+/** Write a null to the stream
185+ @return YES if successful, or NO on failure
186+*/
187+- (BOOL)writeNull;
188+
189+/** Write a boolean to the stream
190+ @return YES if successful, or NO on failure
191+*/
192+- (BOOL)writeBool:(BOOL)x;
193+
194+/** Write a Number to the stream
195+ @return YES if successful, or NO on failure
196+*/
197+- (BOOL)writeNumber:(NSNumber*)n;
198+
199+/** Write a String to the stream
200+ @return YES if successful, or NO on failure
201+*/
202+- (BOOL)writeString:(NSString*)s;
203+
204+@end
205+
206+@interface SBJson4StreamWriter (Private)
207+- (BOOL)writeValue:(id)v;
208+- (void)appendBytes:(const void *)bytes length:(NSUInteger)length;
209+@end
210+
parsers/test_SBJSON/SBJson4StreamWriter.mnew file+358
@@ -0,0 +1,358 @@
1+/*
2+ Copyright (c) 2010, Stig Brautaset.
3+ All rights reserved.
4+
5+ Redistribution and use in source and binary forms, with or without
6+ modification, are permitted provided that the following conditions are
7+ met:
8+
9+ Redistributions of source code must retain the above copyright
10+ notice, this list of conditions and the following disclaimer.
11+
12+ Redistributions in binary form must reproduce the above copyright
13+ notice, this list of conditions and the following disclaimer in the
14+ documentation and/or other materials provided with the distribution.
15+
16+ Neither the name of the the author nor the names of its contributors
17+ may be used to endorse or promote products derived from this software
18+ without specific prior written permission.
19+
20+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
21+ IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22+ TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23+ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31+ */
32+
33+#if !__has_feature(objc_arc)
34+#error "This source file must be compiled with ARC enabled!"
35+#endif
36+
37+#import "SBJson4StreamWriter.h"
38+#import "SBJson4StreamWriterState.h"
39+
40+static NSNumber *kTrue;
41+static NSNumber *kFalse;
42+static NSNumber *kPositiveInfinity;
43+static NSNumber *kNegativeInfinity;
44+
45+
46+@implementation SBJson4StreamWriter
47+
48++ (void)initialize {
49+ kPositiveInfinity = [NSNumber numberWithDouble:+HUGE_VAL];
50+ kNegativeInfinity = [NSNumber numberWithDouble:-HUGE_VAL];
51+ kTrue = [NSNumber numberWithBool:YES];
52+ kFalse = [NSNumber numberWithBool:NO];
53+}
54+
55+#pragma mark Housekeeping
56+
57+- (id)init {
58+ self = [super init];
59+ if (self) {
60+ _maxDepth = 32u;
61+ _stateStack = [[NSMutableArray alloc] initWithCapacity:_maxDepth];
62+ _state = [SBJson4StreamWriterStateStart sharedInstance];
63+ cache = [[NSMutableDictionary alloc] initWithCapacity:32];
64+ }
65+ return self;
66+}
67+
68+#pragma mark Methods
69+
70+- (void)appendBytes:(const void *)bytes length:(NSUInteger)length {
71+ [_delegate writer:self appendBytes:bytes length:length];
72+}
73+
74+- (BOOL)writeObject:(NSDictionary *)dict {
75+ if (![self writeObjectOpen])
76+ return NO;
77+
78+ NSArray *keys = [dict allKeys];
79+
80+ if (_sortKeys) {
81+ if (_sortKeysComparator) {
82+ keys = [keys sortedArrayWithOptions:NSSortStable usingComparator:_sortKeysComparator];
83+ }
84+ else{
85+ keys = [keys sortedArrayUsingSelector:@selector(compare:)];
86+ }
87+ }
88+
89+ for (id k in keys) {
90+ if (![k isKindOfClass:[NSString class]]) {
91+ self.error = [NSString stringWithFormat:@"JSON object key must be string: %@", k];
92+ return NO;
93+ }
94+
95+ if (![self writeString:k])
96+ return NO;
97+ if (![self writeValue:[dict objectForKey:k]])
98+ return NO;
99+ }
100+
101+ return [self writeObjectClose];
102+}
103+
104+- (BOOL)writeArray:(NSArray*)array {
105+ if (![self writeArrayOpen])
106+ return NO;
107+ for (id v in array)
108+ if (![self writeValue:v])
109+ return NO;
110+ return [self writeArrayClose];
111+}
112+
113+
114+- (BOOL)writeObjectOpen {
115+ if ([_state isInvalidState:self]) return NO;
116+ if ([_state expectingKey:self]) return NO;
117+ [_state appendSeparator:self];
118+ if (_humanReadable && _stateStack.count) [_state appendWhitespace:self];
119+
120+ [_stateStack addObject:_state];
121+ self.state = [SBJson4StreamWriterStateObjectStart sharedInstance];
122+
123+ if (_maxDepth && _stateStack.count > _maxDepth) {
124+ self.error = @"Nested too deep";
125+ return NO;
126+ }
127+
128+ [_delegate writer:self appendBytes:"{" length:1];
129+ return YES;
130+}
131+
132+- (BOOL)writeObjectClose {
133+ if ([_state isInvalidState:self]) return NO;
134+
135+ SBJson4StreamWriterState *prev = _state;
136+
137+ self.state = [_stateStack lastObject];
138+ [_stateStack removeLastObject];
139+
140+ if (_humanReadable) [prev appendWhitespace:self];
141+ [_delegate writer:self appendBytes:"}" length:1];
142+
143+ [_state transitionState:self];
144+ return YES;
145+}
146+
147+- (BOOL)writeArrayOpen {
148+ if ([_state isInvalidState:self]) return NO;
149+ if ([_state expectingKey:self]) return NO;
150+ [_state appendSeparator:self];
151+ if (_humanReadable && _stateStack.count) [_state appendWhitespace:self];
152+
153+ [_stateStack addObject:_state];
154+ self.state = [SBJson4StreamWriterStateArrayStart sharedInstance];
155+
156+ if (_maxDepth && _stateStack.count > _maxDepth) {
157+ self.error = @"Nested too deep";
158+ return NO;
159+ }
160+
161+ [_delegate writer:self appendBytes:"[" length:1];
162+ return YES;
163+}
164+
165+- (BOOL)writeArrayClose {
166+ if ([_state isInvalidState:self]) return NO;
167+ if ([_state expectingKey:self]) return NO;
168+
169+ SBJson4StreamWriterState *prev = _state;
170+
171+ self.state = [_stateStack lastObject];
172+ [_stateStack removeLastObject];
173+
174+ if (_humanReadable) [prev appendWhitespace:self];
175+ [_delegate writer:self appendBytes:"]" length:1];
176+
177+ [_state transitionState:self];
178+ return YES;
179+}
180+
181+- (BOOL)writeNull {
182+ if ([_state isInvalidState:self]) return NO;
183+ if ([_state expectingKey:self]) return NO;
184+ [_state appendSeparator:self];
185+ if (_humanReadable) [_state appendWhitespace:self];
186+
187+ [_delegate writer:self appendBytes:"null" length:4];
188+ [_state transitionState:self];
189+ return YES;
190+}
191+
192+- (BOOL)writeBool:(BOOL)x {
193+ if ([_state isInvalidState:self]) return NO;
194+ if ([_state expectingKey:self]) return NO;
195+ [_state appendSeparator:self];
196+ if (_humanReadable) [_state appendWhitespace:self];
197+
198+ if (x)
199+ [_delegate writer:self appendBytes:"true" length:4];
200+ else
201+ [_delegate writer:self appendBytes:"false" length:5];
202+ [_state transitionState:self];
203+ return YES;
204+}
205+
206+
207+- (BOOL)writeValue:(id)o {
208+ if ([o isKindOfClass:[NSDictionary class]]) {
209+ return [self writeObject:o];
210+
211+ } else if ([o isKindOfClass:[NSArray class]]) {
212+ return [self writeArray:o];
213+
214+ } else if ([o isKindOfClass:[NSString class]]) {
215+ [self writeString:o];
216+ return YES;
217+
218+ } else if ([o isKindOfClass:[NSNumber class]]) {
219+ return [self writeNumber:o];
220+
221+ } else if ([o isKindOfClass:[NSNull class]]) {
222+ return [self writeNull];
223+
224+ } else if ([o respondsToSelector:@selector(proxyForJson)]) {
225+ return [self writeValue:[o proxyForJson]];
226+
227+ }
228+
229+ self.error = [NSString stringWithFormat:@"JSON serialisation not supported for %@", [o class]];
230+ return NO;
231+}
232+
233+static const char *strForChar(int c) {
234+ switch (c) {
235+ case 0: return "\\u0000";
236+ case 1: return "\\u0001";
237+ case 2: return "\\u0002";
238+ case 3: return "\\u0003";
239+ case 4: return "\\u0004";
240+ case 5: return "\\u0005";
241+ case 6: return "\\u0006";
242+ case 7: return "\\u0007";
243+ case 8: return "\\b";
244+ case 9: return "\\t";
245+ case 10: return "\\n";
246+ case 11: return "\\u000b";
247+ case 12: return "\\f";
248+ case 13: return "\\r";
249+ case 14: return "\\u000e";
250+ case 15: return "\\u000f";
251+ case 16: return "\\u0010";
252+ case 17: return "\\u0011";
253+ case 18: return "\\u0012";
254+ case 19: return "\\u0013";
255+ case 20: return "\\u0014";
256+ case 21: return "\\u0015";
257+ case 22: return "\\u0016";
258+ case 23: return "\\u0017";
259+ case 24: return "\\u0018";
260+ case 25: return "\\u0019";
261+ case 26: return "\\u001a";
262+ case 27: return "\\u001b";
263+ case 28: return "\\u001c";
264+ case 29: return "\\u001d";
265+ case 30: return "\\u001e";
266+ case 31: return "\\u001f";
267+ case 34: return "\\\"";
268+ case 92: return "\\\\";
269+ default:
270+ [NSException raise:@"Illegal escape char" format:@"-->%c<-- is not a legal escape character", c];
271+ return NULL;
272+ }
273+}
274+
275+- (BOOL)writeString:(NSString*)string {
276+ if ([_state isInvalidState:self]) return NO;
277+ [_state appendSeparator:self];
278+ if (_humanReadable) [_state appendWhitespace:self];
279+
280+ NSMutableData *buf = [cache objectForKey:string];
281+ if (!buf) {
282+
283+ NSUInteger len = [string lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
284+ const char *utf8 = [string UTF8String];
285+ NSUInteger written = 0, i = 0;
286+
287+ buf = [NSMutableData dataWithCapacity:(NSUInteger)(len * 1.1f)];
288+ [buf appendBytes:"\"" length:1];
289+
290+ for (i = 0; i < len; i++) {
291+ int c = utf8[i];
292+ BOOL isControlChar = c >= 0 && c < 32;
293+ if (isControlChar || c == '"' || c == '\\') {
294+ if (i - written)
295+ [buf appendBytes:utf8 + written length:i - written];
296+ written = i + 1;
297+
298+ const char *t = strForChar(c);
299+ [buf appendBytes:t length:strlen(t)];
300+ }
301+ }
302+
303+ if (i - written)
304+ [buf appendBytes:utf8 + written length:i - written];
305+
306+ [buf appendBytes:"\"" length:1];
307+ [cache setObject:buf forKey:string];
308+ }
309+
310+ [_delegate writer:self appendBytes:[buf bytes] length:[buf length]];
311+ [_state transitionState:self];
312+ return YES;
313+}
314+
315+- (BOOL)writeNumber:(NSNumber*)number {
316+ if (number == kTrue || number == kFalse)
317+ return [self writeBool:[number boolValue]];
318+
319+ if ([_state isInvalidState:self]) return NO;
320+ if ([_state expectingKey:self]) return NO;
321+ [_state appendSeparator:self];
322+ if (_humanReadable) [_state appendWhitespace:self];
323+
324+ if ([kPositiveInfinity isEqualToNumber:number]) {
325+ self.error = @"+Infinity is not a valid number in JSON";
326+ return NO;
327+
328+ } else if ([kNegativeInfinity isEqualToNumber:number]) {
329+ self.error = @"-Infinity is not a valid number in JSON";
330+ return NO;
331+
332+ } else if (isnan([number doubleValue])) {
333+ self.error = @"NaN is not a valid number in JSON";
334+ return NO;
335+ }
336+
337+ const char *objcType = [number objCType];
338+ char num[128];
339+ size_t len;
340+
341+ switch (objcType[0]) {
342+ case 'c': case 'i': case 's': case 'l': case 'q':
343+ len = snprintf(num, sizeof num, "%lld", [number longLongValue]);
344+ break;
345+ case 'C': case 'I': case 'S': case 'L': case 'Q':
346+ len = snprintf(num, sizeof num, "%llu", [number unsignedLongLongValue]);
347+ break;
348+ case 'f': case 'd': default: {
349+ len = snprintf(num, sizeof num, "%.17g", [number doubleValue]);
350+ break;
351+ }
352+ }
353+ [_delegate writer:self appendBytes:num length: len];
354+ [_state transitionState:self];
355+ return YES;
356+}
357+
358+@end
parsers/test_SBJSON/SBJson4StreamWriterState.hnew file+69
@@ -0,0 +1,69 @@
1+/*
2+ Copyright (c) 2010, Stig Brautaset.
3+ All rights reserved.
4+
5+ Redistribution and use in source and binary forms, with or without
6+ modification, are permitted provided that the following conditions are
7+ met:
8+
9+ Redistributions of source code must retain the above copyright
10+ notice, this list of conditions and the following disclaimer.
11+
12+ Redistributions in binary form must reproduce the above copyright
13+ notice, this list of conditions and the following disclaimer in the
14+ documentation and/or other materials provided with the distribution.
15+
16+ Neither the name of the the author nor the names of its contributors
17+ may be used to endorse or promote products derived from this software
18+ without specific prior written permission.
19+
20+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
21+ IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22+ TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23+ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31+ */
32+
33+#import <Foundation/Foundation.h>
34+
35+@class SBJson4StreamWriter;
36+
37+@interface SBJson4StreamWriterState : NSObject
38++ (id)sharedInstance;
39+- (BOOL)isInvalidState:(SBJson4StreamWriter *)writer;
40+- (void)appendSeparator:(SBJson4StreamWriter *)writer;
41+- (BOOL)expectingKey:(SBJson4StreamWriter *)writer;
42+- (void)transitionState:(SBJson4StreamWriter *)writer;
43+- (void)appendWhitespace:(SBJson4StreamWriter *)writer;
44+@end
45+
46+@interface SBJson4StreamWriterStateObjectStart : SBJson4StreamWriterState
47+@end
48+
49+@interface SBJson4StreamWriterStateObjectKey : SBJson4StreamWriterStateObjectStart
50+@end
51+
52+@interface SBJson4StreamWriterStateObjectValue : SBJson4StreamWriterState
53+@end
54+
55+@interface SBJson4StreamWriterStateArrayStart : SBJson4StreamWriterState
56+@end
57+
58+@interface SBJson4StreamWriterStateArrayValue : SBJson4StreamWriterState
59+@end
60+
61+@interface SBJson4StreamWriterStateStart : SBJson4StreamWriterState
62+@end
63+
64+@interface SBJson4StreamWriterStateComplete : SBJson4StreamWriterState
65+@end
66+
67+@interface SBJson4StreamWriterStateError : SBJson4StreamWriterState
68+@end
69+
parsers/test_SBJSON/SBJson4StreamWriterState.mnew file+147
@@ -0,0 +1,147 @@
1+/*
2+ Copyright (c) 2010, Stig Brautaset.
3+ All rights reserved.
4+
5+ Redistribution and use in source and binary forms, with or without
6+ modification, are permitted provided that the following conditions are
7+ met:
8+
9+ Redistributions of source code must retain the above copyright
10+ notice, this list of conditions and the following disclaimer.
11+
12+ Redistributions in binary form must reproduce the above copyright
13+ notice, this list of conditions and the following disclaimer in the
14+ documentation and/or other materials provided with the distribution.
15+
16+ Neither the name of the the author nor the names of its contributors
17+ may be used to endorse or promote products derived from this software
18+ without specific prior written permission.
19+
20+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
21+ IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22+ TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23+ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31+ */
32+
33+#if !__has_feature(objc_arc)
34+#error "This source file must be compiled with ARC enabled!"
35+#endif
36+
37+#import "SBJson4StreamWriterState.h"
38+#import "SBJson4StreamWriter.h"
39+
40+#define SINGLETON \
41++ (id)sharedInstance { \
42+ static id state = nil; \
43+ if (!state) { \
44+ @synchronized(self) { \
45+ if (!state) state = [[self alloc] init]; \
46+ } \
47+ } \
48+ return state; \
49+}
50+
51+
52+@implementation SBJson4StreamWriterState
53++ (id)sharedInstance { return nil; }
54+- (BOOL)isInvalidState:(SBJson4StreamWriter *)writer { return NO; }
55+- (void)appendSeparator:(SBJson4StreamWriter *)writer {}
56+- (BOOL)expectingKey:(SBJson4StreamWriter *)writer { return NO; }
57+- (void)transitionState:(SBJson4StreamWriter *)writer {}
58+- (void)appendWhitespace:(SBJson4StreamWriter *)writer {
59+ [writer appendBytes:"\n" length:1];
60+ for (NSUInteger i = 0; i < writer.stateStack.count; i++)
61+ [writer appendBytes:" " length:2];
62+}
63+@end
64+
65+@implementation SBJson4StreamWriterStateObjectStart
66+
67+SINGLETON
68+
69+- (void)transitionState:(SBJson4StreamWriter *)writer {
70+ writer.state = [SBJson4StreamWriterStateObjectValue sharedInstance];
71+}
72+- (BOOL)expectingKey:(SBJson4StreamWriter *)writer {
73+ writer.error = @"JSON object key must be string";
74+ return YES;
75+}
76+@end
77+
78+@implementation SBJson4StreamWriterStateObjectKey
79+
80+SINGLETON
81+
82+- (void)appendSeparator:(SBJson4StreamWriter *)writer {
83+ [writer appendBytes:"," length:1];
84+}
85+@end
86+
87+@implementation SBJson4StreamWriterStateObjectValue
88+
89+SINGLETON
90+
91+- (void)appendSeparator:(SBJson4StreamWriter *)writer {
92+ [writer appendBytes:":" length:1];
93+}
94+- (void)transitionState:(SBJson4StreamWriter *)writer {
95+ writer.state = [SBJson4StreamWriterStateObjectKey sharedInstance];
96+}
97+- (void)appendWhitespace:(SBJson4StreamWriter *)writer {
98+ [writer appendBytes:" " length:1];
99+}
100+@end
101+
102+@implementation SBJson4StreamWriterStateArrayStart
103+
104+SINGLETON
105+
106+- (void)transitionState:(SBJson4StreamWriter *)writer {
107+ writer.state = [SBJson4StreamWriterStateArrayValue sharedInstance];
108+}
109+@end
110+
111+@implementation SBJson4StreamWriterStateArrayValue
112+
113+SINGLETON
114+
115+- (void)appendSeparator:(SBJson4StreamWriter *)writer {
116+ [writer appendBytes:"," length:1];
117+}
118+@end
119+
120+@implementation SBJson4StreamWriterStateStart
121+
122+SINGLETON
123+
124+
125+- (void)transitionState:(SBJson4StreamWriter *)writer {
126+ writer.state = [SBJson4StreamWriterStateComplete sharedInstance];
127+}
128+- (void)appendSeparator:(SBJson4StreamWriter *)writer {
129+}
130+@end
131+
132+@implementation SBJson4StreamWriterStateComplete
133+
134+SINGLETON
135+
136+- (BOOL)isInvalidState:(SBJson4StreamWriter *)writer {
137+ writer.error = @"Stream is closed";
138+ return YES;
139+}
140+@end
141+
142+@implementation SBJson4StreamWriterStateError
143+
144+SINGLETON
145+
146+@end
147+
parsers/test_SBJSON/SBJson4Writer.hnew file+103
@@ -0,0 +1,103 @@
1+/*
2+ Copyright (C) 2009 Stig Brautaset. All rights reserved.
3+
4+ Redistribution and use in source and binary forms, with or without
5+ modification, are permitted provided that the following conditions are met:
6+
7+ * Redistributions of source code must retain the above copyright notice, this
8+ list of conditions and the following disclaimer.
9+
10+ * Redistributions in binary form must reproduce the above copyright notice,
11+ this list of conditions and the following disclaimer in the documentation
12+ and/or other materials provided with the distribution.
13+
14+ * Neither the name of the author nor the names of its contributors may be used
15+ to endorse or promote products derived from this software without specific
16+ prior written permission.
17+
18+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
22+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28+ */
29+
30+#import <Foundation/Foundation.h>
31+
32+/**
33+ The JSON writer class.
34+
35+ This uses SBJson4StreamWriter internally.
36+
37+ */
38+
39+@interface SBJson4Writer : NSObject
40+
41+/**
42+ The maximum depth.
43+
44+ Defaults to 32. If the input is nested deeper than this the input will be deemed to be
45+ malicious and the parser returns nil, signalling an error. ("Nested too deep".) You can
46+ turn off this security feature by setting the maxDepth value to 0.
47+ */
48+@property(nonatomic) NSUInteger maxDepth;
49+
50+/**
51+ Return an error trace, or nil if there was no errors.
52+
53+ Note that this method returns the trace of the last method that failed.
54+ You need to check the return value of the call you're making to figure out
55+ if the call actually failed, before you know call this method.
56+ */
57+@property (nonatomic, readonly, copy) NSString *error;
58+
59+/**
60+ Whether we are generating human-readable (multi line) JSON.
61+
62+ Set whether or not to generate human-readable JSON. The default is NO, which produces
63+ JSON without any whitespace. (Except inside strings.) If set to YES, generates human-readable
64+ JSON with line breaks after each array value and dictionary key/value pair, indented two
65+ spaces per nesting level.
66+ */
67+@property(nonatomic) BOOL humanReadable;
68+
69+/**
70+ Whether or not to sort the dictionary keys in the output.
71+
72+ If this is set to YES, the dictionary keys in the JSON output will be in sorted order.
73+ (This is useful if you need to compare two structures, for example.) The default is NO.
74+ */
75+@property(nonatomic) BOOL sortKeys;
76+
77+/**
78+ An optional comparator to be used if sortKeys is YES.
79+
80+ If this is nil, sorting will be done via @selector(compare:).
81+ */
82+@property (nonatomic, copy) NSComparator sortKeysComparator;
83+
84+/**
85+ Generates string with JSON representation for the given object.
86+
87+ Returns a string containing JSON representation of the passed in value, or nil on error.
88+ If nil is returned and error is not NULL, *error can be interrogated to find the cause of the error.
89+
90+ @param value any instance that can be represented as JSON text.
91+ */
92+- (NSString*)stringWithObject:(id)value;
93+
94+/**
95+ Generates JSON representation for the given object.
96+
97+ Returns an NSData object containing JSON represented as UTF8 text, or nil on error.
98+
99+ @param value any instance that can be represented as JSON text.
100+ */
101+- (NSData*)dataWithObject:(id)value;
102+
103+@end
parsers/test_SBJSON/SBJson4Writer.mnew file+102
@@ -0,0 +1,102 @@
1+/*
2+ Copyright (C) 2009 Stig Brautaset. All rights reserved.
3+
4+ Redistribution and use in source and binary forms, with or without
5+ modification, are permitted provided that the following conditions are met:
6+
7+ * Redistributions of source code must retain the above copyright notice, this
8+ list of conditions and the following disclaimer.
9+
10+ * Redistributions in binary form must reproduce the above copyright notice,
11+ this list of conditions and the following disclaimer in the documentation
12+ and/or other materials provided with the distribution.
13+
14+ * Neither the name of the author nor the names of its contributors may be used
15+ to endorse or promote products derived from this software without specific
16+ prior written permission.
17+
18+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
22+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28+ */
29+
30+#if !__has_feature(objc_arc)
31+#error "This source file must be compiled with ARC enabled!"
32+#endif
33+
34+#import "SBJson4Writer.h"
35+#import "SBJson4StreamWriter.h"
36+
37+
38+@interface SBJson4Writer () < SBJson4StreamWriterDelegate >
39+@property (nonatomic, copy) NSString *error;
40+@property (nonatomic, strong) NSMutableData *acc;
41+@end
42+
43+@implementation SBJson4Writer
44+
45+- (id)init {
46+ self = [super init];
47+ if (self) {
48+ self.maxDepth = 32u;
49+ }
50+ return self;
51+}
52+
53+
54+- (NSString*)stringWithObject:(id)value {
55+ NSData *data = [self dataWithObject:value];
56+ if (data)
57+ return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
58+ return nil;
59+}
60+
61+- (NSData*)dataWithObject:(id)object {
62+ self.error = nil;
63+
64+ self.acc = [[NSMutableData alloc] initWithCapacity:8096u];
65+
66+ SBJson4StreamWriter *streamWriter = [[SBJson4StreamWriter alloc] init];
67+ streamWriter.sortKeys = self.sortKeys;
68+ streamWriter.maxDepth = self.maxDepth;
69+ streamWriter.sortKeysComparator = self.sortKeysComparator;
70+ streamWriter.humanReadable = self.humanReadable;
71+ streamWriter.delegate = self;
72+
73+ BOOL ok = NO;
74+ if ([object isKindOfClass:[NSDictionary class]])
75+ ok = [streamWriter writeObject:object];
76+
77+ else if ([object isKindOfClass:[NSArray class]])
78+ ok = [streamWriter writeArray:object];
79+
80+ else if ([object respondsToSelector:@selector(proxyForJson)])
81+ return [self dataWithObject:[object proxyForJson]];
82+ else {
83+ self.error = @"Not valid type for JSON";
84+ return nil;
85+ }
86+
87+ if (ok)
88+ return self.acc;
89+
90+ self.error = streamWriter.error;
91+ return nil;
92+}
93+
94+#pragma mark SBJson4StreamWriterDelegate
95+
96+- (void)writer:(SBJson4StreamWriter *)writer appendBytes:(const void *)bytes length:(NSUInteger)length {
97+ [self.acc appendBytes:bytes length:length];
98+}
99+
100+
101+
102+@end
parsers/test_SBJSON/bin/test_SBJSONnew file

Binary file not shown.

parsers/test_SBJSON/test_SBJSON.xcodeproj/project.pbxprojnew file+290
@@ -0,0 +1,290 @@
1+// !$*UTF8*$!
2+{
3+ archiveVersion = 1;
4+ classes = {
5+ };
6+ objectVersion = 46;
7+ objects = {
8+
9+/* Begin PBXBuildFile section */
10+ 034CB5251D7C6B80006D4E84 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 034CB5241D7C6B80006D4E84 /* main.m */; };
11+ 034CB53A1D7C6B8F006D4E84 /* SBJson4StreamWriterState.m in Sources */ = {isa = PBXBuildFile; fileRef = 034CB52C1D7C6B8F006D4E84 /* SBJson4StreamWriterState.m */; };
12+ 034CB53B1D7C6B8F006D4E84 /* SBJson4StreamWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = 034CB5301D7C6B8F006D4E84 /* SBJson4StreamWriter.m */; };
13+ 034CB53C1D7C6B8F006D4E84 /* SBJson4StreamParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 034CB5331D7C6B8F006D4E84 /* SBJson4StreamParser.m */; };
14+ 034CB53D1D7C6B8F006D4E84 /* SBJson4Parser.m in Sources */ = {isa = PBXBuildFile; fileRef = 034CB5341D7C6B8F006D4E84 /* SBJson4Parser.m */; };
15+ 034CB53E1D7C6B8F006D4E84 /* SBJson4Writer.m in Sources */ = {isa = PBXBuildFile; fileRef = 034CB5351D7C6B8F006D4E84 /* SBJson4Writer.m */; };
16+ 034CB53F1D7C6B8F006D4E84 /* SBJson4StreamParserState.m in Sources */ = {isa = PBXBuildFile; fileRef = 034CB5371D7C6B8F006D4E84 /* SBJson4StreamParserState.m */; };
17+ 034CB5401D7C6B8F006D4E84 /* SBJson4StreamTokeniser.m in Sources */ = {isa = PBXBuildFile; fileRef = 034CB5381D7C6B8F006D4E84 /* SBJson4StreamTokeniser.m */; };
18+/* End PBXBuildFile section */
19+
20+/* Begin PBXCopyFilesBuildPhase section */
21+ 034CB51F1D7C6B80006D4E84 /* CopyFiles */ = {
22+ isa = PBXCopyFilesBuildPhase;
23+ buildActionMask = 2147483647;
24+ dstPath = /usr/share/man/man1/;
25+ dstSubfolderSpec = 0;
26+ files = (
27+ );
28+ runOnlyForDeploymentPostprocessing = 1;
29+ };
30+/* End PBXCopyFilesBuildPhase section */
31+
32+/* Begin PBXFileReference section */
33+ 034CB5211D7C6B80006D4E84 /* test_SBJSON */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = test_SBJSON; sourceTree = BUILT_PRODUCTS_DIR; };
34+ 034CB5241D7C6B80006D4E84 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
35+ 034CB52B1D7C6B8F006D4E84 /* SBJson4.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJson4.h; sourceTree = "<group>"; };
36+ 034CB52C1D7C6B8F006D4E84 /* SBJson4StreamWriterState.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJson4StreamWriterState.m; sourceTree = "<group>"; };
37+ 034CB52D1D7C6B8F006D4E84 /* SBJson4StreamWriterState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJson4StreamWriterState.h; sourceTree = "<group>"; };
38+ 034CB52E1D7C6B8F006D4E84 /* SBJson4StreamParserState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJson4StreamParserState.h; sourceTree = "<group>"; };
39+ 034CB52F1D7C6B8F006D4E84 /* SBJson4StreamWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJson4StreamWriter.h; sourceTree = "<group>"; };
40+ 034CB5301D7C6B8F006D4E84 /* SBJson4StreamWriter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJson4StreamWriter.m; sourceTree = "<group>"; };
41+ 034CB5311D7C6B8F006D4E84 /* SBJson4StreamParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJson4StreamParser.h; sourceTree = "<group>"; };
42+ 034CB5321D7C6B8F006D4E84 /* SBJson4Parser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJson4Parser.h; sourceTree = "<group>"; };
43+ 034CB5331D7C6B8F006D4E84 /* SBJson4StreamParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJson4StreamParser.m; sourceTree = "<group>"; };
44+ 034CB5341D7C6B8F006D4E84 /* SBJson4Parser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJson4Parser.m; sourceTree = "<group>"; };
45+ 034CB5351D7C6B8F006D4E84 /* SBJson4Writer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJson4Writer.m; sourceTree = "<group>"; };
46+ 034CB5361D7C6B8F006D4E84 /* SBJson4Writer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJson4Writer.h; sourceTree = "<group>"; };
47+ 034CB5371D7C6B8F006D4E84 /* SBJson4StreamParserState.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJson4StreamParserState.m; sourceTree = "<group>"; };
48+ 034CB5381D7C6B8F006D4E84 /* SBJson4StreamTokeniser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJson4StreamTokeniser.m; sourceTree = "<group>"; };
49+ 034CB5391D7C6B8F006D4E84 /* SBJson4StreamTokeniser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJson4StreamTokeniser.h; sourceTree = "<group>"; };
50+/* End PBXFileReference section */
51+
52+/* Begin PBXFrameworksBuildPhase section */
53+ 034CB51E1D7C6B80006D4E84 /* Frameworks */ = {
54+ isa = PBXFrameworksBuildPhase;
55+ buildActionMask = 2147483647;
56+ files = (
57+ );
58+ runOnlyForDeploymentPostprocessing = 0;
59+ };
60+/* End PBXFrameworksBuildPhase section */
61+
62+/* Begin PBXGroup section */
63+ 034CB5181D7C6B80006D4E84 = {
64+ isa = PBXGroup;
65+ children = (
66+ 034CB52B1D7C6B8F006D4E84 /* SBJson4.h */,
67+ 034CB52C1D7C6B8F006D4E84 /* SBJson4StreamWriterState.m */,
68+ 034CB52D1D7C6B8F006D4E84 /* SBJson4StreamWriterState.h */,
69+ 034CB52E1D7C6B8F006D4E84 /* SBJson4StreamParserState.h */,
70+ 034CB52F1D7C6B8F006D4E84 /* SBJson4StreamWriter.h */,
71+ 034CB5301D7C6B8F006D4E84 /* SBJson4StreamWriter.m */,
72+ 034CB5311D7C6B8F006D4E84 /* SBJson4StreamParser.h */,
73+ 034CB5321D7C6B8F006D4E84 /* SBJson4Parser.h */,
74+ 034CB5331D7C6B8F006D4E84 /* SBJson4StreamParser.m */,
75+ 034CB5341D7C6B8F006D4E84 /* SBJson4Parser.m */,
76+ 034CB5351D7C6B8F006D4E84 /* SBJson4Writer.m */,
77+ 034CB5361D7C6B8F006D4E84 /* SBJson4Writer.h */,
78+ 034CB5371D7C6B8F006D4E84 /* SBJson4StreamParserState.m */,
79+ 034CB5381D7C6B8F006D4E84 /* SBJson4StreamTokeniser.m */,
80+ 034CB5391D7C6B8F006D4E84 /* SBJson4StreamTokeniser.h */,
81+ 034CB5231D7C6B80006D4E84 /* test_SBJSON */,
82+ 034CB5221D7C6B80006D4E84 /* Products */,
83+ );
84+ sourceTree = "<group>";
85+ };
86+ 034CB5221D7C6B80006D4E84 /* Products */ = {
87+ isa = PBXGroup;
88+ children = (
89+ 034CB5211D7C6B80006D4E84 /* test_SBJSON */,
90+ );
91+ name = Products;
92+ sourceTree = "<group>";
93+ };
94+ 034CB5231D7C6B80006D4E84 /* test_SBJSON */ = {
95+ isa = PBXGroup;
96+ children = (
97+ 034CB5241D7C6B80006D4E84 /* main.m */,
98+ );
99+ path = test_SBJSON;
100+ sourceTree = "<group>";
101+ };
102+/* End PBXGroup section */
103+
104+/* Begin PBXNativeTarget section */
105+ 034CB5201D7C6B80006D4E84 /* test_SBJSON */ = {
106+ isa = PBXNativeTarget;
107+ buildConfigurationList = 034CB5281D7C6B80006D4E84 /* Build configuration list for PBXNativeTarget "test_SBJSON" */;
108+ buildPhases = (
109+ 034CB51D1D7C6B80006D4E84 /* Sources */,
110+ 034CB51E1D7C6B80006D4E84 /* Frameworks */,
111+ 034CB51F1D7C6B80006D4E84 /* CopyFiles */,
112+ );
113+ buildRules = (
114+ );
115+ dependencies = (
116+ );
117+ name = test_SBJSON;
118+ productName = test_SBJSON;
119+ productReference = 034CB5211D7C6B80006D4E84 /* test_SBJSON */;
120+ productType = "com.apple.product-type.tool";
121+ };
122+/* End PBXNativeTarget section */
123+
124+/* Begin PBXProject section */
125+ 034CB5191D7C6B80006D4E84 /* Project object */ = {
126+ isa = PBXProject;
127+ attributes = {
128+ LastUpgradeCheck = 0730;
129+ ORGANIZATIONNAME = "Nicolas Seriot";
130+ TargetAttributes = {
131+ 034CB5201D7C6B80006D4E84 = {
132+ CreatedOnToolsVersion = 7.3;
133+ };
134+ };
135+ };
136+ buildConfigurationList = 034CB51C1D7C6B80006D4E84 /* Build configuration list for PBXProject "test_SBJSON" */;
137+ compatibilityVersion = "Xcode 3.2";
138+ developmentRegion = English;
139+ hasScannedForEncodings = 0;
140+ knownRegions = (
141+ en,
142+ );
143+ mainGroup = 034CB5181D7C6B80006D4E84;
144+ productRefGroup = 034CB5221D7C6B80006D4E84 /* Products */;
145+ projectDirPath = "";
146+ projectRoot = "";
147+ targets = (
148+ 034CB5201D7C6B80006D4E84 /* test_SBJSON */,
149+ );
150+ };
151+/* End PBXProject section */
152+
153+/* Begin PBXSourcesBuildPhase section */
154+ 034CB51D1D7C6B80006D4E84 /* Sources */ = {
155+ isa = PBXSourcesBuildPhase;
156+ buildActionMask = 2147483647;
157+ files = (
158+ 034CB53F1D7C6B8F006D4E84 /* SBJson4StreamParserState.m in Sources */,
159+ 034CB53C1D7C6B8F006D4E84 /* SBJson4StreamParser.m in Sources */,
160+ 034CB53A1D7C6B8F006D4E84 /* SBJson4StreamWriterState.m in Sources */,
161+ 034CB5251D7C6B80006D4E84 /* main.m in Sources */,
162+ 034CB53D1D7C6B8F006D4E84 /* SBJson4Parser.m in Sources */,
163+ 034CB53E1D7C6B8F006D4E84 /* SBJson4Writer.m in Sources */,
164+ 034CB5401D7C6B8F006D4E84 /* SBJson4StreamTokeniser.m in Sources */,
165+ 034CB53B1D7C6B8F006D4E84 /* SBJson4StreamWriter.m in Sources */,
166+ );
167+ runOnlyForDeploymentPostprocessing = 0;
168+ };
169+/* End PBXSourcesBuildPhase section */
170+
171+/* Begin XCBuildConfiguration section */
172+ 034CB5261D7C6B80006D4E84 /* Debug */ = {
173+ isa = XCBuildConfiguration;
174+ buildSettings = {
175+ ALWAYS_SEARCH_USER_PATHS = NO;
176+ CLANG_ANALYZER_NONNULL = YES;
177+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
178+ CLANG_CXX_LIBRARY = "libc++";
179+ CLANG_ENABLE_MODULES = YES;
180+ CLANG_ENABLE_OBJC_ARC = YES;
181+ CLANG_WARN_BOOL_CONVERSION = YES;
182+ CLANG_WARN_CONSTANT_CONVERSION = YES;
183+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
184+ CLANG_WARN_EMPTY_BODY = YES;
185+ CLANG_WARN_ENUM_CONVERSION = YES;
186+ CLANG_WARN_INT_CONVERSION = YES;
187+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
188+ CLANG_WARN_UNREACHABLE_CODE = YES;
189+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
190+ CODE_SIGN_IDENTITY = "-";
191+ COPY_PHASE_STRIP = NO;
192+ DEBUG_INFORMATION_FORMAT = dwarf;
193+ ENABLE_STRICT_OBJC_MSGSEND = YES;
194+ ENABLE_TESTABILITY = YES;
195+ GCC_C_LANGUAGE_STANDARD = gnu99;
196+ GCC_DYNAMIC_NO_PIC = NO;
197+ GCC_NO_COMMON_BLOCKS = YES;
198+ GCC_OPTIMIZATION_LEVEL = 0;
199+ GCC_PREPROCESSOR_DEFINITIONS = (
200+ "DEBUG=1",
201+ "$(inherited)",
202+ );
203+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
204+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
205+ GCC_WARN_UNDECLARED_SELECTOR = YES;
206+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
207+ GCC_WARN_UNUSED_FUNCTION = YES;
208+ GCC_WARN_UNUSED_VARIABLE = YES;
209+ MACOSX_DEPLOYMENT_TARGET = 10.11;
210+ MTL_ENABLE_DEBUG_INFO = YES;
211+ ONLY_ACTIVE_ARCH = YES;
212+ SDKROOT = macosx;
213+ };
214+ name = Debug;
215+ };
216+ 034CB5271D7C6B80006D4E84 /* Release */ = {
217+ isa = XCBuildConfiguration;
218+ buildSettings = {
219+ ALWAYS_SEARCH_USER_PATHS = NO;
220+ CLANG_ANALYZER_NONNULL = YES;
221+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
222+ CLANG_CXX_LIBRARY = "libc++";
223+ CLANG_ENABLE_MODULES = YES;
224+ CLANG_ENABLE_OBJC_ARC = YES;
225+ CLANG_WARN_BOOL_CONVERSION = YES;
226+ CLANG_WARN_CONSTANT_CONVERSION = YES;
227+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
228+ CLANG_WARN_EMPTY_BODY = YES;
229+ CLANG_WARN_ENUM_CONVERSION = YES;
230+ CLANG_WARN_INT_CONVERSION = YES;
231+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
232+ CLANG_WARN_UNREACHABLE_CODE = YES;
233+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
234+ CODE_SIGN_IDENTITY = "-";
235+ COPY_PHASE_STRIP = NO;
236+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
237+ ENABLE_NS_ASSERTIONS = NO;
238+ ENABLE_STRICT_OBJC_MSGSEND = YES;
239+ GCC_C_LANGUAGE_STANDARD = gnu99;
240+ GCC_NO_COMMON_BLOCKS = YES;
241+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
242+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
243+ GCC_WARN_UNDECLARED_SELECTOR = YES;
244+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
245+ GCC_WARN_UNUSED_FUNCTION = YES;
246+ GCC_WARN_UNUSED_VARIABLE = YES;
247+ MACOSX_DEPLOYMENT_TARGET = 10.11;
248+ MTL_ENABLE_DEBUG_INFO = NO;
249+ SDKROOT = macosx;
250+ };
251+ name = Release;
252+ };
253+ 034CB5291D7C6B80006D4E84 /* Debug */ = {
254+ isa = XCBuildConfiguration;
255+ buildSettings = {
256+ PRODUCT_NAME = "$(TARGET_NAME)";
257+ };
258+ name = Debug;
259+ };
260+ 034CB52A1D7C6B80006D4E84 /* Release */ = {
261+ isa = XCBuildConfiguration;
262+ buildSettings = {
263+ PRODUCT_NAME = "$(TARGET_NAME)";
264+ };
265+ name = Release;
266+ };
267+/* End XCBuildConfiguration section */
268+
269+/* Begin XCConfigurationList section */
270+ 034CB51C1D7C6B80006D4E84 /* Build configuration list for PBXProject "test_SBJSON" */ = {
271+ isa = XCConfigurationList;
272+ buildConfigurations = (
273+ 034CB5261D7C6B80006D4E84 /* Debug */,
274+ 034CB5271D7C6B80006D4E84 /* Release */,
275+ );
276+ defaultConfigurationIsVisible = 0;
277+ defaultConfigurationName = Release;
278+ };
279+ 034CB5281D7C6B80006D4E84 /* Build configuration list for PBXNativeTarget "test_SBJSON" */ = {
280+ isa = XCConfigurationList;
281+ buildConfigurations = (
282+ 034CB5291D7C6B80006D4E84 /* Debug */,
283+ 034CB52A1D7C6B80006D4E84 /* Release */,
284+ );
285+ defaultConfigurationIsVisible = 0;
286+ };
287+/* End XCConfigurationList section */
288+ };
289+ rootObject = 034CB5191D7C6B80006D4E84 /* Project object */;
290+}
parsers/test_SBJSON/test_SBJSON.xcodeproj/project.xcworkspace/contents.xcworkspacedatanew file+7
@@ -0,0 +1,7 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<Workspace
3+ version = "1.0">
4+ <FileRef
5+ location = "self:test_SBJSON.xcodeproj">
6+ </FileRef>
7+</Workspace>
parsers/test_SBJSON/test_SBJSON.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstatenew file

Binary file not shown.

parsers/test_SBJSON/test_SBJSON.xcodeproj/xcuserdata/nst.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlistnew file+5
@@ -0,0 +1,5 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<Bucket
3+ type = "1"
4+ version = "2.0">
5+</Bucket>
parsers/test_SBJSON/test_SBJSON.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test_SBJSON.xcschemenew file+91
@@ -0,0 +1,91 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<Scheme
3+ LastUpgradeVersion = "0730"
4+ version = "1.3">
5+ <BuildAction
6+ parallelizeBuildables = "YES"
7+ buildImplicitDependencies = "YES">
8+ <BuildActionEntries>
9+ <BuildActionEntry
10+ buildForTesting = "YES"
11+ buildForRunning = "YES"
12+ buildForProfiling = "YES"
13+ buildForArchiving = "YES"
14+ buildForAnalyzing = "YES">
15+ <BuildableReference
16+ BuildableIdentifier = "primary"
17+ BlueprintIdentifier = "034CB5201D7C6B80006D4E84"
18+ BuildableName = "test_SBJSON"
19+ BlueprintName = "test_SBJSON"
20+ ReferencedContainer = "container:test_SBJSON.xcodeproj">
21+ </BuildableReference>
22+ </BuildActionEntry>
23+ </BuildActionEntries>
24+ </BuildAction>
25+ <TestAction
26+ buildConfiguration = "Debug"
27+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
28+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
29+ shouldUseLaunchSchemeArgsEnv = "YES">
30+ <Testables>
31+ </Testables>
32+ <MacroExpansion>
33+ <BuildableReference
34+ BuildableIdentifier = "primary"
35+ BlueprintIdentifier = "034CB5201D7C6B80006D4E84"
36+ BuildableName = "test_SBJSON"
37+ BlueprintName = "test_SBJSON"
38+ ReferencedContainer = "container:test_SBJSON.xcodeproj">
39+ </BuildableReference>
40+ </MacroExpansion>
41+ <AdditionalOptions>
42+ </AdditionalOptions>
43+ </TestAction>
44+ <LaunchAction
45+ buildConfiguration = "Debug"
46+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
47+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
48+ launchStyle = "0"
49+ useCustomWorkingDirectory = "NO"
50+ ignoresPersistentStateOnLaunch = "NO"
51+ debugDocumentVersioning = "YES"
52+ debugServiceExtension = "internal"
53+ allowLocationSimulation = "YES">
54+ <BuildableProductRunnable
55+ runnableDebuggingMode = "0">
56+ <BuildableReference
57+ BuildableIdentifier = "primary"
58+ BlueprintIdentifier = "034CB5201D7C6B80006D4E84"
59+ BuildableName = "test_SBJSON"
60+ BlueprintName = "test_SBJSON"
61+ ReferencedContainer = "container:test_SBJSON.xcodeproj">
62+ </BuildableReference>
63+ </BuildableProductRunnable>
64+ <AdditionalOptions>
65+ </AdditionalOptions>
66+ </LaunchAction>
67+ <ProfileAction
68+ buildConfiguration = "Release"
69+ shouldUseLaunchSchemeArgsEnv = "YES"
70+ savedToolIdentifier = ""
71+ useCustomWorkingDirectory = "NO"
72+ debugDocumentVersioning = "YES">
73+ <BuildableProductRunnable
74+ runnableDebuggingMode = "0">
75+ <BuildableReference
76+ BuildableIdentifier = "primary"
77+ BlueprintIdentifier = "034CB5201D7C6B80006D4E84"
78+ BuildableName = "test_SBJSON"
79+ BlueprintName = "test_SBJSON"
80+ ReferencedContainer = "container:test_SBJSON.xcodeproj">
81+ </BuildableReference>
82+ </BuildableProductRunnable>
83+ </ProfileAction>
84+ <AnalyzeAction
85+ buildConfiguration = "Debug">
86+ </AnalyzeAction>
87+ <ArchiveAction
88+ buildConfiguration = "Release"
89+ revealArchiveInOrganizer = "YES">
90+ </ArchiveAction>
91+</Scheme>
parsers/test_SBJSON/test_SBJSON.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plistnew file+22
@@ -0,0 +1,22 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+<plist version="1.0">
4+<dict>
5+ <key>SchemeUserState</key>
6+ <dict>
7+ <key>test_SBJSON.xcscheme</key>
8+ <dict>
9+ <key>orderHint</key>
10+ <integer>0</integer>
11+ </dict>
12+ </dict>
13+ <key>SuppressBuildableAutocreation</key>
14+ <dict>
15+ <key>034CB5201D7C6B80006D4E84</key>
16+ <dict>
17+ <key>primary</key>
18+ <true/>
19+ </dict>
20+ </dict>
21+</dict>
22+</plist>
parsers/test_SBJSON/test_SBJSON/main.mnew file+38
@@ -0,0 +1,38 @@
1+//
2+// main.m
3+// test_SBJSON
4+//
5+// Created by nst on 04/09/16.
6+// Copyright © 2016 Nicolas Seriot. All rights reserved.
7+//
8+
9+#import <Foundation/Foundation.h>
10+#import "SBJson4.h"
11+
12+int main(int argc, const char * argv[]) {
13+ @autoreleasepool {
14+
15+ SBJson4Parser *parser = [SBJson4Parser parserWithBlock:^(id item, BOOL *stop) {
16+ //NSLog(@"-- %@", item);
17+ exit(0);
18+ }
19+ allowMultiRoot:NO
20+ unwrapRootArray:NO
21+ errorHandler:^(NSError *error) {
22+ //NSLog(@"%@", error);
23+ exit(1);
24+ }];
25+
26+ NSString *path = [NSString stringWithCString:argv[1] encoding:NSUTF8StringEncoding];
27+ NSData *data = [NSData dataWithContentsOfFile:path];
28+ SBJson4ParserStatus status = [parser parse:data];
29+
30+ if (status == SBJson4ParserComplete) exit(0);
31+ if (status == SBJson4ParserStopped) exit(1);
32+ if (status == SBJson4ParserWaitingForData) exit(1);
33+ if (status == SBJson4ParserError) exit(1);
34+
35+ [[NSRunLoop currentRunLoop] run];
36+ }
37+ return 0;
38+}
parsers/test_STJSON/STJSON.xcodeproj/project.pbxprojnew file+361
@@ -0,0 +1,361 @@
1+// !$*UTF8*$!
2+{
3+ archiveVersion = 1;
4+ classes = {
5+ };
6+ objectVersion = 46;
7+ objects = {
8+
9+/* Begin PBXBuildFile section */
10+ 035DA2FC1DB503D100C8895E /* STJSONParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 035DA2FB1DB503D100C8895E /* STJSONParser.swift */; };
11+ 035DA3041DB503EC00C8895E /* STJSONTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 035DA3031DB503EC00C8895E /* STJSONTests.swift */; };
12+ 035DA3091DB5044600C8895E /* STJSONParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 035DA2FB1DB503D100C8895E /* STJSONParser.swift */; };
13+ 03B473A41DB7D0F600345B26 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 035DA2F41DB503C400C8895E /* main.swift */; };
14+/* End PBXBuildFile section */
15+
16+/* Begin PBXCopyFilesBuildPhase section */
17+ 035DA2EF1DB503C400C8895E /* CopyFiles */ = {
18+ isa = PBXCopyFilesBuildPhase;
19+ buildActionMask = 2147483647;
20+ dstPath = /usr/share/man/man1/;
21+ dstSubfolderSpec = 0;
22+ files = (
23+ );
24+ runOnlyForDeploymentPostprocessing = 1;
25+ };
26+/* End PBXCopyFilesBuildPhase section */
27+
28+/* Begin PBXFileReference section */
29+ 035DA2F11DB503C400C8895E /* STJSON */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = STJSON; sourceTree = BUILT_PRODUCTS_DIR; };
30+ 035DA2F41DB503C400C8895E /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
31+ 035DA2FB1DB503D100C8895E /* STJSONParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = STJSONParser.swift; sourceTree = "<group>"; };
32+ 035DA3011DB503EC00C8895E /* STJSONTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = STJSONTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
33+ 035DA3031DB503EC00C8895E /* STJSONTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = STJSONTests.swift; sourceTree = "<group>"; };
34+ 035DA3051DB503EC00C8895E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
35+/* End PBXFileReference section */
36+
37+/* Begin PBXFrameworksBuildPhase section */
38+ 035DA2EE1DB503C400C8895E /* Frameworks */ = {
39+ isa = PBXFrameworksBuildPhase;
40+ buildActionMask = 2147483647;
41+ files = (
42+ );
43+ runOnlyForDeploymentPostprocessing = 0;
44+ };
45+ 035DA2FE1DB503EC00C8895E /* Frameworks */ = {
46+ isa = PBXFrameworksBuildPhase;
47+ buildActionMask = 2147483647;
48+ files = (
49+ );
50+ runOnlyForDeploymentPostprocessing = 0;
51+ };
52+/* End PBXFrameworksBuildPhase section */
53+
54+/* Begin PBXGroup section */
55+ 035DA2E81DB503C400C8895E = {
56+ isa = PBXGroup;
57+ children = (
58+ 035DA2F31DB503C400C8895E /* STJSON */,
59+ 035DA3021DB503EC00C8895E /* STJSONTests */,
60+ 035DA2F21DB503C400C8895E /* Products */,
61+ );
62+ sourceTree = "<group>";
63+ };
64+ 035DA2F21DB503C400C8895E /* Products */ = {
65+ isa = PBXGroup;
66+ children = (
67+ 035DA2F11DB503C400C8895E /* STJSON */,
68+ 035DA3011DB503EC00C8895E /* STJSONTests.xctest */,
69+ );
70+ name = Products;
71+ sourceTree = "<group>";
72+ };
73+ 035DA2F31DB503C400C8895E /* STJSON */ = {
74+ isa = PBXGroup;
75+ children = (
76+ 035DA2FB1DB503D100C8895E /* STJSONParser.swift */,
77+ 035DA2F41DB503C400C8895E /* main.swift */,
78+ );
79+ path = STJSON;
80+ sourceTree = "<group>";
81+ };
82+ 035DA3021DB503EC00C8895E /* STJSONTests */ = {
83+ isa = PBXGroup;
84+ children = (
85+ 035DA3031DB503EC00C8895E /* STJSONTests.swift */,
86+ 035DA3051DB503EC00C8895E /* Info.plist */,
87+ );
88+ path = STJSONTests;
89+ sourceTree = "<group>";
90+ };
91+/* End PBXGroup section */
92+
93+/* Begin PBXNativeTarget section */
94+ 035DA2F01DB503C400C8895E /* STJSON */ = {
95+ isa = PBXNativeTarget;
96+ buildConfigurationList = 035DA2F81DB503C400C8895E /* Build configuration list for PBXNativeTarget "STJSON" */;
97+ buildPhases = (
98+ 035DA2ED1DB503C400C8895E /* Sources */,
99+ 035DA2EE1DB503C400C8895E /* Frameworks */,
100+ 035DA2EF1DB503C400C8895E /* CopyFiles */,
101+ );
102+ buildRules = (
103+ );
104+ dependencies = (
105+ );
106+ name = STJSON;
107+ productName = STJSON;
108+ productReference = 035DA2F11DB503C400C8895E /* STJSON */;
109+ productType = "com.apple.product-type.tool";
110+ };
111+ 035DA3001DB503EC00C8895E /* STJSONTests */ = {
112+ isa = PBXNativeTarget;
113+ buildConfigurationList = 035DA3061DB503EC00C8895E /* Build configuration list for PBXNativeTarget "STJSONTests" */;
114+ buildPhases = (
115+ 035DA2FD1DB503EC00C8895E /* Sources */,
116+ 035DA2FE1DB503EC00C8895E /* Frameworks */,
117+ 035DA2FF1DB503EC00C8895E /* Resources */,
118+ );
119+ buildRules = (
120+ );
121+ dependencies = (
122+ );
123+ name = STJSONTests;
124+ productName = STJSONTests;
125+ productReference = 035DA3011DB503EC00C8895E /* STJSONTests.xctest */;
126+ productType = "com.apple.product-type.bundle.unit-test";
127+ };
128+/* End PBXNativeTarget section */
129+
130+/* Begin PBXProject section */
131+ 035DA2E91DB503C400C8895E /* Project object */ = {
132+ isa = PBXProject;
133+ attributes = {
134+ LastSwiftUpdateCheck = 0810;
135+ LastUpgradeCheck = 0810;
136+ ORGANIZATIONNAME = ch.seriot;
137+ TargetAttributes = {
138+ 035DA2F01DB503C400C8895E = {
139+ CreatedOnToolsVersion = 8.1;
140+ ProvisioningStyle = Automatic;
141+ };
142+ 035DA3001DB503EC00C8895E = {
143+ CreatedOnToolsVersion = 8.1;
144+ ProvisioningStyle = Automatic;
145+ };
146+ };
147+ };
148+ buildConfigurationList = 035DA2EC1DB503C400C8895E /* Build configuration list for PBXProject "STJSON" */;
149+ compatibilityVersion = "Xcode 3.2";
150+ developmentRegion = English;
151+ hasScannedForEncodings = 0;
152+ knownRegions = (
153+ en,
154+ );
155+ mainGroup = 035DA2E81DB503C400C8895E;
156+ productRefGroup = 035DA2F21DB503C400C8895E /* Products */;
157+ projectDirPath = "";
158+ projectRoot = "";
159+ targets = (
160+ 035DA2F01DB503C400C8895E /* STJSON */,
161+ 035DA3001DB503EC00C8895E /* STJSONTests */,
162+ );
163+ };
164+/* End PBXProject section */
165+
166+/* Begin PBXResourcesBuildPhase section */
167+ 035DA2FF1DB503EC00C8895E /* Resources */ = {
168+ isa = PBXResourcesBuildPhase;
169+ buildActionMask = 2147483647;
170+ files = (
171+ );
172+ runOnlyForDeploymentPostprocessing = 0;
173+ };
174+/* End PBXResourcesBuildPhase section */
175+
176+/* Begin PBXSourcesBuildPhase section */
177+ 035DA2ED1DB503C400C8895E /* Sources */ = {
178+ isa = PBXSourcesBuildPhase;
179+ buildActionMask = 2147483647;
180+ files = (
181+ 03B473A41DB7D0F600345B26 /* main.swift in Sources */,
182+ 035DA2FC1DB503D100C8895E /* STJSONParser.swift in Sources */,
183+ );
184+ runOnlyForDeploymentPostprocessing = 0;
185+ };
186+ 035DA2FD1DB503EC00C8895E /* Sources */ = {
187+ isa = PBXSourcesBuildPhase;
188+ buildActionMask = 2147483647;
189+ files = (
190+ 035DA3041DB503EC00C8895E /* STJSONTests.swift in Sources */,
191+ 035DA3091DB5044600C8895E /* STJSONParser.swift in Sources */,
192+ );
193+ runOnlyForDeploymentPostprocessing = 0;
194+ };
195+/* End PBXSourcesBuildPhase section */
196+
197+/* Begin XCBuildConfiguration section */
198+ 035DA2F61DB503C400C8895E /* Debug */ = {
199+ isa = XCBuildConfiguration;
200+ buildSettings = {
201+ ALWAYS_SEARCH_USER_PATHS = NO;
202+ CLANG_ANALYZER_NONNULL = YES;
203+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
204+ CLANG_CXX_LIBRARY = "libc++";
205+ CLANG_ENABLE_MODULES = YES;
206+ CLANG_ENABLE_OBJC_ARC = YES;
207+ CLANG_WARN_BOOL_CONVERSION = YES;
208+ CLANG_WARN_CONSTANT_CONVERSION = YES;
209+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
210+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
211+ CLANG_WARN_EMPTY_BODY = YES;
212+ CLANG_WARN_ENUM_CONVERSION = YES;
213+ CLANG_WARN_INFINITE_RECURSION = YES;
214+ CLANG_WARN_INT_CONVERSION = YES;
215+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
216+ CLANG_WARN_SUSPICIOUS_MOVES = YES;
217+ CLANG_WARN_UNREACHABLE_CODE = YES;
218+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
219+ CODE_SIGN_IDENTITY = "-";
220+ COPY_PHASE_STRIP = NO;
221+ DEBUG_INFORMATION_FORMAT = dwarf;
222+ ENABLE_STRICT_OBJC_MSGSEND = YES;
223+ ENABLE_TESTABILITY = YES;
224+ GCC_C_LANGUAGE_STANDARD = gnu99;
225+ GCC_DYNAMIC_NO_PIC = NO;
226+ GCC_NO_COMMON_BLOCKS = YES;
227+ GCC_OPTIMIZATION_LEVEL = 0;
228+ GCC_PREPROCESSOR_DEFINITIONS = (
229+ "DEBUG=1",
230+ "$(inherited)",
231+ );
232+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
233+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
234+ GCC_WARN_UNDECLARED_SELECTOR = YES;
235+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
236+ GCC_WARN_UNUSED_FUNCTION = YES;
237+ GCC_WARN_UNUSED_VARIABLE = YES;
238+ MACOSX_DEPLOYMENT_TARGET = 10.12;
239+ MTL_ENABLE_DEBUG_INFO = YES;
240+ ONLY_ACTIVE_ARCH = YES;
241+ SDKROOT = macosx;
242+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
243+ };
244+ name = Debug;
245+ };
246+ 035DA2F71DB503C400C8895E /* Release */ = {
247+ isa = XCBuildConfiguration;
248+ buildSettings = {
249+ ALWAYS_SEARCH_USER_PATHS = NO;
250+ CLANG_ANALYZER_NONNULL = YES;
251+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
252+ CLANG_CXX_LIBRARY = "libc++";
253+ CLANG_ENABLE_MODULES = YES;
254+ CLANG_ENABLE_OBJC_ARC = YES;
255+ CLANG_WARN_BOOL_CONVERSION = YES;
256+ CLANG_WARN_CONSTANT_CONVERSION = YES;
257+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
258+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
259+ CLANG_WARN_EMPTY_BODY = YES;
260+ CLANG_WARN_ENUM_CONVERSION = YES;
261+ CLANG_WARN_INFINITE_RECURSION = YES;
262+ CLANG_WARN_INT_CONVERSION = YES;
263+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
264+ CLANG_WARN_SUSPICIOUS_MOVES = YES;
265+ CLANG_WARN_UNREACHABLE_CODE = YES;
266+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
267+ CODE_SIGN_IDENTITY = "-";
268+ COPY_PHASE_STRIP = NO;
269+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
270+ ENABLE_NS_ASSERTIONS = NO;
271+ ENABLE_STRICT_OBJC_MSGSEND = YES;
272+ GCC_C_LANGUAGE_STANDARD = gnu99;
273+ GCC_NO_COMMON_BLOCKS = YES;
274+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
275+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
276+ GCC_WARN_UNDECLARED_SELECTOR = YES;
277+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
278+ GCC_WARN_UNUSED_FUNCTION = YES;
279+ GCC_WARN_UNUSED_VARIABLE = YES;
280+ MACOSX_DEPLOYMENT_TARGET = 10.12;
281+ MTL_ENABLE_DEBUG_INFO = NO;
282+ SDKROOT = macosx;
283+ };
284+ name = Release;
285+ };
286+ 035DA2F91DB503C400C8895E /* Debug */ = {
287+ isa = XCBuildConfiguration;
288+ buildSettings = {
289+ PRODUCT_NAME = "$(TARGET_NAME)";
290+ SWIFT_VERSION = 3.0;
291+ };
292+ name = Debug;
293+ };
294+ 035DA2FA1DB503C400C8895E /* Release */ = {
295+ isa = XCBuildConfiguration;
296+ buildSettings = {
297+ PRODUCT_NAME = "$(TARGET_NAME)";
298+ SWIFT_VERSION = 3.0;
299+ };
300+ name = Release;
301+ };
302+ 035DA3071DB503EC00C8895E /* Debug */ = {
303+ isa = XCBuildConfiguration;
304+ buildSettings = {
305+ COMBINE_HIDPI_IMAGES = YES;
306+ INFOPLIST_FILE = STJSONTests/Info.plist;
307+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
308+ PRODUCT_BUNDLE_IDENTIFIER = ch.seriot.STJSONTests;
309+ PRODUCT_NAME = "$(TARGET_NAME)";
310+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
311+ SWIFT_VERSION = 3.0;
312+ };
313+ name = Debug;
314+ };
315+ 035DA3081DB503EC00C8895E /* Release */ = {
316+ isa = XCBuildConfiguration;
317+ buildSettings = {
318+ COMBINE_HIDPI_IMAGES = YES;
319+ INFOPLIST_FILE = STJSONTests/Info.plist;
320+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
321+ PRODUCT_BUNDLE_IDENTIFIER = ch.seriot.STJSONTests;
322+ PRODUCT_NAME = "$(TARGET_NAME)";
323+ SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
324+ SWIFT_VERSION = 3.0;
325+ };
326+ name = Release;
327+ };
328+/* End XCBuildConfiguration section */
329+
330+/* Begin XCConfigurationList section */
331+ 035DA2EC1DB503C400C8895E /* Build configuration list for PBXProject "STJSON" */ = {
332+ isa = XCConfigurationList;
333+ buildConfigurations = (
334+ 035DA2F61DB503C400C8895E /* Debug */,
335+ 035DA2F71DB503C400C8895E /* Release */,
336+ );
337+ defaultConfigurationIsVisible = 0;
338+ defaultConfigurationName = Release;
339+ };
340+ 035DA2F81DB503C400C8895E /* Build configuration list for PBXNativeTarget "STJSON" */ = {
341+ isa = XCConfigurationList;
342+ buildConfigurations = (
343+ 035DA2F91DB503C400C8895E /* Debug */,
344+ 035DA2FA1DB503C400C8895E /* Release */,
345+ );
346+ defaultConfigurationIsVisible = 0;
347+ defaultConfigurationName = Release;
348+ };
349+ 035DA3061DB503EC00C8895E /* Build configuration list for PBXNativeTarget "STJSONTests" */ = {
350+ isa = XCConfigurationList;
351+ buildConfigurations = (
352+ 035DA3071DB503EC00C8895E /* Debug */,
353+ 035DA3081DB503EC00C8895E /* Release */,
354+ );
355+ defaultConfigurationIsVisible = 0;
356+ defaultConfigurationName = Release;
357+ };
358+/* End XCConfigurationList section */
359+ };
360+ rootObject = 035DA2E91DB503C400C8895E /* Project object */;
361+}
parsers/test_STJSON/STJSON.xcodeproj/project.xcworkspace/contents.xcworkspacedatanew file+7
@@ -0,0 +1,7 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<Workspace
3+ version = "1.0">
4+ <FileRef
5+ location = "self:STJSON.xcodeproj">
6+ </FileRef>
7+</Workspace>
parsers/test_STJSON/STJSON.xcodeproj/project.xcworkspace/xcshareddata/STJSON.xcscmblueprintnew file+30
@@ -0,0 +1,30 @@
1+{
2+ "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "ED13D74FC1ED9BC322EA1859E5AD7D001676FA6A",
3+ "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : {
4+
5+ },
6+ "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : {
7+ "ED13D74FC1ED9BC322EA1859E5AD7D001676FA6A" : 9223372036854775807,
8+ "4AEDBEBDB8C4256C790C244CE3F134EA5FC433C3" : 9223372036854775807
9+ },
10+ "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "48F90820-450B-4A88-B246-7C94B65E7D49",
11+ "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : {
12+ "ED13D74FC1ED9BC322EA1859E5AD7D001676FA6A" : "dropbox\/",
13+ "4AEDBEBDB8C4256C790C244CE3F134EA5FC433C3" : "STJSON\/"
14+ },
15+ "DVTSourceControlWorkspaceBlueprintNameKey" : "STJSON",
16+ "DVTSourceControlWorkspaceBlueprintVersion" : 204,
17+ "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "JSON\/parsers\/test_STJSON\/STJSON.xcodeproj",
18+ "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [
19+ {
20+ "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/nst\/STJSON.git",
21+ "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
22+ "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "4AEDBEBDB8C4256C790C244CE3F134EA5FC433C3"
23+ },
24+ {
25+ "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "\/Users\/nst\/Dropbox\/dropbox.git",
26+ "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
27+ "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "ED13D74FC1ED9BC322EA1859E5AD7D001676FA6A"
28+ }
29+ ]
30+}
parsers/test_STJSON/STJSON.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstatenew file

Binary file not shown.

parsers/test_STJSON/STJSON.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/STJSON.xcschemenew file+91
@@ -0,0 +1,91 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<Scheme
3+ LastUpgradeVersion = "0810"
4+ version = "1.3">
5+ <BuildAction
6+ parallelizeBuildables = "YES"
7+ buildImplicitDependencies = "YES">
8+ <BuildActionEntries>
9+ <BuildActionEntry
10+ buildForTesting = "YES"
11+ buildForRunning = "YES"
12+ buildForProfiling = "YES"
13+ buildForArchiving = "YES"
14+ buildForAnalyzing = "YES">
15+ <BuildableReference
16+ BuildableIdentifier = "primary"
17+ BlueprintIdentifier = "035DA2F01DB503C400C8895E"
18+ BuildableName = "STJSON"
19+ BlueprintName = "STJSON"
20+ ReferencedContainer = "container:STJSON.xcodeproj">
21+ </BuildableReference>
22+ </BuildActionEntry>
23+ </BuildActionEntries>
24+ </BuildAction>
25+ <TestAction
26+ buildConfiguration = "Debug"
27+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
28+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
29+ shouldUseLaunchSchemeArgsEnv = "YES">
30+ <Testables>
31+ </Testables>
32+ <MacroExpansion>
33+ <BuildableReference
34+ BuildableIdentifier = "primary"
35+ BlueprintIdentifier = "035DA2F01DB503C400C8895E"
36+ BuildableName = "STJSON"
37+ BlueprintName = "STJSON"
38+ ReferencedContainer = "container:STJSON.xcodeproj">
39+ </BuildableReference>
40+ </MacroExpansion>
41+ <AdditionalOptions>
42+ </AdditionalOptions>
43+ </TestAction>
44+ <LaunchAction
45+ buildConfiguration = "Debug"
46+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
47+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
48+ launchStyle = "0"
49+ useCustomWorkingDirectory = "NO"
50+ ignoresPersistentStateOnLaunch = "NO"
51+ debugDocumentVersioning = "YES"
52+ debugServiceExtension = "internal"
53+ allowLocationSimulation = "YES">
54+ <BuildableProductRunnable
55+ runnableDebuggingMode = "0">
56+ <BuildableReference
57+ BuildableIdentifier = "primary"
58+ BlueprintIdentifier = "035DA2F01DB503C400C8895E"
59+ BuildableName = "STJSON"
60+ BlueprintName = "STJSON"
61+ ReferencedContainer = "container:STJSON.xcodeproj">
62+ </BuildableReference>
63+ </BuildableProductRunnable>
64+ <AdditionalOptions>
65+ </AdditionalOptions>
66+ </LaunchAction>
67+ <ProfileAction
68+ buildConfiguration = "Release"
69+ shouldUseLaunchSchemeArgsEnv = "YES"
70+ savedToolIdentifier = ""
71+ useCustomWorkingDirectory = "NO"
72+ debugDocumentVersioning = "YES">
73+ <BuildableProductRunnable
74+ runnableDebuggingMode = "0">
75+ <BuildableReference
76+ BuildableIdentifier = "primary"
77+ BlueprintIdentifier = "035DA2F01DB503C400C8895E"
78+ BuildableName = "STJSON"
79+ BlueprintName = "STJSON"
80+ ReferencedContainer = "container:STJSON.xcodeproj">
81+ </BuildableReference>
82+ </BuildableProductRunnable>
83+ </ProfileAction>
84+ <AnalyzeAction
85+ buildConfiguration = "Debug">
86+ </AnalyzeAction>
87+ <ArchiveAction
88+ buildConfiguration = "Release"
89+ revealArchiveInOrganizer = "YES">
90+ </ArchiveAction>
91+</Scheme>
parsers/test_STJSON/STJSON.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/STJSONTests.xcschemenew file+56
@@ -0,0 +1,56 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<Scheme
3+ LastUpgradeVersion = "0810"
4+ version = "1.3">
5+ <BuildAction
6+ parallelizeBuildables = "YES"
7+ buildImplicitDependencies = "YES">
8+ </BuildAction>
9+ <TestAction
10+ buildConfiguration = "Debug"
11+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
12+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
13+ shouldUseLaunchSchemeArgsEnv = "YES">
14+ <Testables>
15+ <TestableReference
16+ skipped = "NO">
17+ <BuildableReference
18+ BuildableIdentifier = "primary"
19+ BlueprintIdentifier = "035DA3001DB503EC00C8895E"
20+ BuildableName = "STJSONTests.xctest"
21+ BlueprintName = "STJSONTests"
22+ ReferencedContainer = "container:STJSON.xcodeproj">
23+ </BuildableReference>
24+ </TestableReference>
25+ </Testables>
26+ <AdditionalOptions>
27+ </AdditionalOptions>
28+ </TestAction>
29+ <LaunchAction
30+ buildConfiguration = "Debug"
31+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
32+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
33+ launchStyle = "0"
34+ useCustomWorkingDirectory = "NO"
35+ ignoresPersistentStateOnLaunch = "NO"
36+ debugDocumentVersioning = "YES"
37+ debugServiceExtension = "internal"
38+ allowLocationSimulation = "YES">
39+ <AdditionalOptions>
40+ </AdditionalOptions>
41+ </LaunchAction>
42+ <ProfileAction
43+ buildConfiguration = "Release"
44+ shouldUseLaunchSchemeArgsEnv = "YES"
45+ savedToolIdentifier = ""
46+ useCustomWorkingDirectory = "NO"
47+ debugDocumentVersioning = "YES">
48+ </ProfileAction>
49+ <AnalyzeAction
50+ buildConfiguration = "Debug">
51+ </AnalyzeAction>
52+ <ArchiveAction
53+ buildConfiguration = "Release"
54+ revealArchiveInOrganizer = "YES">
55+ </ArchiveAction>
56+</Scheme>
parsers/test_STJSON/STJSON.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plistnew file+32
@@ -0,0 +1,32 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+<plist version="1.0">
4+<dict>
5+ <key>SchemeUserState</key>
6+ <dict>
7+ <key>STJSON.xcscheme</key>
8+ <dict>
9+ <key>orderHint</key>
10+ <integer>0</integer>
11+ </dict>
12+ <key>STJSONTests.xcscheme</key>
13+ <dict>
14+ <key>orderHint</key>
15+ <integer>1</integer>
16+ </dict>
17+ </dict>
18+ <key>SuppressBuildableAutocreation</key>
19+ <dict>
20+ <key>035DA2F01DB503C400C8895E</key>
21+ <dict>
22+ <key>primary</key>
23+ <true/>
24+ </dict>
25+ <key>035DA3001DB503EC00C8895E</key>
26+ <dict>
27+ <key>primary</key>
28+ <true/>
29+ </dict>
30+ </dict>
31+</dict>
32+</plist>
parsers/test_STJSON/STJSON/STJSONParser.swiftnew file+663
@@ -0,0 +1,663 @@
1+//
2+// JSONParser.swift
3+// JSON
4+//
5+// Created by Nicolas Seriot on 12/07/16.
6+// Copyright © 2016 Nicolas Seriot. All rights reserved.
7+//
8+
9+import Foundation
10+
11+public struct STJSONParser {
12+
13+ public struct Options: OptionSet {
14+ // https://oleb.net/blog/2016/09/swift-option-sets/
15+
16+ public let rawValue: Int
17+
18+ public init(rawValue:Int) {
19+ self.rawValue = rawValue
20+ }
21+
22+ static let useUnicodeReplacementCharacter = Options(rawValue: 1)
23+ }
24+
25+ enum ASCIIByte : UInt8 {
26+ case objectOpen = 0x7B // {
27+ case tab = 0x09 // \t
28+ case newline = 0x0A // \n
29+ case space = 0x20 // " "
30+ case carriageReturn = 0x0D // \r
31+ case doubleQuote = 0x22 // "
32+ case semiColon = 0x3A // :
33+ case objectClose = 0x7D // }
34+ case comma = 0x2C // ,
35+ case arrayOpen = 0x5B // [
36+ case arrayClose = 0x5D // ]
37+ case slash = 0x2F // /
38+ case backSlash = 0x5C // \
39+ case plus = 0x2B // +
40+ case minus = 0x2D // -
41+ case dot = 0x2E // .
42+ case zero = 0x30 // 0
43+ case one = 0x31 // 1
44+ case nine = 0x39 // 9
45+ case utf8BOMByte1 = 0xEF
46+ case utf8BOMByte2 = 0xBB
47+ case utf8BOMByte3 = 0xBF
48+ case A = 0x41
49+ case E = 0x45
50+ case F = 0x46
51+ case Z = 0x5A
52+ case a = 0x61
53+ case z = 0x7A
54+ case e = 0x65
55+ case f = 0x66
56+ case l = 0x6C
57+ case n = 0x6e
58+ case r = 0x72
59+ case s = 0x73
60+ case t = 0x74
61+ case u = 0x75
62+ }
63+
64+ let data : Data
65+ var i = 0
66+ let dataLength : Int
67+ var parserDepth = 0
68+ var maxParserDepth : Int
69+ let REPLACEMENT_STRING = "\u{FFFD}"
70+ var options : Options
71+
72+ init(data:Data, maxParserDepth : Int = 512, options:Options = []) {
73+ self.maxParserDepth = maxParserDepth
74+ self.data = data
75+ self.dataLength = data.count
76+ self.options = options
77+ }
78+
79+ func printRemainingString() {
80+ let range = Range(uncheckedBounds: (i, data.count))
81+ let remainingData = data.subdata(in:range)
82+ guard let remainingString = String(data:remainingData, encoding: .utf8) else {
83+ print("-- can't print remaining string")
84+ return
85+ }
86+ print("-- REMAINING STRING FROM \(i): \(remainingString)")
87+ }
88+
89+ func read() -> UInt8? {
90+ guard i < dataLength else { /* print("can't read at index \(i)"); */ return nil }
91+ return data[i]
92+ }
93+
94+ mutating func readAndMoveByteEither(_ a:[ASCIIByte]) -> UnicodeScalar? {
95+
96+ guard let byte = read() else { return nil }
97+
98+ for b in a {
99+ if byte == b.rawValue {
100+ i = i+1
101+ return UnicodeScalar(byte)
102+ }
103+ }
104+
105+ return nil
106+ }
107+
108+ mutating func readAndMove(_ b:ASCIIByte) -> Bool {
109+
110+ guard let byte = read()
111+ , byte == b.rawValue else { return false }
112+
113+ i = i+1
114+
115+ return true
116+ }
117+
118+ mutating func readAndMoveInByteRange(_ from:ASCIIByte, _ to:ASCIIByte) -> UnicodeScalar? {
119+
120+ guard let byte = read()
121+ , byte >= from.rawValue && byte <= to.rawValue else { return nil }
122+
123+ i = i+1
124+
125+ return UnicodeScalar(byte)
126+ }
127+
128+ mutating func readAndMoveHexadecimalDigit() -> UInt8? {
129+
130+ guard let byte = read()
131+ , readAndMoveInByteRange(.zero, .nine) != nil
132+ || readAndMoveInByteRange(.A, .F) != nil
133+ || readAndMoveInByteRange(.a, .f) != nil else {
134+ return nil
135+ }
136+
137+ return byte
138+ }
139+
140+ mutating func readAndMoveWhitespace() -> Bool {
141+ return readAndMove(.tab)
142+ || readAndMove(.newline)
143+ || readAndMove(.carriageReturn)
144+ || readAndMove(.space)
145+ }
146+
147+ mutating func readAndMoveAcceptableByte() -> Bool {
148+
149+ guard let byte = read()
150+ ,byte != ASCIIByte.doubleQuote.rawValue && byte != ASCIIByte.backSlash.rawValue && byte > 0x1F else {
151+ return false
152+ }
153+
154+ i = i + 1
155+
156+ return true
157+ }
158+
159+ mutating func readArray() throws -> [Any] {
160+
161+ while readAndMoveWhitespace() {}
162+
163+ guard readAndMove(.arrayOpen) else {
164+ throw JSONError.expectedArrayOpen(i:i)
165+ }
166+ parserDepth += 1
167+ guard parserDepth <= maxParserDepth else { throw JSONError.maxParserDepthReached(depth:maxParserDepth) }
168+
169+ var a : [Any] = []
170+
171+ while readAndMoveWhitespace() {}
172+
173+ if readAndMove(.arrayClose) {
174+ parserDepth -= 1
175+ return a
176+ }
177+
178+ if let v = try readValue() {
179+ a.append(v)
180+
181+ while readAndMoveWhitespace() {}
182+
183+ while readAndMove(.comma) {
184+ guard let v = try readValue() else {
185+ throw JSONError.expectedValue(i:i)
186+ }
187+ a.append(v)
188+
189+ while readAndMoveWhitespace() {}
190+ }
191+ }
192+
193+ guard readAndMove(.arrayClose) else {
194+ throw JSONError.expectedArrayClose(i:i)
195+ }
196+ parserDepth -= 1
197+
198+ return a
199+ }
200+
201+ func unescape(_ byte:UInt8) throws -> UInt8 {
202+ if byte == ASCIIByte.backSlash.rawValue
203+ || byte == ASCIIByte.doubleQuote.rawValue
204+ || byte == ASCIIByte.slash.rawValue {
205+ return byte
206+ }
207+
208+ if byte == UInt8(ascii: "b") { return 0x08 } // \b backspace
209+ if byte == UInt8(ascii: "f") { return 0x0C } // \f form feed
210+ if byte == UInt8(ascii: "n") { return 0x0A } // \n line feed
211+ if byte == UInt8(ascii: "r") { return 0x0D } // \r carriage return
212+ if byte == UInt8(ascii: "t") { return 0x09 } // \t tabulation
213+
214+ throw JSONError.expectedCharacterToBeUnescaped(i:i)
215+ }
216+
217+ /*
218+ func isValidCodepoint(codepoint cp:Int) -> Bool {
219+ // http://www.unicode.org/versions/Unicode5.2.0/ch03.pdf
220+ // Table 3-7. Well-Formed UTF-8 Byte Sequences
221+ return (cp >= 0 && cp <= 0xD7FF) || (cp >= 0xE000 && cp <= 0x10FFFF)
222+ }
223+ */
224+
225+ func isHighSurrogate(codepoint cp:Int) -> Bool {
226+ return cp >= 0xD800 && cp <= 0xDBFF
227+ }
228+
229+ func isLowSurrogate(codepoint cp:Int) -> Bool {
230+ return cp >= 0xDC00 && cp <= 0xDFFF
231+ }
232+
233+ mutating func readAndMoveUEscapedCodepoint() -> (String, Int)? {
234+ guard readAndMove(.u) else { return nil }
235+
236+ guard let b1 = readAndMoveHexadecimalDigit() else { /*print("** expected hexadecimal digit");*/ return nil }
237+ guard let b2 = readAndMoveHexadecimalDigit() else { /*print("** expected hexadecimal digit");*/ return nil }
238+ guard let b3 = readAndMoveHexadecimalDigit() else { /*print("** expected hexadecimal digit");*/ return nil }
239+ guard let b4 = readAndMoveHexadecimalDigit() else { /*print("** expected hexadecimal digit");*/ return nil }
240+
241+ guard let s = String(bytes: [b1, b2, b3, b4], encoding: .utf8) else {
242+ fatalError("** cannot convert \([b1, b2, b3, b4]) into string")
243+ }
244+
245+ return (s, strtol(s, nil, 16))
246+ }
247+
248+ mutating func readAndMoveEscapedCodepointOrSurrogates() throws -> String? {
249+
250+ let useReplacementString = self.options.contains(.useUnicodeReplacementCharacter)
251+
252+ /*
253+ http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf
254+ -> 6.1.4 The String Type
255+ // A code unit in the range 0 to 0xD7FF or in the range 0xE000 to 0xFFFF is interpreted as a code point with the same value.
256+ * A sequence of two code units, where the first code unit c1 is in the range 0xD800 to 0xDBFF and the second code unit c2
257+ is in the range 0xDC00 to 0xDFFF, is a surrogate pair and is interpreted as a code point with the value (c1 ‑ 0xD800) ×
258+ 0x400 + (c2 ‑ 0xDC00) + 0x10000. (See 10.1.2)
259+ * A code unit that is in the range 0xD800 to 0xDFFF, but is not part of a surrogate pair, is interpreted as a code point with
260+ the same value.
261+ */
262+
263+ guard let (s1, c1) = readAndMoveUEscapedCodepoint() else {
264+ return nil
265+ }
266+
267+ // valid codepoint -> return
268+ if let u = UnicodeScalar(c1) {
269+ return "\(u)"
270+ }
271+
272+ // invalid codepoint must be high surrogate, or error
273+ guard isHighSurrogate(codepoint: c1) else {
274+ return useReplacementString ? REPLACEMENT_STRING : "\\u\(s1)"
275+ }
276+
277+ // look for second surrogate escape character, or error
278+ guard readAndMove(.backSlash) else {
279+ return useReplacementString ? REPLACEMENT_STRING : "\\u\(s1)"
280+ }
281+
282+ // read second codepoint
283+ guard let (s2, c2) = readAndMoveUEscapedCodepoint() else {
284+ // or escaped sequence
285+ let x = try readAndMoveEscapedSequence()
286+ return useReplacementString ? REPLACEMENT_STRING + "\(x)" : "\\u\(s1)\(x)"
287+ }
288+
289+ // second codepoint must be low surrogate, or error
290+ guard isLowSurrogate(codepoint: c2) else {
291+ return useReplacementString ? REPLACEMENT_STRING + REPLACEMENT_STRING : "\\u\(s1)\\u\(s2)"
292+ }
293+
294+ let finalCodepoint = 0x400 + 0x2400 + (c1 - 0xD800) + (c2 - 0xDC00) + 0x10000
295+ guard let u = UnicodeScalar(finalCodepoint) else {
296+ return useReplacementString ? REPLACEMENT_STRING + REPLACEMENT_STRING : "\\u\(s1)\\u\(s2)"
297+ }
298+
299+ return "\(u)"
300+ }
301+
302+ mutating func readAndMoveEscapedSequence() throws -> String {
303+
304+ if let s = try readAndMoveEscapedCodepointOrSurrogates() {
305+ return s
306+ }
307+
308+ guard let b = read() else {
309+ throw JSONError.expectedCharacter(i:i)
310+ }
311+
312+ i = i + 1
313+
314+ let unescaped = try unescape(b)
315+
316+ let data = Data(bytes: [unescaped])
317+
318+ guard let s = String(data:data, encoding:.utf8) else {
319+ fatalError()
320+ }
321+
322+ return s
323+ }
324+
325+ mutating func readString() throws -> String {
326+
327+ if readAndMove(.doubleQuote) == false {
328+ throw JSONError.expectedDoubleQuote(i:i)
329+ }
330+
331+ var s : String = ""
332+
333+ while readAndMove(.doubleQuote) == false {
334+
335+ guard read() != nil else {
336+ throw JSONError.expectedCharacter(i:i)
337+ }
338+
339+ if readAndMove(.backSlash) {
340+
341+ let x = try readAndMoveEscapedSequence()
342+ s.append(x)
343+
344+ } else if readAndMoveAcceptableByte() {
345+
346+ let start = i-1
347+
348+ while readAndMoveAcceptableByte() {
349+ ()
350+ }
351+
352+ let range = Range(uncheckedBounds: (start, i))
353+
354+ let subdata = data.subdata(in: range)
355+
356+ guard let substring = String(data:subdata, encoding:.utf8) else {
357+ throw JSONError.cannotBuildStringFromData(i:i)
358+ }
359+
360+ s.append(substring)
361+ } else {
362+ throw JSONError.expectedAcceptableCodepointOrEscapedSequence(i:i)
363+ }
364+ }
365+
366+ return s
367+ }
368+
369+ mutating func readObject() throws -> [String:Any] {
370+
371+ guard readAndMove(.objectOpen) else {
372+ throw JSONError.expectedObjectOpen(i:i)
373+ }
374+ parserDepth += 1
375+ guard parserDepth <= maxParserDepth else { throw JSONError.maxParserDepthReached(depth:maxParserDepth) }
376+
377+ var d : [String:Any] = [:]
378+
379+ while readAndMoveWhitespace() {}
380+
381+ if readAndMove(.objectClose) {
382+ parserDepth -= 1
383+ return d
384+ }
385+
386+ repeat {
387+
388+ while readAndMoveWhitespace() {}
389+
390+ let s = try readString()
391+
392+ while readAndMoveWhitespace() {}
393+
394+ guard readAndMove(.semiColon) else {
395+ throw JSONError.expectedSemicolon(i:i)
396+ }
397+
398+ guard let v = try readValue() else {
399+ throw JSONError.expectedValue(i:i)
400+ }
401+
402+ d[s] = v
403+
404+ while readAndMoveWhitespace() {}
405+
406+ } while readAndMove(.comma)
407+
408+ guard readAndMove(.objectClose) else {
409+ throw JSONError.expectedObjectClose(i:i)
410+ }
411+ parserDepth -= 1
412+
413+ return d
414+ }
415+
416+ func throwIfStartsWithUTF16BOM() throws {
417+ let BOM_LENGTH = 2
418+
419+ guard dataLength >= BOM_LENGTH else { return }
420+
421+ let UTF_16_BE = Data(bytes: [0xFE, 0xFF])
422+ let UTF_16_LE = Data(bytes: [0xFF, 0xFE])
423+
424+ try data.withUnsafeBytes { (p:UnsafePointer<UInt8>) -> Void in
425+ let BOM = Data(buffer: UnsafeBufferPointer(start: p, count: BOM_LENGTH))
426+
427+ if BOM == UTF_16_BE { throw JSONError.foundBOMForUnsupportdEncodingUTF16BE }
428+ if BOM == UTF_16_LE { throw JSONError.foundBOMForUnsupportdEncodingUTF16LE }
429+ }
430+ }
431+
432+ func throwIfStartsWithUTF32BOM() throws {
433+ let BOM_LENGTH = 4
434+
435+ guard dataLength >= BOM_LENGTH else { return }
436+
437+ let UTF_32_BE = Data(bytes: [0x00, 0x00, 0xFE, 0xFF])
438+ let UTF_32_LE = Data(bytes: [0xFF, 0xFE, 0x00, 0x00])
439+
440+ try data.withUnsafeBytes { (p:UnsafePointer<UInt8>) -> Void in
441+ let BOM = Data(buffer: UnsafeBufferPointer(start: p, count: BOM_LENGTH))
442+
443+ if BOM == UTF_32_BE { throw JSONError.foundBOMForUnsupportdEncodingUTF32BE }
444+ if BOM == UTF_32_LE { throw JSONError.foundBOMForUnsupportdEncodingUTF32LE }
445+ }
446+ }
447+
448+ mutating func parse() throws -> Any? {
449+
450+ // throw if a UTF-16 or UTF-32 BOM is found
451+ // this is the only place where STJSON does not follow RFC 7159
452+ // which supports UTF-16 anf UTF-32, optionnaly preceeded by a BOM
453+ // STJSON only supports UTF-8
454+ try throwIfStartsWithUTF16BOM()
455+ try throwIfStartsWithUTF32BOM()
456+
457+ // skip UTF-8 BOM if present (EF BB BF)
458+ if readAndMove(.utf8BOMByte1) {
459+ guard readAndMove(.utf8BOMByte2) else { return nil}
460+ guard readAndMove(.utf8BOMByte3) else { return nil}
461+ }
462+
463+ let o = try readValue()
464+
465+ while readAndMoveWhitespace() {}
466+ guard read() == nil else {
467+ throw JSONError.extraData(i:i)
468+ }
469+ return o
470+ }
471+
472+ func myDouble(_ s:String) -> Double? {
473+
474+ return s.withCString() { startPointer -> Double in
475+
476+ var doubleEndPointer : UnsafeMutablePointer<Int8>? = nil
477+
478+ return strtod(startPointer, &doubleEndPointer)
479+ }
480+ }
481+
482+// func myInt(_ s:String) -> Int? {
483+//
484+// return s.withCString() { startPointer -> Int in
485+//
486+// var intEndPointer : UnsafeMutablePointer<Int8>? = nil
487+//
488+// return strtol(startPointer, &intEndPointer, 10)
489+// }
490+// }
491+
492+ mutating func readValue() throws -> Any? {
493+
494+ while readAndMoveWhitespace() {}
495+
496+ guard let byte = read() else {
497+ throw JSONError.cannotReadByte(i:i)
498+ }
499+
500+ switch(byte) {
501+ case ASCIIByte.arrayOpen.rawValue:
502+ return try readArray()
503+ case ASCIIByte.doubleQuote.rawValue:
504+ return try readString()
505+ case ASCIIByte.objectOpen.rawValue:
506+ return try readObject()
507+ case ASCIIByte.t.rawValue:
508+ let start_pos = i
509+ if readAndMove(.t)
510+ && readAndMove(.r)
511+ && readAndMove(.u)
512+ && readAndMove(.e) {
513+ return true
514+ }
515+ throw JSONError.foundGarbage(i: start_pos)
516+ case ASCIIByte.f.rawValue:
517+ let start_pos = i
518+ if readAndMove(.f)
519+ && readAndMove(.a)
520+ && readAndMove(.l)
521+ && readAndMove(.s)
522+ && readAndMove(.e) {
523+ return false
524+ }
525+ throw JSONError.foundGarbage(i: start_pos)
526+ case ASCIIByte.n.rawValue:
527+ let start_pos = i
528+ if readAndMove(.n)
529+ && readAndMove(.u)
530+ && readAndMove(.l)
531+ && readAndMove(.l) {
532+ return NSNull()
533+ }
534+ throw JSONError.foundGarbage(i: start_pos)
535+ default:
536+ guard let (isADouble, n) = try readNumber() else {
537+ throw JSONError.expectedNumber(i: i)
538+ }
539+
540+ guard let d = myDouble(n) else {
541+ print("n is not a double")
542+ return nil
543+ }
544+
545+ if d.isInfinite {
546+ print("d is infinite")
547+ return nil
548+ }
549+
550+ if d.isNaN {
551+ print("d in NaN")
552+ return nil
553+ }
554+
555+ if isADouble {
556+ return d
557+ }
558+
559+ if d > Double(Int.max) {
560+ return n // Int cannot represent n, so we return the string
561+ }
562+
563+ if d < Double(Int.min) {
564+ return n // Int cannot represent n, so we return the string
565+ }
566+
567+ return Int(d)
568+ }
569+ }
570+
571+ enum JSONError: Error {
572+ case cannotReadByte(i:Int)
573+ case expectedDigit(i:Int)
574+ case expectedCharacterToBeUnescaped(i:Int)
575+ case expectedValue(i:Int)
576+ case expectedString(i:Int)
577+ case expectedNumber(i:Int)
578+ case expectedSemicolon(i:Int)
579+ case expectedObjectOpen(i:Int)
580+ case expectedObjectContent(i:Int)
581+ case expectedObjectClose(i:Int)
582+ case expectedArrayOpen(i:Int)
583+ case expectedArrayClose(i:Int)
584+ case expectedDoubleQuote(i:Int)
585+ case expectedCharacter(i:Int)
586+ case cannotBuildStringFromData(i:Int)
587+ case expectedAcceptableCodepointOrEscapedSequence(i:Int)
588+ case cannotReadInt(i:Int)
589+ case extraData(i:Int)
590+ case maxParserDepthReached(depth:Int)
591+ case foundGarbage(i:Int)
592+ case expectedHighSurrogate(i:Int)
593+ case expectedLowSurrogate(i:Int)
594+ case foundSurrogatesWithInvalidCodepoint(i:Int)
595+ case foundBOMForUnsupportdEncodingUTF16BE
596+ case foundBOMForUnsupportdEncodingUTF16LE
597+ case foundBOMForUnsupportdEncodingUTF32BE
598+ case foundBOMForUnsupportdEncodingUTF32LE
599+ }
600+
601+ mutating func readNumber() throws -> (Bool, String)? {
602+
603+ var isADouble = false
604+
605+ var s = ""
606+
607+ if readAndMove(.minus) {
608+ s.append("-")
609+ }
610+
611+ guard let b = read()
612+ , b >= ASCIIByte.zero.rawValue && b <= ASCIIByte.nine.rawValue else { return nil }
613+
614+ if readAndMove(.zero) {
615+ s.append("0")
616+ } else if let d = readAndMoveInByteRange(.one, .nine) {
617+ s.append(String(d))
618+ while let d = readAndMoveInByteRange(.zero, .nine) {
619+ s.append(String(d))
620+ }
621+ }
622+
623+ if readAndMove(.dot) {
624+ isADouble = true
625+
626+ s.append(".")
627+
628+ var digitFound = false
629+
630+ while let d = readAndMoveInByteRange(.zero, .nine) {
631+ digitFound = true
632+ s.append(String(d))
633+ }
634+
635+ guard digitFound else {
636+ throw JSONError.expectedDigit(i: i)
637+ }
638+ }
639+
640+ if let x = readAndMoveByteEither([.e, .E]) {
641+ isADouble = true
642+
643+ s.append(String(x))
644+
645+ if let x = readAndMoveByteEither([.plus, .minus]) {
646+ s.append(String(x))
647+ }
648+
649+ var digitFound = false
650+
651+ while let d = readAndMoveInByteRange(.zero, .nine) {
652+ digitFound = true
653+ s.append(String(d))
654+ }
655+
656+ guard digitFound else {
657+ throw JSONError.expectedDigit(i: i)
658+ }
659+ }
660+
661+ return (isADouble, s)
662+ }
663+}
parsers/test_STJSON/STJSON/main.swiftnew file+47
@@ -0,0 +1,47 @@
1+//
2+// main.swift
3+// STJSON
4+//
5+// Created by Nicolas Seriot on 17.10.16.
6+// Copyright © 2016 ch.seriot. All rights reserved.
7+//
8+
9+import Foundation
10+
11+func main() {
12+
13+ guard ProcessInfo.processInfo.arguments.count == 2 else {
14+ let url = URL(fileURLWithPath: ProcessInfo.processInfo.arguments[0])
15+ let programName = url.lastPathComponent
16+ print("Usage: ./\(programName) file.json")
17+ exit(1)
18+ }
19+
20+ let path = ProcessInfo.processInfo.arguments[1]
21+ let url = NSURL.fileURL(withPath:path)
22+
23+ do {
24+ let data = try Data(contentsOf:url)
25+
26+ //var p = JSONParser(data: data, maxParserDepth:10, options:[.useUnicodeReplacementCharacter])
27+ var p = STJSONParser(data: data)
28+ do {
29+ let o = try p.parse()
30+
31+ guard o != nil else {
32+ exit(1)
33+ }
34+
35+ exit(0)
36+ } catch let e {
37+ print(e)
38+ exit(1)
39+ }
40+ } catch let e {
41+ print("*** CANNOT READ DATA AT \(url)")
42+ print(e)
43+ exit(1)
44+ }
45+}
46+
47+main()
parsers/test_STJSON/STJSONTests/Info.plistnew file+22
@@ -0,0 +1,22 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+<plist version="1.0">
4+<dict>
5+ <key>CFBundleDevelopmentRegion</key>
6+ <string>en</string>
7+ <key>CFBundleExecutable</key>
8+ <string>$(EXECUTABLE_NAME)</string>
9+ <key>CFBundleIdentifier</key>
10+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
11+ <key>CFBundleInfoDictionaryVersion</key>
12+ <string>6.0</string>
13+ <key>CFBundleName</key>
14+ <string>$(PRODUCT_NAME)</string>
15+ <key>CFBundlePackageType</key>
16+ <string>BNDL</string>
17+ <key>CFBundleShortVersionString</key>
18+ <string>1.0</string>
19+ <key>CFBundleVersion</key>
20+ <string>1</string>
21+</dict>
22+</plist>
parsers/test_STJSON/STJSONTests/STJSONTests.swiftnew file+92
@@ -0,0 +1,92 @@
1+//
2+// STJSONTests.swift
3+// STJSONTests
4+//
5+// Created by Nicolas Seriot on 17.10.16.
6+// Copyright © 2016 ch.seriot. All rights reserved.
7+//
8+
9+import XCTest
10+
11+class STJSONTests: XCTestCase {
12+
13+ func parseData(data:Data) -> Any? {
14+
15+ var p = STJSONParser(data: data)
16+ do {
17+ //try data.write(to: URL(fileURLWithPath: "/Users/nst/Desktop/data.json"))
18+ return try p.parse()
19+ } catch let e {
20+ print(e)
21+ return nil
22+ }
23+ }
24+
25+ func parseString(_ s:String) -> Any? {
26+ guard let data = s.data(using: String.Encoding.utf8) else { XCTFail(); return nil }
27+
28+ return parseData(data:data)
29+ }
30+
31+ func testCases() {
32+ let dir = "/Users/nst/Projects/dropbox/JSON/test_cases/"
33+
34+ guard let enumerator = FileManager.default.enumerator(atPath: dir) else {
35+ // please checkout tests from https://github.com/nst/JSONTestSuite
36+ // and setup the path in this method
37+ XCTFail()
38+ return
39+ }
40+
41+ for filename in enumerator where (filename as! NSString).pathExtension == "json" {
42+
43+ guard let s = filename as? String else { continue }
44+
45+ let url = URL(fileURLWithPath: dir+s)
46+
47+ print("*** testing \(s)")
48+
49+ do {
50+ let data = try Data(contentsOf: url)
51+
52+ let o = parseData(data:data)
53+
54+ if s.hasPrefix("n_") {
55+ if o != nil {
56+ print("STJSON\tSHOULD_HAVE_FAILED\t\(filename)")
57+ }
58+ XCTAssertNil(o)
59+ } else if s.hasPrefix("y_") {
60+ if o == nil {
61+ print("STJSON\tSHOULD_HAVE_PASSED\t\(filename)")
62+ }
63+ XCTAssertNotNil(o)
64+ } else if o == nil {
65+ print("STJSON\tIMPLEMENTATION_FAIL\t\(filename)")
66+ } else {
67+ print("STJSON\tIMPLEMENTATION_PASS\t\(filename)")
68+ }
69+ } catch let e {
70+ print(e)
71+ XCTFail()
72+ }
73+ }
74+ }
75+
76+ func testReadDouble() {
77+ XCTAssertEqual(2.0, STJSONParser(data:Data()).myDouble("2.0"))
78+ }
79+
80+ func testReadDoubleWithExponent() {
81+ XCTAssertEqual(100.0, STJSONParser(data:Data()).myDouble("10.0e1"))
82+ }
83+
84+ func testReadExponent() {
85+
86+ let i = Int(Double("20e2")!)
87+ print("***", i)
88+
89+ let o = parseString("[20e2]") as! [Double]
90+ XCTAssertEqual([2000], o)
91+ }
92+}
parsers/test_STJSON/bin/STJSONnew file

Binary file not shown.

parsers/test_TouchJSON/bin/test_TouchJSONnew file

Binary file not shown.

parsers/test_TouchJSON/test_TouchJSON.xcodeproj/project.pbxprojnew file+262
@@ -0,0 +1,262 @@
1+// !$*UTF8*$!
2+{
3+ archiveVersion = 1;
4+ classes = {
5+ };
6+ objectVersion = 46;
7+ objects = {
8+
9+/* Begin PBXBuildFile section */
10+ 03DBC2FC1DAEE58E00BA6472 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 03DBC2FB1DAEE58E00BA6472 /* main.m */; };
11+ 03DBC3041DAEE5C800BA6472 /* CJSONDeserializer.m in Sources */ = {isa = PBXBuildFile; fileRef = 03DBC3031DAEE5C800BA6472 /* CJSONDeserializer.m */; };
12+/* End PBXBuildFile section */
13+
14+/* Begin PBXCopyFilesBuildPhase section */
15+ 03DBC2F61DAEE58E00BA6472 /* CopyFiles */ = {
16+ isa = PBXCopyFilesBuildPhase;
17+ buildActionMask = 2147483647;
18+ dstPath = /usr/share/man/man1/;
19+ dstSubfolderSpec = 0;
20+ files = (
21+ );
22+ runOnlyForDeploymentPostprocessing = 1;
23+ };
24+/* End PBXCopyFilesBuildPhase section */
25+
26+/* Begin PBXFileReference section */
27+ 03DBC2F81DAEE58E00BA6472 /* test_TouchJSON */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = test_TouchJSON; sourceTree = BUILT_PRODUCTS_DIR; };
28+ 03DBC2FB1DAEE58E00BA6472 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
29+ 03DBC3021DAEE5A300BA6472 /* CJSONDeserializer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CJSONDeserializer.h; sourceTree = "<group>"; };
30+ 03DBC3031DAEE5C800BA6472 /* CJSONDeserializer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CJSONDeserializer.m; sourceTree = "<group>"; };
31+/* End PBXFileReference section */
32+
33+/* Begin PBXFrameworksBuildPhase section */
34+ 03DBC2F51DAEE58E00BA6472 /* Frameworks */ = {
35+ isa = PBXFrameworksBuildPhase;
36+ buildActionMask = 2147483647;
37+ files = (
38+ );
39+ runOnlyForDeploymentPostprocessing = 0;
40+ };
41+/* End PBXFrameworksBuildPhase section */
42+
43+/* Begin PBXGroup section */
44+ 03DBC2EF1DAEE58E00BA6472 = {
45+ isa = PBXGroup;
46+ children = (
47+ 03DBC2FA1DAEE58E00BA6472 /* test_TouchJSON */,
48+ 03DBC2F91DAEE58E00BA6472 /* Products */,
49+ );
50+ sourceTree = "<group>";
51+ };
52+ 03DBC2F91DAEE58E00BA6472 /* Products */ = {
53+ isa = PBXGroup;
54+ children = (
55+ 03DBC2F81DAEE58E00BA6472 /* test_TouchJSON */,
56+ );
57+ name = Products;
58+ sourceTree = "<group>";
59+ };
60+ 03DBC2FA1DAEE58E00BA6472 /* test_TouchJSON */ = {
61+ isa = PBXGroup;
62+ children = (
63+ 03DBC3021DAEE5A300BA6472 /* CJSONDeserializer.h */,
64+ 03DBC3031DAEE5C800BA6472 /* CJSONDeserializer.m */,
65+ 03DBC2FB1DAEE58E00BA6472 /* main.m */,
66+ );
67+ path = test_TouchJSON;
68+ sourceTree = "<group>";
69+ };
70+/* End PBXGroup section */
71+
72+/* Begin PBXNativeTarget section */
73+ 03DBC2F71DAEE58E00BA6472 /* test_TouchJSON */ = {
74+ isa = PBXNativeTarget;
75+ buildConfigurationList = 03DBC2FF1DAEE58E00BA6472 /* Build configuration list for PBXNativeTarget "test_TouchJSON" */;
76+ buildPhases = (
77+ 03DBC2F41DAEE58E00BA6472 /* Sources */,
78+ 03DBC2F51DAEE58E00BA6472 /* Frameworks */,
79+ 03DBC2F61DAEE58E00BA6472 /* CopyFiles */,
80+ );
81+ buildRules = (
82+ );
83+ dependencies = (
84+ );
85+ name = test_TouchJSON;
86+ productName = test_TouchJSON;
87+ productReference = 03DBC2F81DAEE58E00BA6472 /* test_TouchJSON */;
88+ productType = "com.apple.product-type.tool";
89+ };
90+/* End PBXNativeTarget section */
91+
92+/* Begin PBXProject section */
93+ 03DBC2F01DAEE58E00BA6472 /* Project object */ = {
94+ isa = PBXProject;
95+ attributes = {
96+ LastUpgradeCheck = 0800;
97+ ORGANIZATIONNAME = "Nicolas Seriot";
98+ TargetAttributes = {
99+ 03DBC2F71DAEE58E00BA6472 = {
100+ CreatedOnToolsVersion = 8.0;
101+ DevelopmentTeam = VBYRKYS73S;
102+ ProvisioningStyle = Automatic;
103+ };
104+ };
105+ };
106+ buildConfigurationList = 03DBC2F31DAEE58E00BA6472 /* Build configuration list for PBXProject "test_TouchJSON" */;
107+ compatibilityVersion = "Xcode 3.2";
108+ developmentRegion = English;
109+ hasScannedForEncodings = 0;
110+ knownRegions = (
111+ en,
112+ );
113+ mainGroup = 03DBC2EF1DAEE58E00BA6472;
114+ productRefGroup = 03DBC2F91DAEE58E00BA6472 /* Products */;
115+ projectDirPath = "";
116+ projectRoot = "";
117+ targets = (
118+ 03DBC2F71DAEE58E00BA6472 /* test_TouchJSON */,
119+ );
120+ };
121+/* End PBXProject section */
122+
123+/* Begin PBXSourcesBuildPhase section */
124+ 03DBC2F41DAEE58E00BA6472 /* Sources */ = {
125+ isa = PBXSourcesBuildPhase;
126+ buildActionMask = 2147483647;
127+ files = (
128+ 03DBC3041DAEE5C800BA6472 /* CJSONDeserializer.m in Sources */,
129+ 03DBC2FC1DAEE58E00BA6472 /* main.m in Sources */,
130+ );
131+ runOnlyForDeploymentPostprocessing = 0;
132+ };
133+/* End PBXSourcesBuildPhase section */
134+
135+/* Begin XCBuildConfiguration section */
136+ 03DBC2FD1DAEE58E00BA6472 /* Debug */ = {
137+ isa = XCBuildConfiguration;
138+ buildSettings = {
139+ ALWAYS_SEARCH_USER_PATHS = NO;
140+ CLANG_ANALYZER_NONNULL = YES;
141+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
142+ CLANG_CXX_LIBRARY = "libc++";
143+ CLANG_ENABLE_MODULES = YES;
144+ CLANG_ENABLE_OBJC_ARC = YES;
145+ CLANG_WARN_BOOL_CONVERSION = YES;
146+ CLANG_WARN_CONSTANT_CONVERSION = YES;
147+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
148+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
149+ CLANG_WARN_EMPTY_BODY = YES;
150+ CLANG_WARN_ENUM_CONVERSION = YES;
151+ CLANG_WARN_INFINITE_RECURSION = YES;
152+ CLANG_WARN_INT_CONVERSION = YES;
153+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
154+ CLANG_WARN_SUSPICIOUS_MOVES = YES;
155+ CLANG_WARN_UNREACHABLE_CODE = YES;
156+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
157+ CODE_SIGN_IDENTITY = "-";
158+ COPY_PHASE_STRIP = NO;
159+ DEBUG_INFORMATION_FORMAT = dwarf;
160+ ENABLE_STRICT_OBJC_MSGSEND = YES;
161+ ENABLE_TESTABILITY = YES;
162+ GCC_C_LANGUAGE_STANDARD = gnu99;
163+ GCC_DYNAMIC_NO_PIC = NO;
164+ GCC_NO_COMMON_BLOCKS = YES;
165+ GCC_OPTIMIZATION_LEVEL = 0;
166+ GCC_PREPROCESSOR_DEFINITIONS = (
167+ "DEBUG=1",
168+ "$(inherited)",
169+ );
170+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
171+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
172+ GCC_WARN_UNDECLARED_SELECTOR = YES;
173+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
174+ GCC_WARN_UNUSED_FUNCTION = YES;
175+ GCC_WARN_UNUSED_VARIABLE = YES;
176+ MACOSX_DEPLOYMENT_TARGET = 10.12;
177+ MTL_ENABLE_DEBUG_INFO = YES;
178+ ONLY_ACTIVE_ARCH = YES;
179+ SDKROOT = macosx;
180+ };
181+ name = Debug;
182+ };
183+ 03DBC2FE1DAEE58E00BA6472 /* Release */ = {
184+ isa = XCBuildConfiguration;
185+ buildSettings = {
186+ ALWAYS_SEARCH_USER_PATHS = NO;
187+ CLANG_ANALYZER_NONNULL = YES;
188+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
189+ CLANG_CXX_LIBRARY = "libc++";
190+ CLANG_ENABLE_MODULES = YES;
191+ CLANG_ENABLE_OBJC_ARC = YES;
192+ CLANG_WARN_BOOL_CONVERSION = YES;
193+ CLANG_WARN_CONSTANT_CONVERSION = YES;
194+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
195+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
196+ CLANG_WARN_EMPTY_BODY = YES;
197+ CLANG_WARN_ENUM_CONVERSION = YES;
198+ CLANG_WARN_INFINITE_RECURSION = YES;
199+ CLANG_WARN_INT_CONVERSION = YES;
200+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
201+ CLANG_WARN_SUSPICIOUS_MOVES = YES;
202+ CLANG_WARN_UNREACHABLE_CODE = YES;
203+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
204+ CODE_SIGN_IDENTITY = "-";
205+ COPY_PHASE_STRIP = NO;
206+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
207+ ENABLE_NS_ASSERTIONS = NO;
208+ ENABLE_STRICT_OBJC_MSGSEND = YES;
209+ GCC_C_LANGUAGE_STANDARD = gnu99;
210+ GCC_NO_COMMON_BLOCKS = YES;
211+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
212+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
213+ GCC_WARN_UNDECLARED_SELECTOR = YES;
214+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
215+ GCC_WARN_UNUSED_FUNCTION = YES;
216+ GCC_WARN_UNUSED_VARIABLE = YES;
217+ MACOSX_DEPLOYMENT_TARGET = 10.12;
218+ MTL_ENABLE_DEBUG_INFO = NO;
219+ SDKROOT = macosx;
220+ };
221+ name = Release;
222+ };
223+ 03DBC3001DAEE58E00BA6472 /* Debug */ = {
224+ isa = XCBuildConfiguration;
225+ buildSettings = {
226+ DEVELOPMENT_TEAM = VBYRKYS73S;
227+ PRODUCT_NAME = "$(TARGET_NAME)";
228+ };
229+ name = Debug;
230+ };
231+ 03DBC3011DAEE58E00BA6472 /* Release */ = {
232+ isa = XCBuildConfiguration;
233+ buildSettings = {
234+ DEVELOPMENT_TEAM = VBYRKYS73S;
235+ PRODUCT_NAME = "$(TARGET_NAME)";
236+ };
237+ name = Release;
238+ };
239+/* End XCBuildConfiguration section */
240+
241+/* Begin XCConfigurationList section */
242+ 03DBC2F31DAEE58E00BA6472 /* Build configuration list for PBXProject "test_TouchJSON" */ = {
243+ isa = XCConfigurationList;
244+ buildConfigurations = (
245+ 03DBC2FD1DAEE58E00BA6472 /* Debug */,
246+ 03DBC2FE1DAEE58E00BA6472 /* Release */,
247+ );
248+ defaultConfigurationIsVisible = 0;
249+ defaultConfigurationName = Release;
250+ };
251+ 03DBC2FF1DAEE58E00BA6472 /* Build configuration list for PBXNativeTarget "test_TouchJSON" */ = {
252+ isa = XCConfigurationList;
253+ buildConfigurations = (
254+ 03DBC3001DAEE58E00BA6472 /* Debug */,
255+ 03DBC3011DAEE58E00BA6472 /* Release */,
256+ );
257+ defaultConfigurationIsVisible = 0;
258+ };
259+/* End XCConfigurationList section */
260+ };
261+ rootObject = 03DBC2F01DAEE58E00BA6472 /* Project object */;
262+}
parsers/test_TouchJSON/test_TouchJSON.xcodeproj/project.xcworkspace/contents.xcworkspacedatanew file+7
@@ -0,0 +1,7 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<Workspace
3+ version = "1.0">
4+ <FileRef
5+ location = "self:test_TouchJSON.xcodeproj">
6+ </FileRef>
7+</Workspace>
parsers/test_TouchJSON/test_TouchJSON.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstatenew file

Binary file not shown.

parsers/test_TouchJSON/test_TouchJSON.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test_TouchJSON.xcschemenew file+97
@@ -0,0 +1,97 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<Scheme
3+ LastUpgradeVersion = "0800"
4+ version = "1.3">
5+ <BuildAction
6+ parallelizeBuildables = "YES"
7+ buildImplicitDependencies = "YES">
8+ <BuildActionEntries>
9+ <BuildActionEntry
10+ buildForTesting = "YES"
11+ buildForRunning = "YES"
12+ buildForProfiling = "YES"
13+ buildForArchiving = "YES"
14+ buildForAnalyzing = "YES">
15+ <BuildableReference
16+ BuildableIdentifier = "primary"
17+ BlueprintIdentifier = "03DBC2F71DAEE58E00BA6472"
18+ BuildableName = "test_TouchJSON"
19+ BlueprintName = "test_TouchJSON"
20+ ReferencedContainer = "container:test_TouchJSON.xcodeproj">
21+ </BuildableReference>
22+ </BuildActionEntry>
23+ </BuildActionEntries>
24+ </BuildAction>
25+ <TestAction
26+ buildConfiguration = "Debug"
27+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
28+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
29+ shouldUseLaunchSchemeArgsEnv = "YES">
30+ <Testables>
31+ </Testables>
32+ <MacroExpansion>
33+ <BuildableReference
34+ BuildableIdentifier = "primary"
35+ BlueprintIdentifier = "03DBC2F71DAEE58E00BA6472"
36+ BuildableName = "test_TouchJSON"
37+ BlueprintName = "test_TouchJSON"
38+ ReferencedContainer = "container:test_TouchJSON.xcodeproj">
39+ </BuildableReference>
40+ </MacroExpansion>
41+ <AdditionalOptions>
42+ </AdditionalOptions>
43+ </TestAction>
44+ <LaunchAction
45+ buildConfiguration = "Debug"
46+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
47+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
48+ launchStyle = "0"
49+ useCustomWorkingDirectory = "NO"
50+ ignoresPersistentStateOnLaunch = "NO"
51+ debugDocumentVersioning = "YES"
52+ debugServiceExtension = "internal"
53+ allowLocationSimulation = "YES">
54+ <BuildableProductRunnable
55+ runnableDebuggingMode = "0">
56+ <BuildableReference
57+ BuildableIdentifier = "primary"
58+ BlueprintIdentifier = "03DBC2F71DAEE58E00BA6472"
59+ BuildableName = "test_TouchJSON"
60+ BlueprintName = "test_TouchJSON"
61+ ReferencedContainer = "container:test_TouchJSON.xcodeproj">
62+ </BuildableReference>
63+ </BuildableProductRunnable>
64+ <CommandLineArguments>
65+ <CommandLineArgument
66+ argument = "/Users/nst/Projects/dropbox/JSON/test_cases_content/object_same_key_unclear_values.json"
67+ isEnabled = "YES">
68+ </CommandLineArgument>
69+ </CommandLineArguments>
70+ <AdditionalOptions>
71+ </AdditionalOptions>
72+ </LaunchAction>
73+ <ProfileAction
74+ buildConfiguration = "Release"
75+ shouldUseLaunchSchemeArgsEnv = "YES"
76+ savedToolIdentifier = ""
77+ useCustomWorkingDirectory = "NO"
78+ debugDocumentVersioning = "YES">
79+ <BuildableProductRunnable
80+ runnableDebuggingMode = "0">
81+ <BuildableReference
82+ BuildableIdentifier = "primary"
83+ BlueprintIdentifier = "03DBC2F71DAEE58E00BA6472"
84+ BuildableName = "test_TouchJSON"
85+ BlueprintName = "test_TouchJSON"
86+ ReferencedContainer = "container:test_TouchJSON.xcodeproj">
87+ </BuildableReference>
88+ </BuildableProductRunnable>
89+ </ProfileAction>
90+ <AnalyzeAction
91+ buildConfiguration = "Debug">
92+ </AnalyzeAction>
93+ <ArchiveAction
94+ buildConfiguration = "Release"
95+ revealArchiveInOrganizer = "YES">
96+ </ArchiveAction>
97+</Scheme>
parsers/test_TouchJSON/test_TouchJSON.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plistnew file+22
@@ -0,0 +1,22 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+<plist version="1.0">
4+<dict>
5+ <key>SchemeUserState</key>
6+ <dict>
7+ <key>test_TouchJSON.xcscheme</key>
8+ <dict>
9+ <key>orderHint</key>
10+ <integer>0</integer>
11+ </dict>
12+ </dict>
13+ <key>SuppressBuildableAutocreation</key>
14+ <dict>
15+ <key>03DBC2F71DAEE58E00BA6472</key>
16+ <dict>
17+ <key>primary</key>
18+ <true/>
19+ </dict>
20+ </dict>
21+</dict>
22+</plist>
parsers/test_TouchJSON/test_TouchJSON/CJSONDeserializer.hnew file+96
@@ -0,0 +1,96 @@
1+//
2+// CJSONDeserializer.h
3+// TouchCode
4+//
5+// Created by Jonathan Wight on 12/15/2005.
6+// Copyright 2005 toxicsoftware.com. All rights reserved.
7+//
8+// Permission is hereby granted, free of charge, to any person
9+// obtaining a copy of this software and associated documentation
10+// files (the "Software"), to deal in the Software without
11+// restriction, including without limitation the rights to use,
12+// copy, modify, merge, publish, distribute, sublicense, and/or sell
13+// copies of the Software, and to permit persons to whom the
14+// Software is furnished to do so, subject to the following
15+// conditions:
16+//
17+// The above copyright notice and this permission notice shall be
18+// included in all copies or substantial portions of the Software.
19+//
20+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27+// OTHER DEALINGS IN THE SOFTWARE.
28+//
29+
30+#import <Foundation/Foundation.h>
31+
32+extern NSString *const kJSONDeserializerErrorDomain /* = @"CJSONDeserializerErrorDomain" */;
33+
34+typedef enum {
35+
36+ // Fundamental scanning errors
37+ kJSONDeserializerErrorCode_NothingToScan = -11,
38+ kJSONDeserializerErrorCode_CouldNotDecodeData = -12,
39+ kJSONDeserializerErrorCode_CouldNotScanObject = -15,
40+ kJSONDeserializerErrorCode_ScanningFragmentsNotAllowed = -16,
41+ kJSONDeserializerErrorCode_DidNotConsumeAllData = -17,
42+ kJSONDeserializerErrorCode_FailedToCreateObject = -18,
43+
44+ // Dictionary scanning
45+ kJSONDeserializerErrorCode_DictionaryStartCharacterMissing = -101,
46+ kJSONDeserializerErrorCode_DictionaryKeyScanFailed = -102,
47+ kJSONDeserializerErrorCode_DictionaryKeyNotTerminated = -103,
48+ kJSONDeserializerErrorCode_DictionaryValueScanFailed = -104,
49+ kJSONDeserializerErrorCode_DictionaryNotTerminated = -106,
50+
51+ // Array scanning
52+ kJSONDeserializerErrorCode_ArrayStartCharacterMissing = -201,
53+ kJSONDeserializerErrorCode_ArrayValueScanFailed = -202,
54+ kJSONDeserializerErrorCode_ArrayValueIsNull = -203,
55+ kJSONDeserializerErrorCode_ArrayNotTerminated = -204,
56+
57+ // String scanning
58+ kJSONDeserializerErrorCode_StringNotStartedWithBackslash = -301,
59+ kJSONDeserializerErrorCode_StringUnicodeNotDecoded = -302,
60+ kJSONDeserializerErrorCode_StringUnknownEscapeCode = -303,
61+ kJSONDeserializerErrorCode_StringNotTerminated = -304,
62+ kJSONDeserializerErrorCode_StringBadEscaping = -305,
63+ kJSONDeserializerErrorCode_StringCouldNotBeCreated = -306,
64+
65+ // Number scanning
66+ kJSONDeserializerErrorCode_NumberNotScannable = -401
67+
68+} EJSONDeserializerErrorCode;
69+
70+enum {
71+ // The first three flags map to the corresponding NSJSONSerialization flags.
72+ kJSONDeserializationOptions_MutableContainers = (1UL << 0),
73+ kJSONDeserializationOptions_MutableLeaves = (1UL << 1),
74+ kJSONDeserializationOptions_AllowFragments = (1UL << 2),
75+ kJSONDeserializationOptions_LaxEscapeCodes = (1UL << 3),
76+ kJSONDeserializationOptions_Default = kJSONDeserializationOptions_MutableContainers,
77+};
78+typedef NSUInteger EJSONDeserializationOptions;
79+
80+@interface CJSONDeserializer : NSObject
81+
82+/// Object to return instead when a null encountered in the JSON. Defaults to NSNull. Setting to null causes the deserializer to skip null values.
83+@property (readwrite, nonatomic, strong) id nullObject;
84+
85+/// JSON must be encoded in Unicode (UTF-8, UTF-16 or UTF-32). Use this if you expect to get the JSON in another encoding.
86+
87+@property (readwrite, nonatomic, assign) EJSONDeserializationOptions options;
88+
89++ (CJSONDeserializer *)deserializer;
90+
91+- (id)deserialize:(NSData *)inData error:(NSError **)outError;
92+
93+- (id)deserializeAsDictionary:(NSData *)inData error:(NSError **)outError;
94+- (id)deserializeAsArray:(NSData *)inData error:(NSError **)outError;
95+
96+@end
parsers/test_TouchJSON/test_TouchJSON/CJSONDeserializer.mnew file+1240

This diff is too big to show here.

parsers/test_TouchJSON/test_TouchJSON/main.mnew file+25

This diff is too big to show here.

parsers/test_cJSON/bin/test-cJSONnew file

Binary file not shown.

parsers/test_cJSON/cJSON.cnew file+754

This diff is too big to show here.

parsers/test_cJSON/cJSON.hnew file+153

This diff is too big to show here.

parsers/test_cJSON/test-cJSON.xcodeproj/project.pbxprojnew file+257

This diff is too big to show here.

parsers/test_cJSON/test-cJSON.xcodeproj/project.xcworkspace/contents.xcworkspacedatanew file+7

This diff is too big to show here.

parsers/test_cJSON/test-cJSON.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstatenew file

Binary file not shown.

parsers/test_cJSON/test-cJSON.xcodeproj/xcuserdata/nst.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlistnew file+5

This diff is too big to show here.

parsers/test_cJSON/test-cJSON.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test-cJSON.xcschemenew file+91

This diff is too big to show here.

parsers/test_cJSON/test-cJSON.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plistnew file+22

This diff is too big to show here.

parsers/test_cJSON/test-cJSON/main.cnew file+69

This diff is too big to show here.

parsers/test_ccan_json/bin/test_ccannew file

Binary file not shown.

parsers/test_ccan_json/json/_test/common.hnew file+18

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_10.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_101.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_11.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_12.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_125.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_127.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_13.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_136.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_137.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_139.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_14.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_140.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_145.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_147.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_149.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_15.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_150.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_151.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_153.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_154.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_155.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_156.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_157.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_158.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_159.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_16.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_160.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_161.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_162.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_163.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_164.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_165.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_169.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_17.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_171.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_172.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_173.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_175.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_176.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_177.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_178.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_179.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_18.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_180.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_181.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_183.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_184.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_185.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_186.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_187.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_188.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_189.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_19.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_190.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_191.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_192.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_193.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_194.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_195.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_197.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_198.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_199.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_2.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_20.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_200.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_201.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_202.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_203.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_204.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_205.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_206.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_207.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_208.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_209.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_21.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_210.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_211.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_212.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_213.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_214.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_216.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_217.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_218.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_219.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_22.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_220.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_221.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_222.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_223.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_23.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_24.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_25.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_26.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_27.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_28.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_29.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_3.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_30.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_31.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_32.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_33.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_34.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_35.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_36.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_37.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_4.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_40.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_44.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_46.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_5.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_54.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_55.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_59.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_6.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_63.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_64.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_66.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_69.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_7.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_77.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_78.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_79.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_8.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_80.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_81.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_82.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_83.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_85.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_86.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_87.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_9.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/n_91.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_100.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_102.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_103.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_104.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_105.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_106.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_107.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_108.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_109.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_110.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_111.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_112.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_113.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_114.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_115.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_116.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_117.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_118.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_119.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_120.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_121.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_122.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_123.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_124.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_126.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_128.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_129.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_130.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_131.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_132.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_133.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_134.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_135.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_138.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_141.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_142.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_143.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_144.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_146.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_148.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_152.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_166.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_167.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_168.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_170.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_174.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_182.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_196.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_215.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_38.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_39.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_41.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_42.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_43.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_45.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_47.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_48.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_49.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_50.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_51.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_52.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_53.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_56.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_57.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_58.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_60.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_61.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_62.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_65.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_67.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_68.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_70.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_71.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_72.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_73.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_74.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_75.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_76.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_84.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_88.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_89.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_90.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_92.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_93.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_94.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_95.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_96.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_97.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_98.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/nst_files/y_99.jsonnew file+1

This diff is too big to show here.

parsers/test_ccan_json/json/_test/run-construction.cnew file+191

This diff is too big to show here.

parsers/test_ccan_json/json/_test/run-decode-encode.cnew file+77

This diff is too big to show here.

parsers/test_ccan_json/json/_test/run-stringify.cnew file+108

This diff is too big to show here.

parsers/test_ccan_json/json/_test/run-validate.cnew file+49

This diff is too big to show here.

parsers/test_ccan_json/json/_test/test-stringsnew file+224

This diff is too big to show here.

parsers/test_ccan_json/json/_test/test-strings-reencodednew file+90

This diff is too big to show here.

parsers/test_ccan_json/json/_test/x.pynew file+21

This diff is too big to show here.

parsers/test_ccan_json/json/json.cnew file+1381

This diff is too big to show here.

parsers/test_ccan_json/json/json.hnew file+117

This diff is too big to show here.

parsers/test_ccan_json/test_ccan/test_ccan.xcodeproj/project.pbxprojnew file+262

This diff is too big to show here.

parsers/test_ccan_json/test_ccan/test_ccan.xcodeproj/project.xcworkspace/contents.xcworkspacedatanew file+7

This diff is too big to show here.

parsers/test_ccan_json/test_ccan/test_ccan.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstatenew file

Binary file not shown.

parsers/test_ccan_json/test_ccan/test_ccan.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test_ccan.xcschemenew file+91

This diff is too big to show here.

parsers/test_ccan_json/test_ccan/test_ccan.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plistnew file+22

This diff is too big to show here.

parsers/test_ccan_json/test_ccan/test_ccan/main.cnew file+44

This diff is too big to show here.

parsers/test_dkjson.luanew file+25

This diff is too big to show here.

parsers/test_go/test_jsonnew file

Binary file not shown.

parsers/test_go/test_json.gonew file+30

This diff is too big to show here.

parsers/test_jansson/bin/test_janssonnew file

Binary file not shown.

parsers/test_jansson/dump.cnew file+467

This diff is too big to show here.

parsers/test_jansson/error.cnew file+63

This diff is too big to show here.

parsers/test_jansson/hashtable.cnew file+356

This diff is too big to show here.

parsers/test_jansson/hashtable.hnew file+184

This diff is too big to show here.

parsers/test_jansson/hashtable_seed.cnew file+277

This diff is too big to show here.

parsers/test_jansson/jansson.hnew file+298

This diff is too big to show here.

parsers/test_jansson/jansson_config.hnew file+43

This diff is too big to show here.

parsers/test_jansson/jansson_private.hnew file+109

This diff is too big to show here.

parsers/test_jansson/load.cnew file+1110

This diff is too big to show here.

parsers/test_jansson/lookup3.hnew file+381

This diff is too big to show here.

parsers/test_jansson/memory.cnew file+69

This diff is too big to show here.

parsers/test_jansson/pack_unpack.cnew file+871

This diff is too big to show here.

parsers/test_jansson/strbuffer.cnew file+111

This diff is too big to show here.

parsers/test_jansson/strbuffer.hnew file+34

This diff is too big to show here.

parsers/test_jansson/strconv.cnew file+145

This diff is too big to show here.

parsers/test_jansson/test_jansson.xcodeproj/project.pbxprojnew file+309

This diff is too big to show here.

parsers/test_jansson/test_jansson.xcodeproj/project.xcworkspace/contents.xcworkspacedatanew file+7

This diff is too big to show here.

parsers/test_jansson/test_jansson.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstatenew file

Binary file not shown.

parsers/test_jansson/test_jansson.xcodeproj/xcuserdata/nst.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlistnew file+5

This diff is too big to show here.

parsers/test_jansson/test_jansson.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test_jansson.xcschemenew file+91

This diff is too big to show here.

parsers/test_jansson/test_jansson.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plistnew file+22

This diff is too big to show here.

parsers/test_jansson/test_jansson/main.cnew file+208

This diff is too big to show here.

parsers/test_jansson/utf.cnew file+187

This diff is too big to show here.

parsers/test_jansson/utf.hnew file+27

This diff is too big to show here.

parsers/test_jansson/value.cnew file+1048

This diff is too big to show here.

parsers/test_jsmn/bin/test_jsmnnew file

Binary file not shown.

parsers/test_jsmn/jsmn.cnew file+311

This diff is too big to show here.

parsers/test_jsmn/jsmn.hnew file+76

This diff is too big to show here.

parsers/test_jsmn/test_jsmn/test_jsmn.xcodeproj/project.pbxprojnew file+253

This diff is too big to show here.

parsers/test_jsmn/test_jsmn/test_jsmn.xcodeproj/project.xcworkspace/contents.xcworkspacedatanew file+7

This diff is too big to show here.

parsers/test_jsmn/test_jsmn/test_jsmn.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstatenew file

Binary file not shown.

parsers/test_jsmn/test_jsmn/test_jsmn.xcodeproj/xcuserdata/nst.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlistnew file+23

This diff is too big to show here.

parsers/test_jsmn/test_jsmn/test_jsmn.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test_jsmn.xcschemenew file+101

This diff is too big to show here.

parsers/test_jsmn/test_jsmn/test_jsmn.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plistnew file+22

This diff is too big to show here.

parsers/test_jsmn/test_jsmn/test_jsmn/main.cnew file+50

This diff is too big to show here.

parsers/test_json-jq.pynew file+34

This diff is too big to show here.

parsers/test_json-parser/bin/test_json-parsernew file

Binary file not shown.

parsers/test_json-parser/test_json-parser.xcodeproj/project.pbxprojnew file+258

This diff is too big to show here.

parsers/test_json-parser/test_json-parser.xcodeproj/project.xcworkspace/contents.xcworkspacedatanew file+7

This diff is too big to show here.

parsers/test_json-parser/test_json-parser.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstatenew file

Binary file not shown.

parsers/test_json-parser/test_json-parser.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/test_json-parser.xcschemenew file+91

This diff is too big to show here.

parsers/test_json-parser/test_json-parser.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plistnew file+22

This diff is too big to show here.

parsers/test_json-parser/test_json-parser/json.cnew file+1011

This diff is too big to show here.

parsers/test_json-parser/test_json-parser/json.hnew file+283

This diff is too big to show here.

parsers/test_json-parser/test_json-parser/main.cnew file+66

This diff is too big to show here.

parsers/test_json-rust/Cargo.locknew file+14

This diff is too big to show here.

parsers/test_json-rust/Cargo.tomlnew file+7

This diff is too big to show here.

parsers/test_json-rust/READMEnew file+2

This diff is too big to show here.

parsers/test_json-rust/src/main.rsnew file+42

This diff is too big to show here.

parsers/test_json-rust/target/debug/.cargo-locknew file

No changes to the content.

parsers/test_json-rust/target/debug/.fingerprint/json-74a82b4ec4439e90/dep-lib-jsonnew file

Binary file not shown.

parsers/test_json-rust/target/debug/.fingerprint/json-74a82b4ec4439e90/lib-jsonnew file+1

This diff is too big to show here.

parsers/test_json-rust/target/debug/.fingerprint/json-74a82b4ec4439e90/lib-json.jsonnew file+1

This diff is too big to show here.

parsers/test_json-rust/target/debug/.fingerprint/tj-b5d63a9d8da2968e/bin-tjnew file+1

This diff is too big to show here.

parsers/test_json-rust/target/debug/.fingerprint/tj-b5d63a9d8da2968e/bin-tj.jsonnew file+1

This diff is too big to show here.

parsers/test_json-rust/target/debug/.fingerprint/tj-b5d63a9d8da2968e/dep-bin-tjnew file

Binary file not shown.

parsers/test_json-rust/target/debug/.fingerprint/tj-bb890ae6f101bb25/bin-tjnew file+1

This diff is too big to show here.

parsers/test_json-rust/target/debug/.fingerprint/tj-bb890ae6f101bb25/bin-tj.jsonnew file+1

This diff is too big to show here.

parsers/test_json-rust/target/debug/.fingerprint/tj-bb890ae6f101bb25/dep-bin-tjnew file

Binary file not shown.

parsers/test_json-rust/target/debug/.fingerprint/tj-bf24d0bdc8d0f4d6/bin-tjnew file+1

This diff is too big to show here.

parsers/test_json-rust/target/debug/.fingerprint/tj-bf24d0bdc8d0f4d6/bin-tj.jsonnew file+1

This diff is too big to show here.

parsers/test_json-rust/target/debug/.fingerprint/tj-bf24d0bdc8d0f4d6/dep-bin-tjnew file

Binary file not shown.

parsers/test_json-rust/target/debug/deps/libjson-6bbf4c11dd6d7c25.rlibnew file

Binary file not shown.

parsers/test_json-rust/target/debug/tjnew file

Binary file not shown.

parsers/test_json-rust/target/debug/tj.dSYM/Contents/Info.plistnew file+20

This diff is too big to show here.

parsers/test_json-rust/target/debug/tj.dSYM/Contents/Resources/DWARF/tjnew file

Binary file not shown.

parsers/test_json-rustc_serialize/rj/Cargo.locknew file+14

This diff is too big to show here.

parsers/test_json-rustc_serialize/rj/Cargo.tomlnew file+7

This diff is too big to show here.

parsers/test_json-rustc_serialize/rj/READMEnew file+2

This diff is too big to show here.

parsers/test_json-rustc_serialize/rj/src/main.rsnew file+32

This diff is too big to show here.

parsers/test_json-rustc_serialize/rj/target/debug/.cargo-locknew file

No changes to the content.

parsers/test_json-rustc_serialize/rj/target/debug/.fingerprint/rj-8f8b750d20f3bf10/bin-rjnew file+1

This diff is too big to show here.

parsers/test_json-rustc_serialize/rj/target/debug/.fingerprint/rj-8f8b750d20f3bf10/bin-rj.jsonnew file+1

This diff is too big to show here.

parsers/test_json-rustc_serialize/rj/target/debug/.fingerprint/rj-8f8b750d20f3bf10/dep-bin-rjnew file

Binary file not shown.

parsers/test_json-rustc_serialize/rj/target/debug/.fingerprint/rj-da0f8f63b87cf531/bin-rjnew file+1

This diff is too big to show here.

parsers/test_json-rustc_serialize/rj/target/debug/.fingerprint/rj-da0f8f63b87cf531/bin-rj.jsonnew file+1

This diff is too big to show here.

parsers/test_json-rustc_serialize/rj/target/debug/.fingerprint/rj-da0f8f63b87cf531/dep-bin-rjnew file

Binary file not shown.

parsers/test_json-rustc_serialize/rj/target/debug/.fingerprint/rustc-serialize-80c565222c5ccdbb/dep-lib-rustc-serializenew file

Binary file not shown.

parsers/test_json-rustc_serialize/rj/target/debug/.fingerprint/rustc-serialize-80c565222c5ccdbb/lib-rustc-serializenew file+1

This diff is too big to show here.

parsers/test_json-rustc_serialize/rj/target/debug/.fingerprint/rustc-serialize-80c565222c5ccdbb/lib-rustc-serialize.jsonnew file+1

This diff is too big to show here.

parsers/test_json-rustc_serialize/rj/target/debug/deps/librustc_serialize-3561541d79c18212.rlibnew file

Binary file not shown.

parsers/test_json-rustc_serialize/rj/target/debug/rjnew file

Binary file not shown.

parsers/test_json-rustc_serialize/rj/target/debug/rj.dSYM/Contents/Info.plistnew file+20

This diff is too big to show here.

parsers/test_json-rustc_serialize/rj/target/debug/rj.dSYM/Contents/Resources/DWARF/rjnew file

Binary file not shown.

parsers/test_json.jsnew file+13

This diff is too big to show here.

parsers/test_json.phpnew file+21

This diff is too big to show here.

parsers/test_json.plnew file+32

This diff is too big to show here.

parsers/test_json.pynew file+39

This diff is too big to show here.

parsers/test_json.rbnew file+23

This diff is too big to show here.

parsers/test_jsonChecker/bin/jsonCheckernew file

Binary file not shown.

parsers/test_jsonChecker/jsonChecker/JSON_checker.cnew file+400

This diff is too big to show here.

parsers/test_jsonChecker/jsonChecker/JSON_checker.hnew file+13

This diff is too big to show here.

parsers/test_jsonChecker/jsonChecker/jsonChecker.xcodeproj/project.pbxprojnew file+253

This diff is too big to show here.

parsers/test_jsonChecker/jsonChecker/jsonChecker.xcodeproj/project.xcworkspace/contents.xcworkspacedatanew file+7

This diff is too big to show here.

parsers/test_jsonChecker/jsonChecker/jsonChecker.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstatenew file

Binary file not shown.

parsers/test_jsonChecker/jsonChecker/jsonChecker.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/jsonChecker.xcschemenew file+91

This diff is too big to show here.

parsers/test_jsonChecker/jsonChecker/jsonChecker.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plistnew file+22

This diff is too big to show here.

parsers/test_jsonChecker/jsonChecker/jsonChecker/main.cnew file+53

This diff is too big to show here.

parsers/test_jsonChecker2/FSM.rtfnew file+57

This diff is too big to show here.

parsers/test_jsonChecker2/bin/jsonChecker2new file

Binary file not shown.

parsers/test_jsonChecker2/jsonChecker2/JSON_checker.cnew file+402

This diff is too big to show here.

parsers/test_jsonChecker2/jsonChecker2/JSON_checker.hnew file+13

This diff is too big to show here.

parsers/test_jsonChecker2/jsonChecker2/jsonChecker/main.cnew file+53

This diff is too big to show here.

parsers/test_jsonChecker2/jsonChecker2/jsonChecker2.xcodeproj/project.pbxprojnew file+253

This diff is too big to show here.

parsers/test_jsonChecker2/jsonChecker2/jsonChecker2.xcodeproj/project.xcworkspace/contents.xcworkspacedatanew file+7

This diff is too big to show here.

parsers/test_jsonChecker2/jsonChecker2/jsonChecker2.xcodeproj/project.xcworkspace/xcuserdata/nst.xcuserdatad/UserInterfaceState.xcuserstatenew file

Binary file not shown.

parsers/test_jsonChecker2/jsonChecker2/jsonChecker2.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/jsonChecker.xcschemenew file+97

This diff is too big to show here.

parsers/test_jsonChecker2/jsonChecker2/jsonChecker2.xcodeproj/xcuserdata/nst.xcuserdatad/xcschemes/xcschememanagement.plistnew file+22

This diff is too big to show here.

parsers/test_json_re.rbnew file+33

This diff is too big to show here.

parsers/test_json_xs.plnew file+28

This diff is too big to show here.

parsers/test_jsonlite.rnew file+7

This diff is too big to show here.

parsers/test_rjson.rnew file+7

This diff is too big to show here.

results/logs.txtnew file+1423

This diff is too big to show here.

results/parsing.htmlnew file+2149

This diff is too big to show here.

results/parsing_pruned.htmlnew file+146

This diff is too big to show here.

results/pruned_results.pngnew file

Binary file not shown.

results/style.cssnew file+89

This diff is too big to show here.

results/transform.htmlnew file+1492

This diff is too big to show here.

run_tests.pynew file+583

This diff is too big to show here.

test_parsing/i_number_neg_int_huge_exp.jsonnew file+1

This diff is too big to show here.

test_parsing/i_number_pos_double_huge_exp.jsonnew file+1

This diff is too big to show here.

test_parsing/i_object_key_lone_2nd_surrogate.jsonnew file+1

This diff is too big to show here.

test_parsing/i_string_1st_surrogate_but_2nd_missing.jsonnew file+1

This diff is too big to show here.

test_parsing/i_string_1st_valid_surrogate_2nd_invalid.jsonnew file+1

This diff is too big to show here.

test_parsing/i_string_UTF-16_invalid_lonely_surrogate.jsonnew file+1

This diff is too big to show here.

test_parsing/i_string_UTF-16_invalid_surrogate.jsonnew file+1

This diff is too big to show here.

test_parsing/i_string_UTF-8_invalid_sequence.jsonnew file+1

This diff is too big to show here.

test_parsing/i_string_incomplete_surrogate_and_escape_valid.jsonnew file+1

This diff is too big to show here.

test_parsing/i_string_incomplete_surrogate_pair.jsonnew file+1

This diff is too big to show here.

test_parsing/i_string_incomplete_surrogates_escape_valid.jsonnew file+1

This diff is too big to show here.

test_parsing/i_string_inverted_surrogates_U+1D11E.jsonnew file+1

This diff is too big to show here.

test_parsing/i_string_lone_second_surrogate.jsonnew file+1

This diff is too big to show here.

test_parsing/i_string_not_in_unicode_range.jsonnew file+1

This diff is too big to show here.

test_parsing/i_string_truncated-utf-8.jsonnew file+1

This diff is too big to show here.

test_parsing/i_string_unicode_U+10FFFE_nonchar.jsonnew file+1

This diff is too big to show here.

test_parsing/i_string_unicode_U+1FFFE_nonchar.jsonnew file+1

This diff is too big to show here.

test_parsing/i_string_unicode_U+FDD0_nonchar.jsonnew file+1

This diff is too big to show here.

test_parsing/i_string_unicode_U+FFFE_nonchar.jsonnew file+1

This diff is too big to show here.

test_parsing/i_structure_500_nested_arrays.jsonnew file+1

This diff is too big to show here.

test_parsing/i_structure_UTF-8_BOM_empty_object.jsonnew file+1

This diff is too big to show here.

test_parsing/n_array_1_true_without_comma.jsonnew file+1

This diff is too big to show here.

test_parsing/n_array_colon_instead_of_comma.jsonnew file+1

This diff is too big to show here.

test_parsing/n_array_comma_after_close.jsonnew file+1

This diff is too big to show here.

test_parsing/n_array_comma_and_number.jsonnew file+1

This diff is too big to show here.

test_parsing/n_array_double_comma.jsonnew file+1

This diff is too big to show here.

test_parsing/n_array_double_extra_comma.jsonnew file+1

This diff is too big to show here.

test_parsing/n_array_extra_close.jsonnew file+1

This diff is too big to show here.

test_parsing/n_array_extra_comma.jsonnew file+1

This diff is too big to show here.

test_parsing/n_array_incomplete.jsonnew file+1

This diff is too big to show here.

test_parsing/n_array_incomplete_invalid_value.jsonnew file+1

This diff is too big to show here.

test_parsing/n_array_inner_array_no_comma.jsonnew file+1

This diff is too big to show here.

test_parsing/n_array_invalid-utf-8-in-identifier.jsonnew file+1

This diff is too big to show here.

test_parsing/n_array_invalid_utf8.jsonnew file+1

This diff is too big to show here.

test_parsing/n_array_items_separated_by_semicolon.jsonnew file+1

This diff is too big to show here.

test_parsing/n_array_just_comma.jsonnew file+1

This diff is too big to show here.

test_parsing/n_array_just_minus.jsonnew file+1

This diff is too big to show here.

test_parsing/n_array_missing_value.jsonnew file+1

This diff is too big to show here.

test_parsing/n_array_newlines_unclosed.jsonnew file+3

This diff is too big to show here.

test_parsing/n_array_number_and_comma.jsonnew file+1

This diff is too big to show here.

test_parsing/n_array_number_and_several_commas.jsonnew file+1

This diff is too big to show here.

test_parsing/n_array_spaces_vertical_tab_formfeed.jsonnew file+1

This diff is too big to show here.

test_parsing/n_array_star_inside.jsonnew file+1

This diff is too big to show here.

test_parsing/n_array_unclosed.jsonnew file+1

This diff is too big to show here.

test_parsing/n_array_unclosed_trailing_comma.jsonnew file+1

This diff is too big to show here.

test_parsing/n_array_unclosed_with_new_lines.jsonnew file+3

This diff is too big to show here.

test_parsing/n_array_unclosed_with_object_inside.jsonnew file+1

This diff is too big to show here.

test_parsing/n_incomplete_false.jsonnew file+1

This diff is too big to show here.

test_parsing/n_incomplete_null.jsonnew file+1

This diff is too big to show here.

test_parsing/n_incomplete_true.jsonnew file+1

This diff is too big to show here.

test_parsing/n_number_++.jsonnew file+1

This diff is too big to show here.

test_parsing/n_number_+1.jsonnew file+1

This diff is too big to show here.

test_parsing/n_number_+Inf.jsonnew file+1

This diff is too big to show here.

test_parsing/n_number_-01.jsonnew file+1

This diff is too big to show here.

test_parsing/n_number_-1.0..jsonnew file+1

This diff is too big to show here.

test_parsing/n_number_-2..jsonnew file+1

This diff is too big to show here.

test_parsing/n_number_-NaN.jsonnew file+1

This diff is too big to show here.

test_parsing/n_number_.-1.jsonnew file+1

This diff is too big to show here.

test_parsing/n_number_.2e-3.jsonnew file+1

This diff is too big to show here.

test_parsing/n_number_0.1.2.jsonnew file+1

This diff is too big to show here.

test_parsing/n_number_0.3e+.jsonnew file+1

This diff is too big to show here.

test_parsing/n_number_0.3e.jsonnew file+1

This diff is too big to show here.

test_parsing/n_number_0.e1.jsonnew file+1

This diff is too big to show here.

test_parsing/n_number_0_capital_E+.jsonnew file+1

This diff is too big to show here.

test_parsing/n_number_0_capital_E.jsonnew file+1

This diff is too big to show here.

test_parsing/n_number_0e+.jsonnew file+1

This diff is too big to show here.

test_parsing/n_number_0e.jsonnew file+1

This diff is too big to show here.

test_parsing/n_number_1.0e+.jsonnew file+1

This diff is too big to show here.

test_parsing/n_number_1.0e-.jsonnew file+1

This diff is too big to show here.

test_parsing/n_number_1.0e.jsonnew file+1

This diff is too big to show here.

test_parsing/n_number_1_000.jsonnew file+1

This diff is too big to show here.

test_parsing/n_number_1eE2.jsonnew file+1

This diff is too big to show here.

test_parsing/n_number_2.e+3.jsonnew file+1

This diff is too big to show here.

test_parsing/n_number_2.e-3.jsonnew file+1

This diff is too big to show here.

test_parsing/n_number_2.e3.jsonnew file+1

This diff is too big to show here.

test_parsing/n_number_9.e+.jsonnew file+1

This diff is too big to show here.

test_parsing/n_number_Inf.jsonnew file+1

This diff is too big to show here.

test_parsing/n_number_NaN.jsonnew file+1

This diff is too big to show here.

test_parsing/n_number_U+FF11_fullwidth_digit_one.jsonnew file+1

This diff is too big to show here.

test_parsing/n_number_expression.jsonnew file+1

This diff is too big to show here.

test_parsing/n_number_hex_1_digit.jsonnew file+1

This diff is too big to show here.

test_parsing/n_number_hex_2_digits.jsonnew file+1

This diff is too big to show here.

test_parsing/n_number_infinity.jsonnew file+1

This diff is too big to show here.

test_parsing/n_number_invalid+-.jsonnew file+1

This diff is too big to show here.

test_parsing/n_number_invalid-negative-real.jsonnew file+1

This diff is too big to show here.

test_parsing/n_number_invalid-utf-8-in-bigger-int.jsonnew file+1

This diff is too big to show here.

test_parsing/n_number_invalid-utf-8-in-exponent.jsonnew file+1

This diff is too big to show here.

test_parsing/n_number_invalid-utf-8-in-int.jsonnew file+1

This diff is too big to show here.

test_parsing/n_number_minus_infinity.jsonnew file+1

This diff is too big to show here.

test_parsing/n_number_minus_sign_with_trailing_garbage.jsonnew file+1

This diff is too big to show here.

test_parsing/n_number_minus_space_1.jsonnew file+1

This diff is too big to show here.

test_parsing/n_number_neg_int_starting_with_zero.jsonnew file+1

This diff is too big to show here.

test_parsing/n_number_neg_real_without_int_part.jsonnew file+1

This diff is too big to show here.

test_parsing/n_number_neg_with_garbage_at_end.jsonnew file+1

This diff is too big to show here.

test_parsing/n_number_real_garbage_after_e.jsonnew file+1

This diff is too big to show here.

test_parsing/n_number_real_with_invalid_utf8_after_e.jsonnew file+1

This diff is too big to show here.

test_parsing/n_number_real_without_fractional_part.jsonnew file+1

This diff is too big to show here.

test_parsing/n_number_starting_with_dot.jsonnew file+1

This diff is too big to show here.

test_parsing/n_number_then_00.jsonnew file

Binary file not shown.

test_parsing/n_number_with_alpha.jsonnew file+1

This diff is too big to show here.

test_parsing/n_number_with_alpha_char.jsonnew file+1

This diff is too big to show here.

test_parsing/n_number_with_leading_zero.jsonnew file+1

This diff is too big to show here.

test_parsing/n_object_bad_value.jsonnew file+1

This diff is too big to show here.

test_parsing/n_object_bracket_key.jsonnew file+1

This diff is too big to show here.

test_parsing/n_object_comma_instead_of_colon.jsonnew file+1

This diff is too big to show here.

test_parsing/n_object_double_colon.jsonnew file+1

This diff is too big to show here.

test_parsing/n_object_emoji.jsonnew file+1

This diff is too big to show here.

test_parsing/n_object_garbage_at_end.jsonnew file+1

This diff is too big to show here.

test_parsing/n_object_key_with_single_quotes.jsonnew file+1

This diff is too big to show here.

test_parsing/n_object_missing_colon.jsonnew file+1

This diff is too big to show here.

test_parsing/n_object_missing_key.jsonnew file+1

This diff is too big to show here.

test_parsing/n_object_missing_semicolon.jsonnew file+1

This diff is too big to show here.

test_parsing/n_object_missing_value.jsonnew file+1

This diff is too big to show here.

test_parsing/n_object_no-colon.jsonnew file+1

This diff is too big to show here.

test_parsing/n_object_non_string_key.jsonnew file+1

This diff is too big to show here.

test_parsing/n_object_non_string_key_but_huge_number_instead.jsonnew file+1

This diff is too big to show here.

test_parsing/n_object_pi_in_key_and_trailing_comma.jsonnew file+1

This diff is too big to show here.

test_parsing/n_object_repeated_null_null.jsonnew file+1

This diff is too big to show here.

test_parsing/n_object_several_trailing_commas.jsonnew file+1

This diff is too big to show here.

test_parsing/n_object_single_quote.jsonnew file+1

This diff is too big to show here.

test_parsing/n_object_trailing_comma.jsonnew file+1

This diff is too big to show here.

test_parsing/n_object_trailing_comment.jsonnew file+1

This diff is too big to show here.

test_parsing/n_object_trailing_comment_open.jsonnew file+1

This diff is too big to show here.

test_parsing/n_object_trailing_comment_slash_open.jsonnew file+1

This diff is too big to show here.

test_parsing/n_object_trailing_comment_slash_open_incomplete.jsonnew file+1

This diff is too big to show here.

test_parsing/n_object_two_commas_in_a_row.jsonnew file+1

This diff is too big to show here.

test_parsing/n_object_unquoted_key.jsonnew file+1

This diff is too big to show here.

test_parsing/n_object_unterminated-value.jsonnew file+1

This diff is too big to show here.

test_parsing/n_object_with_single_string.jsonnew file+1

This diff is too big to show here.

test_parsing/n_object_with_trailing_garbage.jsonnew file+1

This diff is too big to show here.

test_parsing/n_single_space.jsonnew file+1

This diff is too big to show here.

test_parsing/n_string_1_surrogate_then_escape u.jsonnew file+1

This diff is too big to show here.

test_parsing/n_string_1_surrogate_then_escape u1.jsonnew file+1

This diff is too big to show here.

test_parsing/n_string_1_surrogate_then_escape u1x.jsonnew file+1

This diff is too big to show here.

test_parsing/n_string_1_surrogate_then_escape.jsonnew file+1

This diff is too big to show here.

test_parsing/n_string_UTF-16_incomplete_surrogate.jsonnew file+1

This diff is too big to show here.

test_parsing/n_string_UTF8_surrogate_U+D800.jsonnew file+1

This diff is too big to show here.

test_parsing/n_string_accentuated_char_no_quotes.jsonnew file+1

This diff is too big to show here.

test_parsing/n_string_backslash_00.jsonnew file

Binary file not shown.

test_parsing/n_string_escape_x.jsonnew file+1

This diff is too big to show here.

test_parsing/n_string_escaped_backslash_bad.jsonnew file+1

This diff is too big to show here.

test_parsing/n_string_escaped_ctrl_char_tab.jsonnew file+1

This diff is too big to show here.

test_parsing/n_string_escaped_emoji.jsonnew file+1

This diff is too big to show here.

test_parsing/n_string_incomplete_escape.jsonnew file+1

This diff is too big to show here.

test_parsing/n_string_incomplete_escaped_character.jsonnew file+1

This diff is too big to show here.

test_parsing/n_string_incomplete_surrogate_escape_invalid.jsonnew file+1

This diff is too big to show here.

test_parsing/n_string_invalid-utf-8-in-escape.jsonnew file+1

This diff is too big to show here.

test_parsing/n_string_invalid_backslash_esc.jsonnew file+1

This diff is too big to show here.

test_parsing/n_string_invalid_unicode_escape.jsonnew file+1

This diff is too big to show here.

test_parsing/n_string_invalid_utf-8.jsonnew file+1

This diff is too big to show here.

test_parsing/n_string_invalid_utf8_after_escape.jsonnew file+1

This diff is too big to show here.

test_parsing/n_string_iso_latin_1.jsonnew file+1

This diff is too big to show here.

test_parsing/n_string_leading_uescaped_thinspace.jsonnew file+1

This diff is too big to show here.

test_parsing/n_string_lone_utf8_continuation_byte.jsonnew file+1

This diff is too big to show here.

test_parsing/n_string_no_quotes_with_bad_escape.jsonnew file+1

This diff is too big to show here.

test_parsing/n_string_overlong_sequence_2_bytes.jsonnew file+1

This diff is too big to show here.

test_parsing/n_string_overlong_sequence_6_bytes.jsonnew file+1

This diff is too big to show here.

test_parsing/n_string_overlong_sequence_6_bytes_null.jsonnew file+1

This diff is too big to show here.

test_parsing/n_string_single_doublequote.jsonnew file+1

This diff is too big to show here.

test_parsing/n_string_single_quote.jsonnew file+1

This diff is too big to show here.

test_parsing/n_string_single_string_no_double_quotes.jsonnew file+1

This diff is too big to show here.

test_parsing/n_string_start_escape_unclosed.jsonnew file+1

This diff is too big to show here.

test_parsing/n_string_unescaped_crtl_char.jsonnew file

Binary file not shown.

test_parsing/n_string_unescaped_newline.jsonnew file+2

This diff is too big to show here.

test_parsing/n_string_unescaped_tab.jsonnew file+1

This diff is too big to show here.

test_parsing/n_string_unicode_CapitalU.jsonnew file+1

This diff is too big to show here.

test_parsing/n_string_with_trailing_garbage.jsonnew file+1

This diff is too big to show here.

test_parsing/n_structure_100000_opening_arrays.jsonnew file+1

This diff is too big to show here.

test_parsing/n_structure_<.>.jsonnew file+1

This diff is too big to show here.

test_parsing/n_structure_<null>.jsonnew file+1

This diff is too big to show here.

test_parsing/n_structure_U+2060_word_joined.jsonnew file+1

This diff is too big to show here.

test_parsing/n_structure_UTF8_BOM_no_data.jsonnew file+1

This diff is too big to show here.

test_parsing/n_structure_array_trailing_garbage.jsonnew file+1

This diff is too big to show here.

test_parsing/n_structure_array_with_extra_array_close.jsonnew file+1

This diff is too big to show here.

test_parsing/n_structure_array_with_unclosed_string.jsonnew file+1

This diff is too big to show here.

test_parsing/n_structure_ascii-unicode-identifier.jsonnew file+1

This diff is too big to show here.

test_parsing/n_structure_capitalized_True.jsonnew file+1

This diff is too big to show here.

test_parsing/n_structure_close_unopened_array.jsonnew file+1

This diff is too big to show here.

test_parsing/n_structure_comma_instead_of_closing_brace.jsonnew file+1

This diff is too big to show here.

test_parsing/n_structure_double_array.jsonnew file+1

This diff is too big to show here.

test_parsing/n_structure_end_array.jsonnew file+1

This diff is too big to show here.

test_parsing/n_structure_incomplete_UTF8_BOM.jsonnew file+1

This diff is too big to show here.

test_parsing/n_structure_lone-invalid-utf-8.jsonnew file+1

This diff is too big to show here.

test_parsing/n_structure_lone-open-bracket.jsonnew file+1

This diff is too big to show here.

test_parsing/n_structure_no_data.jsonnew file

No changes to the content.

test_parsing/n_structure_null-byte-outside-string.jsonnew file

Binary file not shown.

test_parsing/n_structure_number_with_trailing_garbage.jsonnew file+1

This diff is too big to show here.

test_parsing/n_structure_object_followed_by_closing_object.jsonnew file+1

This diff is too big to show here.

test_parsing/n_structure_object_unclosed_no_value.jsonnew file+1

This diff is too big to show here.

test_parsing/n_structure_object_with_comment.jsonnew file+1

This diff is too big to show here.

test_parsing/n_structure_object_with_trailing_garbage.jsonnew file+1

This diff is too big to show here.

test_parsing/n_structure_open_array_apostrophe.jsonnew file+1

This diff is too big to show here.

test_parsing/n_structure_open_array_comma.jsonnew file+1

This diff is too big to show here.

test_parsing/n_structure_open_array_object.jsonnew file+1

This diff is too big to show here.

test_parsing/n_structure_open_array_open_object.jsonnew file+1

This diff is too big to show here.

test_parsing/n_structure_open_array_open_string.jsonnew file+1

This diff is too big to show here.

test_parsing/n_structure_open_array_string.jsonnew file+1

This diff is too big to show here.

test_parsing/n_structure_open_object.jsonnew file+1

This diff is too big to show here.

test_parsing/n_structure_open_object_close_array.jsonnew file+1

This diff is too big to show here.

test_parsing/n_structure_open_object_comma.jsonnew file+1

This diff is too big to show here.

test_parsing/n_structure_open_object_open_array.jsonnew file+1

This diff is too big to show here.

test_parsing/n_structure_open_object_open_string.jsonnew file+1

This diff is too big to show here.

test_parsing/n_structure_open_object_string_with_apostrophes.jsonnew file+1

This diff is too big to show here.

test_parsing/n_structure_open_open.jsonnew file+1

This diff is too big to show here.

test_parsing/n_structure_single_point.jsonnew file+1

This diff is too big to show here.

test_parsing/n_structure_single_star.jsonnew file+1

This diff is too big to show here.

test_parsing/n_structure_trailing_#.jsonnew file+1

This diff is too big to show here.

test_parsing/n_structure_uescaped_LF_before_string.jsonnew file+1

This diff is too big to show here.

test_parsing/n_structure_unclosed_array.jsonnew file+1

This diff is too big to show here.

test_parsing/n_structure_unclosed_array_partial_null.jsonnew file+1

This diff is too big to show here.

test_parsing/n_structure_unclosed_array_unfinished_false.jsonnew file+1

This diff is too big to show here.

test_parsing/n_structure_unclosed_array_unfinished_true.jsonnew file+1

This diff is too big to show here.

test_parsing/n_structure_unclosed_object.jsonnew file+1

This diff is too big to show here.

test_parsing/n_structure_unicode-identifier.jsonnew file+1

This diff is too big to show here.

test_parsing/n_structure_whitespace_U+2060_word_joiner.jsonnew file+1

This diff is too big to show here.

test_parsing/n_structure_whitespace_formfeed.jsonnew file+1

This diff is too big to show here.

test_parsing/y_array_arraysWithSpaces.jsonnew file+1

This diff is too big to show here.

test_parsing/y_array_empty-string.jsonnew file+1

This diff is too big to show here.

test_parsing/y_array_empty.jsonnew file+1

This diff is too big to show here.

test_parsing/y_array_ending_with_newline.jsonnew file+1

This diff is too big to show here.

test_parsing/y_array_false.jsonnew file+1

This diff is too big to show here.

test_parsing/y_array_heterogeneous.jsonnew file+1

This diff is too big to show here.

test_parsing/y_array_null.jsonnew file+1

This diff is too big to show here.

test_parsing/y_array_with_1_and_newline.jsonnew file+2

This diff is too big to show here.

test_parsing/y_array_with_leading_space.jsonnew file+1

This diff is too big to show here.

test_parsing/y_array_with_several_null.jsonnew file+1

This diff is too big to show here.

test_parsing/y_array_with_trailing_space.jsonnew file+1

This diff is too big to show here.

test_parsing/y_number.jsonnew file+1

This diff is too big to show here.

test_parsing/y_number_0e+1.jsonnew file+1

This diff is too big to show here.

test_parsing/y_number_0e1.jsonnew file+1

This diff is too big to show here.

test_parsing/y_number_after_space.jsonnew file+1

This diff is too big to show here.

test_parsing/y_number_double_close_to_zero.jsonnew file+1

This diff is too big to show here.

test_parsing/y_number_double_huge_neg_exp.jsonnew file+1

This diff is too big to show here.

test_parsing/y_number_huge_exp.jsonnew file+1

This diff is too big to show here.

test_parsing/y_number_int_with_exp.jsonnew file+1

This diff is too big to show here.

test_parsing/y_number_minus_zero.jsonnew file+1

This diff is too big to show here.

test_parsing/y_number_negative_int.jsonnew file+1

This diff is too big to show here.

test_parsing/y_number_negative_one.jsonnew file+1

This diff is too big to show here.

test_parsing/y_number_negative_zero.jsonnew file+1

This diff is too big to show here.

test_parsing/y_number_real_capital_e.jsonnew file+1

This diff is too big to show here.

test_parsing/y_number_real_capital_e_neg_exp.jsonnew file+1

This diff is too big to show here.

test_parsing/y_number_real_capital_e_pos_exp.jsonnew file+1

This diff is too big to show here.

test_parsing/y_number_real_exponent.jsonnew file+1

This diff is too big to show here.

test_parsing/y_number_real_fraction_exponent.jsonnew file+1

This diff is too big to show here.

test_parsing/y_number_real_neg_exp.jsonnew file+1

This diff is too big to show here.

test_parsing/y_number_real_neg_overflow.jsonnew file+1

This diff is too big to show here.

test_parsing/y_number_real_pos_exponent.jsonnew file+1

This diff is too big to show here.

test_parsing/y_number_real_pos_overflow.jsonnew file+1

This diff is too big to show here.

test_parsing/y_number_real_underflow.jsonnew file+1

This diff is too big to show here.

test_parsing/y_number_simple_int.jsonnew file+1

This diff is too big to show here.

test_parsing/y_number_simple_real.jsonnew file+1

This diff is too big to show here.

test_parsing/y_number_too_big_neg_int.jsonnew file+1

This diff is too big to show here.

test_parsing/y_number_too_big_pos_int.jsonnew file+1

This diff is too big to show here.

test_parsing/y_number_very_big_negative_int.jsonnew file+1

This diff is too big to show here.

test_parsing/y_object.jsonnew file+1

This diff is too big to show here.

test_parsing/y_object_basic.jsonnew file+1

This diff is too big to show here.

test_parsing/y_object_duplicated_key.jsonnew file+1

This diff is too big to show here.

test_parsing/y_object_duplicated_key_and_value.jsonnew file+1

This diff is too big to show here.

test_parsing/y_object_empty.jsonnew file+1

This diff is too big to show here.

test_parsing/y_object_empty_key.jsonnew file+1

This diff is too big to show here.

test_parsing/y_object_escaped_null_in_key.jsonnew file+1

This diff is too big to show here.

test_parsing/y_object_extreme_numbers.jsonnew file+1

This diff is too big to show here.

test_parsing/y_object_long_strings.jsonnew file+1

This diff is too big to show here.

test_parsing/y_object_simple.jsonnew file+1

This diff is too big to show here.

test_parsing/y_object_string_unicode.jsonnew file+1

This diff is too big to show here.

test_parsing/y_object_with_newlines.jsonnew file+3

This diff is too big to show here.

test_parsing/y_string_1_2_3_bytes_UTF-8_sequences.jsonnew file+1

This diff is too big to show here.

test_parsing/y_string_UTF-16_Surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF.jsonnew file+1

This diff is too big to show here.

test_parsing/y_string_accepted_surrogate_pair.jsonnew file+1

This diff is too big to show here.

test_parsing/y_string_accepted_surrogate_pairs.jsonnew file+1

This diff is too big to show here.

test_parsing/y_string_allowed_escapes.jsonnew file+1

This diff is too big to show here.

test_parsing/y_string_backslash_and_u_escaped_zero.jsonnew file+1

This diff is too big to show here.

test_parsing/y_string_backslash_doublequotes.jsonnew file+1

This diff is too big to show here.

test_parsing/y_string_comments.jsonnew file+1

This diff is too big to show here.

test_parsing/y_string_double_escape_a.jsonnew file+1

This diff is too big to show here.

test_parsing/y_string_double_escape_n.jsonnew file+1

This diff is too big to show here.

test_parsing/y_string_escaped_control_character.jsonnew file+1

This diff is too big to show here.

test_parsing/y_string_escaped_noncharacter.jsonnew file+1

This diff is too big to show here.

test_parsing/y_string_in_array.jsonnew file+1

This diff is too big to show here.

test_parsing/y_string_in_array_with_leading_space.jsonnew file+1

This diff is too big to show here.

test_parsing/y_string_last_surrogates_1_and_2.jsonnew file+1

This diff is too big to show here.

test_parsing/y_string_newline_uescaped.jsonnew file+1

This diff is too big to show here.

test_parsing/y_string_nonCharacterInUTF-8_U+10FFFF.jsonnew file+1

This diff is too big to show here.

test_parsing/y_string_nonCharacterInUTF-8_U+1FFFF.jsonnew file+1

This diff is too big to show here.

test_parsing/y_string_nonCharacterInUTF-8_U+FFFF.jsonnew file+1

This diff is too big to show here.

test_parsing/y_string_null_escape.jsonnew file+1

This diff is too big to show here.

test_parsing/y_string_one-byte-utf-8.jsonnew file+1

This diff is too big to show here.

test_parsing/y_string_pi.jsonnew file+1

This diff is too big to show here.

test_parsing/y_string_simple_ascii.jsonnew file+1

This diff is too big to show here.

test_parsing/y_string_space.jsonnew file+1

This diff is too big to show here.

test_parsing/y_string_three-byte-utf-8.jsonnew file+1

This diff is too big to show here.

test_parsing/y_string_two-byte-utf-8.jsonnew file+1

This diff is too big to show here.

test_parsing/y_string_u+2028_line_sep.jsonnew file+1

This diff is too big to show here.

test_parsing/y_string_u+2029_par_sep.jsonnew file+1

This diff is too big to show here.

test_parsing/y_string_uEscape.jsonnew file+1

This diff is too big to show here.

test_parsing/y_string_unescaped_char_delete.jsonnew file+1

This diff is too big to show here.

test_parsing/y_string_unicode.jsonnew file+1

This diff is too big to show here.

test_parsing/y_string_unicodeEscapedBackslash.jsonnew file+1

This diff is too big to show here.

test_parsing/y_string_unicode_2.jsonnew file+1

This diff is too big to show here.

test_parsing/y_string_unicode_U+200B_ZERO_WIDTH_SPACE.jsonnew file+1

This diff is too big to show here.

test_parsing/y_string_unicode_U+2064_invisible_plus.jsonnew file+1

This diff is too big to show here.

test_parsing/y_string_unicode_escaped_double_quote.jsonnew file+1

This diff is too big to show here.

test_parsing/y_string_utf16.jsonnew file

Binary file not shown.

test_parsing/y_string_utf8.jsonnew file+1

This diff is too big to show here.

test_parsing/y_string_with_del_character.jsonnew file+1

This diff is too big to show here.

test_parsing/y_structure_lonely_false.jsonnew file+1

This diff is too big to show here.

test_parsing/y_structure_lonely_int.jsonnew file+1

This diff is too big to show here.

test_parsing/y_structure_lonely_negative_real.jsonnew file+1

This diff is too big to show here.

test_parsing/y_structure_lonely_null.jsonnew file+1

This diff is too big to show here.

test_parsing/y_structure_lonely_string.jsonnew file+1

This diff is too big to show here.

test_parsing/y_structure_lonely_true.jsonnew file+1

This diff is too big to show here.

test_parsing/y_structure_string_empty.jsonnew file+1

This diff is too big to show here.

test_parsing/y_structure_trailing_newline.jsonnew file+1

This diff is too big to show here.

test_parsing/y_structure_true_in_array.jsonnew file+1

This diff is too big to show here.

test_parsing/y_structure_whitespace_array.jsonnew file+1

This diff is too big to show here.

test_transform/number_1.0.jsonnew file+1

This diff is too big to show here.

test_transform/number_1.000000000000000005.jsonnew file+1

This diff is too big to show here.

test_transform/number_1000000000000000.jsonnew file+1

This diff is too big to show here.

test_transform/number_10000000000000000999.jsonnew file+1

This diff is too big to show here.

test_transform/number_1e-999.jsonnew file+1

This diff is too big to show here.

test_transform/number_1e6.jsonnew file+1

This diff is too big to show here.

test_transform/object_key_nfc_nfd.jsonnew file+1

This diff is too big to show here.

test_transform/object_key_nfd_nfc.jsonnew file+1

This diff is too big to show here.

test_transform/object_same_key_different_values.jsonnew file+1

This diff is too big to show here.

test_transform/object_same_key_same_value.jsonnew file+1

This diff is too big to show here.

test_transform/object_same_key_unclear_values.jsonnew file+1

This diff is too big to show here.

test_transform/string_1_escaped_invalid_codepoint.jsonnew file+1

This diff is too big to show here.

test_transform/string_1_invalid_codepoint.jsonnew file+1

This diff is too big to show here.

test_transform/string_2_escaped_invalid_codepoints.jsonnew file+1

This diff is too big to show here.

test_transform/string_2_invalid_codepoints.jsonnew file+1

This diff is too big to show here.

test_transform/string_3_escaped_invalid_codepoints.jsonnew file+1

This diff is too big to show here.

test_transform/string_3_invalid_codepoints.jsonnew file+1

This diff is too big to show here.

test_transform/string_with_escaped_NULL.jsonnew file+1

This diff is too big to show here.