├── README.md ├── java-version ├── .classpath ├── .project ├── .settings │ └── org.eclipse.jdt.core.prefs ├── bin │ ├── com │ │ └── bgw │ │ │ ├── translator │ │ │ ├── MessageTranslator.class │ │ │ ├── RoyISO8583.class │ │ │ ├── RoyISO8583Field.class │ │ │ └── Translator.class │ │ │ └── utility │ │ │ ├── Encryption.class │ │ │ └── Utility.class │ ├── org │ │ └── json │ │ │ ├── CDL.class │ │ │ ├── Cookie.class │ │ │ ├── CookieList.class │ │ │ ├── HTTP.class │ │ │ ├── HTTPTokener.class │ │ │ ├── JSONArray.class │ │ │ ├── JSONException.class │ │ │ ├── JSONML.class │ │ │ ├── JSONObject$Null.class │ │ │ ├── JSONObject.class │ │ │ ├── JSONPointer$Builder.class │ │ │ ├── JSONPointer.class │ │ │ ├── JSONPointerException.class │ │ │ ├── JSONPropertyIgnore.class │ │ │ ├── JSONPropertyName.class │ │ │ ├── JSONString.class │ │ │ ├── JSONStringer.class │ │ │ ├── JSONTokener.class │ │ │ ├── JSONWriter.class │ │ │ ├── Property.class │ │ │ ├── XML$1$1.class │ │ │ ├── XML$1.class │ │ │ ├── XML.class │ │ │ └── XMLTokener.class │ └── test │ │ └── Test.class └── src │ ├── com │ └── bgw │ │ ├── translator │ │ ├── MessageTranslator.java │ │ ├── RoyISO8583.java │ │ ├── RoyISO8583Field.java │ │ └── Translator.java │ │ └── utility │ │ ├── Encryption.java │ │ └── Utility.java │ ├── org │ └── json │ │ ├── CDL.java │ │ ├── Cookie.java │ │ ├── CookieList.java │ │ ├── HTTP.java │ │ ├── HTTPTokener.java │ │ ├── JSONArray.java │ │ ├── JSONException.java │ │ ├── JSONML.java │ │ ├── JSONObject.java │ │ ├── JSONPointer.java │ │ ├── JSONPointerException.java │ │ ├── JSONPropertyIgnore.java │ │ ├── JSONPropertyName.java │ │ ├── JSONString.java │ │ ├── JSONStringer.java │ │ ├── JSONTokener.java │ │ ├── JSONWriter.java │ │ ├── Property.java │ │ ├── XML.java │ │ └── XMLTokener.java │ └── test │ └── Test.java └── php-version ├── index.php └── lib ├── MessageTranslator.php └── RoyISO8583.php /README.md: -------------------------------------------------------------------------------- 1 | # ISO8583-JSON-XML 2 | This library is used to convert messages from one format to another. The supported formats are ISO 8583, JSON, and XML. 3 | 4 | Beginner programmers often experience difficulties when parsing and building data with ISO 8583 format. Most programmers are more familiar with human readable formats such as JSON and XML. On the other hand, however, the company requires the ISO 8583 format because some or all of the partners use that format. 5 | 6 | Using this library, both senior programmers and novice programmers will be easier to build applications that use the ISO 8583 message format. 7 | 8 | You can save the configuration on file or database as string. 9 | 10 | ### Capability 11 | 12 | 1. Convert JSON to ISO 8583 13 | 2. Convert XML to ISO 8583 14 | 3. Convert ISO 8583 to JSON 15 | 4. Convert ISO 8583 to XML 16 | 5. Convert JSON to XML 17 | 6. Convert XML to JSON 18 | 19 | ### Example 20 | 21 | Script 22 | 23 | ```java 24 | package test; 25 | 26 | import java.io.IOException; 27 | 28 | import org.json.JSONArray; 29 | import org.json.JSONException; 30 | import org.json.JSONObject; 31 | 32 | import com.bgw.translator.MessageTranslator; 33 | 34 | public class Test { 35 | public static void main(String[] args) throws IOException { 36 | String configStr = "[{\"field\":\"2\",\"format\":\"%-6s\",\"variable\":\"pan\",\"options\":\"\",\"type\":\"LLVAR\",\"field_length\":\"6\"},{\"field\":\"3\",\"format\":\"%06d\",\"variable\":\"processing_code\",\"options\":\"\",\"type\":\"NUMERIC\",\"field_length\":\"6\"},{\"field\":\"4\",\"format\":\"%012d\",\"variable\":\"amount\",\"options\":\"\",\"type\":\"NUMERIC\",\"field_length\":\"12\"},{\"field\":\"7\",\"format\":\"%-10s\",\"variable\":\"transmission_date_time\",\"options\":\"\",\"type\":\"STRING\",\"field_length\":\"10\"},{\"field\":\"11\",\"format\":\"%06d\",\"variable\":\"stan\",\"options\":\"\",\"type\":\"NUMERIC\",\"field_length\":\"6\"},{\"field\":\"12\",\"format\":\"%-6s\",\"variable\":\"local_time\",\"options\":\"\",\"type\":\"STRING\",\"field_length\":\"6\"},{\"field\":\"13\",\"format\":\"%-4s\",\"variable\":\"local_date\",\"options\":\"\",\"type\":\"STRING\",\"field_length\":\"4\"},{\"field\":\"15\",\"format\":\"%-4s\",\"variable\":\"settlement_date\",\"options\":\"\",\"type\":\"STRING\",\"field_length\":\"4\"},{\"field\":\"18\",\"format\":\"%04d\",\"variable\":\"merchant_type\",\"options\":\"\",\"type\":\"NUMERIC\",\"field_length\":\"4\"},{\"field\":\"32\",\"format\":\"%-3s\",\"variable\":\"acq_institution_code\",\"options\":\"\",\"type\":\"LLVAR\",\"field_length\":\"3\"},{\"field\":\"37\",\"format\":\"%012d\",\"variable\":\"reference_number\",\"options\":\"\",\"type\":\"NUMERIC\",\"field_length\":\"12\"},{\"field\":\"41\",\"format\":\"%-8s\",\"variable\":\"card_acceptor_terminal\",\"options\":\"\",\"type\":\"STRING\",\"field_length\":\"8\"},{\"field\":\"42\",\"format\":\"%15s\",\"variable\":\"acceptor_identification_code\",\"options\":\"\",\"type\":\"STRING\",\"field_length\":\"15\"},{\"field\":\"48\",\"format\":\"%-7s%011d%012d%01d%-32s%-32s%-25s%4s%-9s\",\"variable\":\"switcher_id, meter_id, customer_id, id_selector, pln_reference_number, ba_reference_number, customer_name, tariff, ceiling\",\"options\":\"\",\"type\":\"LLLVAR\",\"field_length\":\"133\"},{\"field\":\"49\",\"format\":\"%03d\",\"variable\":\"transaction_currency_code\",\"options\":\"\",\"type\":\"NUMERIC\",\"field_length\":\"3\"}]"; 37 | 38 | MessageTranslator mt = new MessageTranslator(); 39 | String mti_id = "0210"; 40 | String iso = "0210723A400108C1800006364235361000000000050000072751515134657351515107270728678903555232442364723376832 234822 1339876 7183712217171837122171212462348242265823582523523547223323582375872385728357823758235235KAMSHORY, MT R51350 360"; 41 | String iso_new = ""; 42 | String xml = ""; 43 | JSONArray config = new JSONArray(); 44 | JSONObject json = new JSONObject(); 45 | 46 | 47 | try 48 | { 49 | config = new JSONArray(configStr); 50 | json = mt.parseISO8583(iso, config); 51 | iso_new = new String(mt.buildISO8583(json, config, mti_id)); 52 | xml = mt.buildXML(json, "data"); 53 | 54 | System.out.println("Demonstration of conversion of ISO 8583 - JSON - XML"); 55 | System.out.println("Config : "); 56 | System.out.println(config.toString()); 57 | System.out.println("============================================================="); 58 | 59 | System.out.println("Original ISO 8583 : "); 60 | System.out.println("'"+iso+"'"); 61 | System.out.println("Convert ISO to JSON"); 62 | System.out.println("JSON : "); 63 | System.out.println(json.toString()); 64 | System.out.println("============================================================="); 65 | 66 | System.out.println("Now, convert JSON to new ISO"); 67 | System.out.println("New ISO 8583 : "); 68 | System.out.println("'"+iso_new+"'"); 69 | System.out.println("============================================================="); 70 | 71 | System.out.println("Now, convert JSON to XML"); 72 | System.out.println("XML : "); 73 | System.out.println(xml); 74 | System.out.println("============================================================="); 75 | 76 | } 77 | catch (JSONException e) 78 | { 79 | e.printStackTrace(); 80 | } 81 | } 82 | } 83 | ``` 84 | 85 | Output 86 | 87 | ``` 88 | Demonstration of conversion of ISO 8583 - JSON - XML 89 | Config : 90 | [{"field":"2","format":"%-6s","variable":"pan","options":"","field_length":"6","type":"LLVAR"},{"field":"3","format":"%06d","variable":"processing_code","options":"","field_length":"6","type":"NUMERIC"},{"field":"4","format":"%012d","variable":"amount","options":"","field_length":"12","type":"NUMERIC"},{"field":"7","format":"%-10s","variable":"transmission_date_time","options":"","field_length":"10","type":"STRING"},{"field":"11","format":"%06d","variable":"stan","options":"","field_length":"6","type":"NUMERIC"},{"field":"12","format":"%-6s","variable":"local_time","options":"","field_length":"6","type":"STRING"},{"field":"13","format":"%-4s","variable":"local_date","options":"","field_length":"4","type":"STRING"},{"field":"15","format":"%-4s","variable":"settlement_date","options":"","field_length":"4","type":"STRING"},{"field":"18","format":"%04d","variable":"merchant_type","options":"","field_length":"4","type":"NUMERIC"},{"field":"32","format":"%-3s","variable":"acq_institution_code","options":"","field_length":"3","type":"LLVAR"},{"field":"37","format":"%012d","variable":"reference_number","options":"","field_length":"12","type":"NUMERIC"},{"field":"41","format":"%-8s","variable":"card_acceptor_terminal","options":"","field_length":"8","type":"STRING"},{"field":"42","format":"%15s","variable":"acceptor_identification_code","options":"","field_length":"15","type":"STRING"},{"field":"48","format":"%-7s%011d%012d%01d%-32s%-32s%-25s%4s%-9s","variable":"switcher_id, meter_id, customer_id, id_selector, pln_reference_number, ba_reference_number, customer_name, tariff, ceiling","options":"","field_length":"133","type":"LLLVAR"},{"field":"49","format":"%03d","variable":"transaction_currency_code","options":"","field_length":"3","type":"NUMERIC"}] 91 | ============================================================= 92 | Original ISO 8583 : 93 | '0210723A400108C1800006364235361000000000050000072751515134657351515107270728678903555232442364723376832 234822 1339876 7183712217171837122171212462348242265823582523523547223323582375872385728357823758235235KAMSHORY, MT R51350 360' 94 | Convert ISO to JSON 95 | JSON : 96 | {"ceiling":"1350 ","amount":"50000","settlement_date":"0728","switcher_id":"9876 ","ba_reference_number":"23582375872385728357823758235235","processing_code":"361000","transaction_currency_code":"360","id_selector":"1","reference_number":"232442364723","local_date":"0727","pln_reference_number":"24623482422658235825235235472233","local_time":"515151","transmission_date_time":"0727515151","stan":"346573","acq_institution_code":"555","card_acceptor_terminal":"376832 ","tariff":" R5","acceptor_identification_code":"234822 ","customer_name":"KAMSHORY, MT ","pan":"364235","customer_id":"718371221712","meter_id":"71837122171","merchant_type":"6789"} 97 | ============================================================= 98 | Now, convert JSON to new ISO 99 | New ISO 8583 : 100 | '0210723A400108C1800006364235361000000000050000072751515134657351515107270728678903555232442364723376832 234822 1339876 7183712217171837122171212462348242265823582523523547223323582375872385728357823758235235KAMSHORY, MT R51350 360' 101 | ============================================================= 102 | Now, convert JSON to XML 103 | XML : 104 | 105 | 1350 106 | 50000 107 | 0728 108 | 9876 109 | 23582375872385728357823758235235 110 | 361000 111 | 360 112 | 1 113 | 232442364723 114 | 0727 115 | 24623482422658235825235235472233 116 | 515151 117 | 0727515151 118 | 346573 119 | 555 120 | 376832 121 | R5 122 | 234822 123 | KAMSHORY, MT 124 | 364235 125 | 718371221712 126 | 71837122171 127 | 6789 128 | 129 | ============================================================= 130 | ``` 131 | 132 | You can also use JSONObject as config type. 133 | 134 | ```java 135 | String configStr = "{\"f41\":{\"format\":\"%-8s\", \"variable\":\"terminal_id\", \"options\":\"\",\n" + 136 | "\"field_length\":\"8\", \"type\":\"STRING\"},\"f63\":{\"format\":\"%-32s%-30s%-50s%-\n" + 137 | "18s\", \"variable\":\"locket_code, locket_name, locket_address, locket_phone\",\n" + 138 | "\"options\":\"\", \"field_length\":\"130\", \"type\":\"LLLVAR\"},\"f32\":{\"format\":\"%-\n" + 139 | "11s\", \"variable\":\"acq_institution_code\", \"options\":\"\", \"field_length\":\"11\",\n" + 140 | "\"type\":\"LLVAR\"},\"f121\":{\"format\":\"%-32s\", \"variable\":\"payment_reference\",\n" + 141 | "\"options\":\"\", \"field_length\":\"32\", \"type\":\"LLLVAR\"},\"f12\":{\"format\":\"%-6s\",\n" + 142 | "\"variable\":\"local_time\", \"options\":\"\", \"field_length\":\"6\",\n" + 143 | "\"type\":\"STRING\"},\"f120\":{\"format\":\"%-20s\", \"variable\":\"product_code\",\n" + 144 | "\"options\":\"\", \"field_length\":\"20\", \"type\":\"LLLVAR\"},\"f11\":{\"format\":\"%-6s\",\n" + 145 | "\"variable\":\"stan\", \"options\":\"\", \"field_length\":\"6\",\n" + 146 | "\"type\":\"STRING\"},\"f33\":{\"format\":\"%-11s\",\n" + 147 | "\"variable\":\"fwd_institution_code\", \"options\":\"\", \"field_length\":\"11\",\n" + 148 | "\"type\":\"LLVAR\"},\"f13\":{\"format\":\"%-4s\", \"variable\":\"local_date\",\n" + 149 | "\"options\":\"\", \"field_length\":\"4\", \"type\":\"STRING\"},\"f49\":{\"format\":\"%03d\",\n" + 150 | "\"variable\":\"transaction_currency_code\", \"options\":\"\", \"field_length\":\"3\",\n" + 151 | "\"type\":\"NUMERIC\"},\"f15\":{\"format\":\"%-4s\", \"variable\":\"settlement_date\",\n" + 152 | "\"options\":\"\", \"field_length\":\"4\", \"type\":\"STRING\"},\"f37\":{\"format\":\"%-12s\",\n" + 153 | "\"variable\":\"reference_number\", \"options\":\"\", \"field_length\":\"12\",\n" + 154 | "\"type\":\"STRING\"},\"f48\":{\"format\":\"%-13s\", \"variable\":\"registration_number\",\n" + 155 | "\"options\":\"\", \"field_length\":\"13\", \"type\":\"LLLVAR\"},\"f2\":{\"format\":\"%-19s\",\n" + 156 | "\"variable\":\"pan\", \"options\":\"\", \"field_length\":\"19\",\n" + 157 | "\"type\":\"LLVAR\"},\"f18\":{\"format\":\"%04d\", \"variable\":\"merchant_type\",\n" + 158 | "\"options\":\"\", \"field_length\":\"4\", \"type\":\"NUMERIC\"},\"f3\":{\"format\":\"%06d\",\n" + 159 | "\"variable\":\"processing_code\", \"options\":\"\", \"field_length\":\"6\",\n" + 160 | "\"type\":\"NUMERIC\"},\"f7\":{\"format\":\"%-10s\",\n" + 161 | "\"variable\":\"transmission_date_time\", \"options\":\"\", \"field_length\":\"10\",\n" + 162 | "\"type\":\"STRING\"},\"f127\":{\"format\":\"%-20s%-32s\", \"variable\":\"username,\n" + 163 | "password\", \"options\":\"\", \"field_length\":\"52\", \"type\":\"LLLVAR\"}}"; 164 | JSONObject config = new JSONObject(); 165 | try 166 | { 167 | config = new JSONObject(configStr); 168 | } 169 | catch (JSONException e) 170 | { 171 | e.printStackTrace(); 172 | } 173 | -------------------------------------------------------------------------------- /java-version/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /java-version/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | RoyISO8385 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.jdt.core.javanature 16 | 17 | 18 | -------------------------------------------------------------------------------- /java-version/.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 3 | org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate 4 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 5 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve 6 | org.eclipse.jdt.core.compiler.compliance=1.8 7 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate 8 | org.eclipse.jdt.core.compiler.debug.localVariable=generate 9 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate 10 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 11 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 12 | org.eclipse.jdt.core.compiler.source=1.8 13 | -------------------------------------------------------------------------------- /java-version/bin/com/bgw/translator/MessageTranslator.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamshory/ISO8583-JSON-XML/6fede851f2b33456a625e69a36a8f9182df0c0d0/java-version/bin/com/bgw/translator/MessageTranslator.class -------------------------------------------------------------------------------- /java-version/bin/com/bgw/translator/RoyISO8583.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamshory/ISO8583-JSON-XML/6fede851f2b33456a625e69a36a8f9182df0c0d0/java-version/bin/com/bgw/translator/RoyISO8583.class -------------------------------------------------------------------------------- /java-version/bin/com/bgw/translator/RoyISO8583Field.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamshory/ISO8583-JSON-XML/6fede851f2b33456a625e69a36a8f9182df0c0d0/java-version/bin/com/bgw/translator/RoyISO8583Field.class -------------------------------------------------------------------------------- /java-version/bin/com/bgw/translator/Translator.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamshory/ISO8583-JSON-XML/6fede851f2b33456a625e69a36a8f9182df0c0d0/java-version/bin/com/bgw/translator/Translator.class -------------------------------------------------------------------------------- /java-version/bin/com/bgw/utility/Encryption.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamshory/ISO8583-JSON-XML/6fede851f2b33456a625e69a36a8f9182df0c0d0/java-version/bin/com/bgw/utility/Encryption.class -------------------------------------------------------------------------------- /java-version/bin/com/bgw/utility/Utility.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamshory/ISO8583-JSON-XML/6fede851f2b33456a625e69a36a8f9182df0c0d0/java-version/bin/com/bgw/utility/Utility.class -------------------------------------------------------------------------------- /java-version/bin/org/json/CDL.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamshory/ISO8583-JSON-XML/6fede851f2b33456a625e69a36a8f9182df0c0d0/java-version/bin/org/json/CDL.class -------------------------------------------------------------------------------- /java-version/bin/org/json/Cookie.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamshory/ISO8583-JSON-XML/6fede851f2b33456a625e69a36a8f9182df0c0d0/java-version/bin/org/json/Cookie.class -------------------------------------------------------------------------------- /java-version/bin/org/json/CookieList.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamshory/ISO8583-JSON-XML/6fede851f2b33456a625e69a36a8f9182df0c0d0/java-version/bin/org/json/CookieList.class -------------------------------------------------------------------------------- /java-version/bin/org/json/HTTP.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamshory/ISO8583-JSON-XML/6fede851f2b33456a625e69a36a8f9182df0c0d0/java-version/bin/org/json/HTTP.class -------------------------------------------------------------------------------- /java-version/bin/org/json/HTTPTokener.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamshory/ISO8583-JSON-XML/6fede851f2b33456a625e69a36a8f9182df0c0d0/java-version/bin/org/json/HTTPTokener.class -------------------------------------------------------------------------------- /java-version/bin/org/json/JSONArray.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamshory/ISO8583-JSON-XML/6fede851f2b33456a625e69a36a8f9182df0c0d0/java-version/bin/org/json/JSONArray.class -------------------------------------------------------------------------------- /java-version/bin/org/json/JSONException.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamshory/ISO8583-JSON-XML/6fede851f2b33456a625e69a36a8f9182df0c0d0/java-version/bin/org/json/JSONException.class -------------------------------------------------------------------------------- /java-version/bin/org/json/JSONML.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamshory/ISO8583-JSON-XML/6fede851f2b33456a625e69a36a8f9182df0c0d0/java-version/bin/org/json/JSONML.class -------------------------------------------------------------------------------- /java-version/bin/org/json/JSONObject$Null.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamshory/ISO8583-JSON-XML/6fede851f2b33456a625e69a36a8f9182df0c0d0/java-version/bin/org/json/JSONObject$Null.class -------------------------------------------------------------------------------- /java-version/bin/org/json/JSONObject.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamshory/ISO8583-JSON-XML/6fede851f2b33456a625e69a36a8f9182df0c0d0/java-version/bin/org/json/JSONObject.class -------------------------------------------------------------------------------- /java-version/bin/org/json/JSONPointer$Builder.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamshory/ISO8583-JSON-XML/6fede851f2b33456a625e69a36a8f9182df0c0d0/java-version/bin/org/json/JSONPointer$Builder.class -------------------------------------------------------------------------------- /java-version/bin/org/json/JSONPointer.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamshory/ISO8583-JSON-XML/6fede851f2b33456a625e69a36a8f9182df0c0d0/java-version/bin/org/json/JSONPointer.class -------------------------------------------------------------------------------- /java-version/bin/org/json/JSONPointerException.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamshory/ISO8583-JSON-XML/6fede851f2b33456a625e69a36a8f9182df0c0d0/java-version/bin/org/json/JSONPointerException.class -------------------------------------------------------------------------------- /java-version/bin/org/json/JSONPropertyIgnore.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamshory/ISO8583-JSON-XML/6fede851f2b33456a625e69a36a8f9182df0c0d0/java-version/bin/org/json/JSONPropertyIgnore.class -------------------------------------------------------------------------------- /java-version/bin/org/json/JSONPropertyName.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamshory/ISO8583-JSON-XML/6fede851f2b33456a625e69a36a8f9182df0c0d0/java-version/bin/org/json/JSONPropertyName.class -------------------------------------------------------------------------------- /java-version/bin/org/json/JSONString.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamshory/ISO8583-JSON-XML/6fede851f2b33456a625e69a36a8f9182df0c0d0/java-version/bin/org/json/JSONString.class -------------------------------------------------------------------------------- /java-version/bin/org/json/JSONStringer.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamshory/ISO8583-JSON-XML/6fede851f2b33456a625e69a36a8f9182df0c0d0/java-version/bin/org/json/JSONStringer.class -------------------------------------------------------------------------------- /java-version/bin/org/json/JSONTokener.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamshory/ISO8583-JSON-XML/6fede851f2b33456a625e69a36a8f9182df0c0d0/java-version/bin/org/json/JSONTokener.class -------------------------------------------------------------------------------- /java-version/bin/org/json/JSONWriter.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamshory/ISO8583-JSON-XML/6fede851f2b33456a625e69a36a8f9182df0c0d0/java-version/bin/org/json/JSONWriter.class -------------------------------------------------------------------------------- /java-version/bin/org/json/Property.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamshory/ISO8583-JSON-XML/6fede851f2b33456a625e69a36a8f9182df0c0d0/java-version/bin/org/json/Property.class -------------------------------------------------------------------------------- /java-version/bin/org/json/XML$1$1.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamshory/ISO8583-JSON-XML/6fede851f2b33456a625e69a36a8f9182df0c0d0/java-version/bin/org/json/XML$1$1.class -------------------------------------------------------------------------------- /java-version/bin/org/json/XML$1.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamshory/ISO8583-JSON-XML/6fede851f2b33456a625e69a36a8f9182df0c0d0/java-version/bin/org/json/XML$1.class -------------------------------------------------------------------------------- /java-version/bin/org/json/XML.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamshory/ISO8583-JSON-XML/6fede851f2b33456a625e69a36a8f9182df0c0d0/java-version/bin/org/json/XML.class -------------------------------------------------------------------------------- /java-version/bin/org/json/XMLTokener.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamshory/ISO8583-JSON-XML/6fede851f2b33456a625e69a36a8f9182df0c0d0/java-version/bin/org/json/XMLTokener.class -------------------------------------------------------------------------------- /java-version/bin/test/Test.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kamshory/ISO8583-JSON-XML/6fede851f2b33456a625e69a36a8f9182df0c0d0/java-version/bin/test/Test.class -------------------------------------------------------------------------------- /java-version/src/com/bgw/translator/RoyISO8583Field.java: -------------------------------------------------------------------------------- 1 | package com.bgw.translator; 2 | 3 | import java.lang.reflect.Field; 4 | 5 | import com.bgw.utility.Utility; 6 | 7 | /** 8 | * RoyISO8583Field is field of RoyISO8583 9 | * @author Kamshory, MT 10 | * 11 | */ 12 | public class RoyISO8583Field { 13 | /** 14 | * Field type 15 | */ 16 | public String type = ""; 17 | /** 18 | * Field data 19 | */ 20 | public String data = ""; 21 | /** 22 | * Field length 23 | */ 24 | public int length = 0; 25 | /** 26 | * Field flag whether the data is set or not. 27 | */ 28 | public boolean isSet = false; 29 | /** 30 | * Default constructor 31 | */ 32 | public RoyISO8583Field() 33 | { 34 | } 35 | /** 36 | * Get field 37 | * @return JSONObject contains ISO 8583 field data and its attributes 38 | */ 39 | public RoyISO8583Field getField() 40 | { 41 | return this; 42 | } 43 | /** 44 | * Set field 45 | * @param field JSONObject contains ISO 8583 field data and its attributes 46 | * @return RoyISO8583Field 47 | */ 48 | public RoyISO8583Field setField(RoyISO8583Field field) 49 | { 50 | this.isSet = true; 51 | this.type = field.type; 52 | this.length = field.length; 53 | this.data = field.data; 54 | return this; 55 | } 56 | public RoyISO8583Field setField(String data, String type, int length) 57 | { 58 | this.isSet = true; 59 | this.type = type; 60 | this.length = length; 61 | this.data = data; 62 | return this; 63 | } 64 | /** 65 | * Overrides toString method to convert object to JSON String. This method is useful to debug or show value of each properties of the object. 66 | */ 67 | public String toString() 68 | { 69 | Field[] fields = this.getClass().getDeclaredFields(); 70 | int i, max = fields.length; 71 | String fieldName = ""; 72 | String fieldType = ""; 73 | String ret = ""; 74 | String value = ""; 75 | boolean skip = false; 76 | int j = 0; 77 | for(i = 0; i < max; i++) 78 | { 79 | fieldName = fields[i].getName().toString(); 80 | fieldType = fields[i].getType().toString(); 81 | if(i == 0) 82 | { 83 | ret += "{"; 84 | } 85 | if(fieldType.equals("int") || fieldType.equals("long") || fieldType.equals("float") || fieldType.equals("double") || fieldType.equals("boolean")) 86 | { 87 | try 88 | { 89 | value = fields[i].get(this).toString(); 90 | } 91 | catch (Exception e) 92 | { 93 | value = "0"; 94 | } 95 | skip = false; 96 | } 97 | else if(fieldType.contains("String")) 98 | { 99 | try 100 | { 101 | value = "\""+Utility.escapeJSON((String) fields[i].get(this))+"\""; 102 | } 103 | catch (Exception e) 104 | { 105 | value = "\""+"\""; 106 | } 107 | skip = false; 108 | } 109 | else 110 | { 111 | value = "\""+"\""; 112 | skip = true; 113 | } 114 | if(!skip) 115 | { 116 | if(j > 0) 117 | { 118 | ret += ","; 119 | } 120 | j++; 121 | ret += "\r\n\t\""+fieldName+"\":"+value; 122 | } 123 | if(i == max-1) 124 | { 125 | ret += "\r\n}"; 126 | } 127 | } 128 | return ret; 129 | } 130 | 131 | } 132 | -------------------------------------------------------------------------------- /java-version/src/com/bgw/utility/Encryption.java: -------------------------------------------------------------------------------- 1 | package com.bgw.utility; 2 | 3 | import java.io.UnsupportedEncodingException; 4 | import java.util.Arrays; 5 | import java.util.Base64; 6 | 7 | import javax.crypto.Cipher; 8 | import javax.crypto.IllegalBlockSizeException; 9 | import javax.crypto.SecretKey; 10 | import javax.crypto.spec.SecretKeySpec; 11 | 12 | /** 13 | * CryptoTool is class to encrypt and decrypt data. 14 | * @author Kamshory, MT 15 | * 16 | */ 17 | public class Encryption 18 | { 19 | /** 20 | * Encryptor 21 | */ 22 | Cipher ecipher; 23 | /** 24 | * Decryptor 25 | */ 26 | Cipher dcipher; 27 | /** 28 | * Constructor with key as String 29 | * @param key Key 30 | */ 31 | public Encryption(String key) 32 | { 33 | this.init(key); 34 | } 35 | /** 36 | * Constructor with key as SecretKey 37 | * @param key String key to encrypt or decrypt data 38 | */ 39 | public Encryption(SecretKey key) 40 | { 41 | this.init(key); 42 | } 43 | /** 44 | * Init key 45 | * @param key SecretKey to encrypt or decrypt data 46 | * @return true if success and false if failed 47 | */ 48 | public boolean init(SecretKey key) 49 | { 50 | try 51 | { 52 | ecipher = Cipher.getInstance("AES"); 53 | dcipher = Cipher.getInstance("AES"); 54 | ecipher.init(Cipher.ENCRYPT_MODE, key); 55 | dcipher.init(Cipher.DECRYPT_MODE, key); 56 | } 57 | catch (javax.crypto.NoSuchPaddingException e) 58 | { 59 | e.printStackTrace(); 60 | } 61 | catch (java.security.NoSuchAlgorithmException e) 62 | { 63 | e.printStackTrace(); 64 | } 65 | catch (java.security.InvalidKeyException e) 66 | { 67 | e.printStackTrace(); 68 | } 69 | return true; 70 | } 71 | /** 72 | * Init key 73 | * @param key Key 74 | * @return true if success and false if failed 75 | */ 76 | public boolean init(String key) 77 | { 78 | while( key.length() < 16) 79 | { 80 | key += "&"; 81 | } 82 | byte[] bkey = (key).getBytes(); 83 | bkey = Arrays.copyOf(bkey, 16); // use only first 128 bit 84 | SecretKeySpec skey2 = new SecretKeySpec(bkey, "AES"); 85 | try 86 | { 87 | ecipher = Cipher.getInstance("AES"); 88 | dcipher = Cipher.getInstance("AES"); 89 | ecipher.init(Cipher.ENCRYPT_MODE, skey2); 90 | dcipher.init(Cipher.DECRYPT_MODE, skey2); 91 | } 92 | catch (javax.crypto.NoSuchPaddingException e) 93 | { 94 | e.printStackTrace(); 95 | } 96 | catch (java.security.NoSuchAlgorithmException e) 97 | { 98 | e.printStackTrace(); 99 | } 100 | catch (java.security.InvalidKeyException e) 101 | { 102 | e.printStackTrace(); 103 | } 104 | return true; 105 | } 106 | /** 107 | * Encrypt plain text into cipher text 108 | * @param input Plain text to be encrypted 109 | * @return String containing cipher text 110 | */ 111 | public String encrypt(String input) 112 | { 113 | try 114 | { 115 | // Encode the string into bytes using utf-8 116 | byte[] utf8 = input.getBytes("UTF8"); 117 | // Encrypt 118 | byte[] enc = ecipher.doFinal(utf8); 119 | // Encode bytes to base64 to get a string 120 | return new String(this.base64Encode(enc)); 121 | } 122 | catch (Exception e) 123 | { 124 | e.printStackTrace(); 125 | } 126 | return null; 127 | } 128 | /** 129 | * Decrypt cipher text into plain text 130 | * @param input Cipher text 131 | * @return Plain text 132 | */ 133 | public String decrypt(String input) 134 | { 135 | try 136 | { 137 | // Decode base64 to get bytes 138 | byte[] dec = this.base64Decode(input); 139 | // Decrypt 140 | byte[] utf8 = dcipher.doFinal(dec); 141 | // Decode using utf-8 142 | return new String(utf8, "UTF8"); 143 | } 144 | catch (javax.crypto.BadPaddingException e) 145 | { 146 | e.printStackTrace(); 147 | } 148 | catch (IllegalBlockSizeException e) 149 | { 150 | e.printStackTrace(); 151 | } 152 | catch (UnsupportedEncodingException e) 153 | { 154 | e.printStackTrace(); 155 | } 156 | return null; 157 | } 158 | /** 159 | * Base64 encoding 160 | * @param input String to be encoded 161 | * @return Encoded string 162 | */ 163 | public String base64Encode(byte[] input) 164 | { 165 | try 166 | { 167 | return Base64.getEncoder().encodeToString(input); 168 | } 169 | catch(NullPointerException e) 170 | { 171 | return ""; 172 | } 173 | } 174 | /** 175 | * Base64 decoding 176 | * @param input String to be decoded 177 | * @return Decoded string 178 | */ 179 | public byte[] base64Decode(String input) 180 | { 181 | try 182 | { 183 | return Base64.getDecoder().decode(input); 184 | } 185 | catch(NullPointerException e) 186 | { 187 | e.printStackTrace(); 188 | return null; 189 | } 190 | } 191 | } -------------------------------------------------------------------------------- /java-version/src/com/bgw/utility/Utility.java: -------------------------------------------------------------------------------- 1 | package com.bgw.utility; 2 | 3 | import java.io.UnsupportedEncodingException; 4 | import java.security.MessageDigest; 5 | import java.security.NoSuchAlgorithmException; 6 | import java.text.DateFormat; 7 | import java.text.ParseException; 8 | import java.text.SimpleDateFormat; 9 | import java.util.Calendar; 10 | import java.util.Date; 11 | /** 12 | * This class is used as utility 13 | * @author Kamshory, MT 14 | */ 15 | public class Utility 16 | { 17 | /** 18 | * Debug mode 19 | */ 20 | public static boolean debugMode = false; 21 | /** 22 | * Transaction indicator on debug mode 23 | */ 24 | public static boolean transactionIndicator = false; 25 | /** 26 | * Get current time with specified format 27 | * @return Current time with format yyyy-MM-dd 28 | */ 29 | public static String now() 30 | { 31 | String result = ""; 32 | try 33 | { 34 | DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 35 | Date dateObject = new Date(); 36 | result = dateFormat.format(dateObject); 37 | } 38 | catch(Exception e) 39 | { 40 | e.printStackTrace(); 41 | } 42 | return result; 43 | } 44 | /** 45 | * Get current time with specified format 46 | * @param precission Decimal precission 47 | * @return Current time with format yyyy-MM-dd 48 | */ 49 | public static String now(int precission) 50 | { 51 | if(precission > 6) 52 | { 53 | precission = 6; 54 | } 55 | if(precission < 0) 56 | { 57 | precission = 0; 58 | } 59 | long decimal = 0; 60 | long nanoSecond = System.nanoTime(); 61 | if(precission == 6) 62 | { 63 | decimal = nanoSecond % 1000000; 64 | } 65 | else if(precission == 5) 66 | { 67 | decimal = nanoSecond % 100000; 68 | } 69 | else if(precission == 4) 70 | { 71 | decimal = nanoSecond % 10000; 72 | } 73 | else if(precission == 3) 74 | { 75 | decimal = nanoSecond % 1000; 76 | } 77 | else if(precission == 2) 78 | { 79 | decimal = nanoSecond % 100; 80 | } 81 | else if(precission == 1) 82 | { 83 | decimal = nanoSecond % 10; 84 | } 85 | String result = ""; 86 | try 87 | { 88 | DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 89 | Date dateObject = new Date(); 90 | result = dateFormat.format(dateObject)+"."+decimal; 91 | } 92 | catch(Exception e) 93 | { 94 | e.printStackTrace(); 95 | } 96 | return result; 97 | } 98 | public static String now3() 99 | { 100 | String result = ""; 101 | try 102 | { 103 | long miliSecond = System.nanoTime() % 1000; 104 | DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 105 | Date dateObject = new Date(); 106 | result = dateFormat.format(dateObject)+"."+miliSecond; 107 | } 108 | catch(Exception e) 109 | { 110 | e.printStackTrace(); 111 | } 112 | return result; 113 | } 114 | public static String now6() 115 | { 116 | String result = ""; 117 | try 118 | { 119 | long microSecond = System.nanoTime() % 1000000; 120 | DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 121 | Date dateObject = new Date(); 122 | result = dateFormat.format(dateObject)+"."+microSecond; 123 | } 124 | catch(Exception e) 125 | { 126 | e.printStackTrace(); 127 | } 128 | return result; 129 | } 130 | /** 131 | * Get current time with specified format 132 | * @param format Time format 133 | * @return Current time with specified format 134 | */ 135 | public static String now(String format) 136 | { 137 | String result = ""; 138 | try 139 | { 140 | DateFormat dateFormat = new SimpleDateFormat(format); 141 | Date dateObject = new Date(); 142 | result = dateFormat.format(dateObject); 143 | } 144 | catch(Exception e) 145 | { 146 | e.printStackTrace(); 147 | } 148 | return result; 149 | } 150 | /** 151 | * Get MySQL format of current time 152 | * @return Current time with MySQL format 153 | */ 154 | public static String MySQLDate() 155 | { 156 | return now("yyyy-MM-dd HH:mm:ss"); 157 | } 158 | /** 159 | * Get PgSQL format of current time 160 | * @return Current time with PgSQL format 161 | */ 162 | public static String PgSQLDate() 163 | { 164 | return now("yyyy-MM-dd HH:mm:ss.SSS"); 165 | } 166 | /** 167 | * Get current time with MMddHHmmss format 168 | * @return Current time with MMddHHmmss format 169 | */ 170 | public static String date10() 171 | { 172 | return now("MMddHHmmss"); 173 | } 174 | /** 175 | * Get current time with MMdd format 176 | * @return Current time with MMdd format 177 | */ 178 | public static String date4() 179 | { 180 | return now("MMdd"); 181 | } 182 | /** 183 | * Get current time with HHmmss format 184 | * @return Current time with HHmmss format 185 | */ 186 | public static String time6() 187 | { 188 | return now("HHmmss"); 189 | } 190 | /** 191 | * Get current time with HHmm format 192 | * @return Current time with HHmm format 193 | */ 194 | public static String time4() 195 | { 196 | return now("HHmm"); 197 | } 198 | /** 199 | * Convert Date10 to MySQL date format (MMddHHmmss to yyyy-MM-dd HH:mm:ss) 200 | * @param datetime Date10 201 | * @return MySQL date format 202 | */ 203 | public static String date10ToMySQLDate(String datetime) 204 | { 205 | return date10ToFullDate(datetime, "yyyy-MM-dd HH:mm:ss"); 206 | } 207 | /** 208 | * Convert Date10 to PgSQL date format (MMddHHmmss to yyyy-MM-dd HH:mm:ss.SSS) 209 | * @param datetime Date10 210 | * @return PgSQL date format 211 | */ 212 | public static String date10ToPgSQLDate(String datetime) 213 | { 214 | return date10ToFullDate(datetime, "yyyy-MM-dd HH:mm:ss.SSS"); 215 | } 216 | /** 217 | * Convert Date10 to full date time 218 | * @param datetime Date10 219 | * @param format Expected format 220 | * @return Full date time format 221 | */ 222 | public static String date10ToFullDate(String datetime, String format) 223 | { 224 | while(datetime.length() < 10) 225 | { 226 | datetime = "0"+datetime; 227 | } 228 | String yyyy = now("yyyy"); 229 | DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss"); 230 | String result = ""; 231 | try 232 | { 233 | // debug year transition 234 | if(datetime.length() > 4) 235 | { 236 | String month1 = datetime.substring(0, 4); 237 | if(month1.equals("1231")) 238 | { 239 | String month2 = now("MMdd"); 240 | if(!month2.equals("0101")) 241 | { 242 | int YYYY = Integer.parseInt(yyyy) - 1; 243 | yyyy = YYYY+""; 244 | } 245 | } 246 | } 247 | Date dateObject = dateFormat.parse(yyyy+datetime); 248 | dateFormat = new SimpleDateFormat(format); 249 | result = dateFormat.format(dateObject); 250 | } 251 | catch (ParseException e) 252 | { 253 | e.printStackTrace(); 254 | result = MySQLDate(); 255 | } 256 | return result; 257 | } 258 | /** 259 | * Date time 260 | * @param format Date time format 261 | * @return String contains current date time 262 | */ 263 | public static String date(String format) 264 | { 265 | String result = ""; 266 | try 267 | { 268 | SimpleDateFormat dateFormat = new SimpleDateFormat(format); 269 | Date dateObject = new Date(); 270 | result = dateFormat.format(dateObject); 271 | } 272 | catch(Exception e) 273 | { 274 | e.printStackTrace(); 275 | } 276 | return result; 277 | } 278 | /** 279 | * Date time 280 | * @param format Date time format 281 | * @param date Date time 282 | * @return String contains current date time 283 | */ 284 | public static String date(String format, Date date) 285 | { 286 | String result = ""; 287 | try 288 | { 289 | SimpleDateFormat dateFormat = new SimpleDateFormat(format); 290 | result = dateFormat.format(date); 291 | } 292 | catch(Exception e) 293 | { 294 | e.printStackTrace(); 295 | } 296 | return result; 297 | } 298 | /** 299 | * Date time 300 | * @param format Date time format 301 | * @param time Unix Timestamp 302 | * @return String contains current date time 303 | */ 304 | public static String date(String format, long time) 305 | { 306 | String result = ""; 307 | try 308 | { 309 | SimpleDateFormat dateFormat = new SimpleDateFormat(format); 310 | Date dateObject = new Date(time); 311 | result = dateFormat.format(dateObject); 312 | } 313 | catch(Exception e) 314 | { 315 | e.printStackTrace(); 316 | } 317 | return result; 318 | } 319 | /** 320 | * Date yesterday 321 | * @return Date yesterday 322 | */ 323 | public static Date yesterday() 324 | { 325 | final Calendar cal = Calendar.getInstance(); 326 | cal.add(Calendar.DATE, -1); 327 | return cal.getTime(); 328 | } 329 | /** 330 | * Date tomorrow 331 | * @return Date tomorrow 332 | */ 333 | public static Date tomorrow() 334 | { 335 | final Calendar cal = Calendar.getInstance(); 336 | cal.add(Calendar.DATE, +1); 337 | return cal.getTime(); 338 | } 339 | /** 340 | * Get random integer in a range 341 | * @param min Minimum value 342 | * @param max Maximum value 343 | * @return Random integer 344 | */ 345 | public static int random(int min, int max) 346 | { 347 | java.util.Random rand = new java.util.Random(); 348 | return rand.nextInt((max - min) + 1) + min; 349 | } 350 | /** 351 | * Get SHA-1 digest of string 352 | * @param input Input string 353 | * @return SHA-1 digest 354 | */ 355 | public static String sha1(String input) 356 | { 357 | String sha1 = ""; 358 | try 359 | { 360 | MessageDigest crypt = MessageDigest.getInstance("SHA-1"); 361 | crypt.reset(); 362 | crypt.update(input.getBytes("UTF-8")); 363 | sha1 = byteArrayToHexString(crypt.digest()); 364 | } 365 | catch(NoSuchAlgorithmException e) 366 | { 367 | e.printStackTrace(); 368 | } 369 | catch(UnsupportedEncodingException e) 370 | { 371 | e.printStackTrace(); 372 | } 373 | return sha1; 374 | } 375 | /** 376 | * Get MD5 digest of string 377 | * @param input Input string 378 | * @return MD5 digest 379 | */ 380 | public static String md5(String input) 381 | { 382 | String sha1 = ""; 383 | try 384 | { 385 | MessageDigest crypt = MessageDigest.getInstance("MD5"); 386 | crypt.reset(); 387 | crypt.update(input.getBytes("UTF-8")); 388 | sha1 = byteArrayToHexString(crypt.digest()); 389 | } 390 | catch(NoSuchAlgorithmException e) 391 | { 392 | e.printStackTrace(); 393 | } 394 | catch(UnsupportedEncodingException e) 395 | { 396 | e.printStackTrace(); 397 | } 398 | return sha1; 399 | } 400 | /** 401 | * Convert array byte to string contains hexadecimal number 402 | * @param b array byte 403 | * @return String contains hexadecimal number 404 | */ 405 | public static String byteArrayToHexString(byte[] b) 406 | { 407 | String result = ""; 408 | for (int i=0; i < b.length; i++) 409 | { 410 | result += Integer.toString((b[i] & 0xff) + 0x100, 16).substring(1); 411 | } 412 | return result; 413 | } 414 | /** 415 | * Print text to screen on debug mode 416 | * @param input Text to be printed 417 | */ 418 | public static void print(String input) 419 | { 420 | if(Utility.debugMode) 421 | { 422 | System.out.print(input); 423 | } 424 | } 425 | /** 426 | * Print text to screen on debug mode. It will add new line on the end of text 427 | * @param input Text to be printed 428 | */ 429 | public static void println(String input) 430 | { 431 | if(Utility.debugMode) 432 | { 433 | System.out.println(input); 434 | } 435 | } 436 | public static String escapeJSON(String input) 437 | { 438 | String output = ""; 439 | if(input != null) 440 | { 441 | output = input.replaceAll("\"", "\\\""); 442 | output = output.replaceAll("/", "\\/"); 443 | } 444 | return output; 445 | } 446 | } 447 | -------------------------------------------------------------------------------- /java-version/src/org/json/CDL.java: -------------------------------------------------------------------------------- 1 | package org.json; 2 | 3 | /* 4 | Copyright (c) 2002 JSON.org 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | The Software shall be used for Good, not Evil. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | SOFTWARE. 25 | */ 26 | 27 | /** 28 | * This provides static methods to convert comma delimited text into a 29 | * JSONArray, and to convert a JSONArray into comma delimited text. Comma 30 | * delimited text is a very popular format for data interchange. It is 31 | * understood by most database, spreadsheet, and organizer programs. 32 | *

33 | * Each row of text represents a row in a table or a data record. Each row 34 | * ends with a NEWLINE character. Each row contains one or more values. 35 | * Values are separated by commas. A value can contain any character except 36 | * for comma, unless is is wrapped in single quotes or double quotes. 37 | *

38 | * The first row usually contains the names of the columns. 39 | *

40 | * A comma delimited list can be converted into a JSONArray of JSONObjects. 41 | * The names for the elements in the JSONObjects can be taken from the names 42 | * in the first row. 43 | * @author JSON.org 44 | * @version 2016-05-01 45 | */ 46 | public class CDL { 47 | 48 | /** 49 | * Get the next value. The value can be wrapped in quotes. The value can 50 | * be empty. 51 | * @param x A JSONTokener of the source text. 52 | * @return The value string, or null if empty. 53 | * @throws JSONException if the quoted string is badly formed. 54 | */ 55 | private static String getValue(JSONTokener x) throws JSONException { 56 | char c; 57 | char q; 58 | StringBuffer sb; 59 | do { 60 | c = x.next(); 61 | } while (c == ' ' || c == '\t'); 62 | switch (c) { 63 | case 0: 64 | return null; 65 | case '"': 66 | case '\'': 67 | q = c; 68 | sb = new StringBuffer(); 69 | for (;;) { 70 | c = x.next(); 71 | if (c == q) { 72 | //Handle escaped double-quote 73 | char nextC = x.next(); 74 | if(nextC != '\"') { 75 | // if our quote was the end of the file, don't step 76 | if(nextC > 0) { 77 | x.back(); 78 | } 79 | break; 80 | } 81 | } 82 | if (c == 0 || c == '\n' || c == '\r') { 83 | throw x.syntaxError("Missing close quote '" + q + "'."); 84 | } 85 | sb.append(c); 86 | } 87 | return sb.toString(); 88 | case ',': 89 | x.back(); 90 | return ""; 91 | default: 92 | x.back(); 93 | return x.nextTo(','); 94 | } 95 | } 96 | 97 | /** 98 | * Produce a JSONArray of strings from a row of comma delimited values. 99 | * @param x A JSONTokener of the source text. 100 | * @return A JSONArray of strings. 101 | * @throws JSONException 102 | */ 103 | public static JSONArray rowToJSONArray(JSONTokener x) throws JSONException { 104 | JSONArray ja = new JSONArray(); 105 | for (;;) { 106 | String value = getValue(x); 107 | char c = x.next(); 108 | if (value == null || 109 | (ja.length() == 0 && value.length() == 0 && c != ',')) { 110 | return null; 111 | } 112 | ja.put(value); 113 | for (;;) { 114 | if (c == ',') { 115 | break; 116 | } 117 | if (c != ' ') { 118 | if (c == '\n' || c == '\r' || c == 0) { 119 | return ja; 120 | } 121 | throw x.syntaxError("Bad character '" + c + "' (" + 122 | (int)c + ")."); 123 | } 124 | c = x.next(); 125 | } 126 | } 127 | } 128 | 129 | /** 130 | * Produce a JSONObject from a row of comma delimited text, using a 131 | * parallel JSONArray of strings to provides the names of the elements. 132 | * @param names A JSONArray of names. This is commonly obtained from the 133 | * first row of a comma delimited text file using the rowToJSONArray 134 | * method. 135 | * @param x A JSONTokener of the source text. 136 | * @return A JSONObject combining the names and values. 137 | * @throws JSONException 138 | */ 139 | public static JSONObject rowToJSONObject(JSONArray names, JSONTokener x) 140 | throws JSONException { 141 | JSONArray ja = rowToJSONArray(x); 142 | return ja != null ? ja.toJSONObject(names) : null; 143 | } 144 | 145 | /** 146 | * Produce a comma delimited text row from a JSONArray. Values containing 147 | * the comma character will be quoted. Troublesome characters may be 148 | * removed. 149 | * @param ja A JSONArray of strings. 150 | * @return A string ending in NEWLINE. 151 | */ 152 | public static String rowToString(JSONArray ja) { 153 | StringBuilder sb = new StringBuilder(); 154 | for (int i = 0; i < ja.length(); i += 1) { 155 | if (i > 0) { 156 | sb.append(','); 157 | } 158 | Object object = ja.opt(i); 159 | if (object != null) { 160 | String string = object.toString(); 161 | if (string.length() > 0 && (string.indexOf(',') >= 0 || 162 | string.indexOf('\n') >= 0 || string.indexOf('\r') >= 0 || 163 | string.indexOf(0) >= 0 || string.charAt(0) == '"')) { 164 | sb.append('"'); 165 | int length = string.length(); 166 | for (int j = 0; j < length; j += 1) { 167 | char c = string.charAt(j); 168 | if (c >= ' ' && c != '"') { 169 | sb.append(c); 170 | } 171 | } 172 | sb.append('"'); 173 | } else { 174 | sb.append(string); 175 | } 176 | } 177 | } 178 | sb.append('\n'); 179 | return sb.toString(); 180 | } 181 | 182 | /** 183 | * Produce a JSONArray of JSONObjects from a comma delimited text string, 184 | * using the first row as a source of names. 185 | * @param string The comma delimited text. 186 | * @return A JSONArray of JSONObjects. 187 | * @throws JSONException 188 | */ 189 | public static JSONArray toJSONArray(String string) throws JSONException { 190 | return toJSONArray(new JSONTokener(string)); 191 | } 192 | 193 | /** 194 | * Produce a JSONArray of JSONObjects from a comma delimited text string, 195 | * using the first row as a source of names. 196 | * @param x The JSONTokener containing the comma delimited text. 197 | * @return A JSONArray of JSONObjects. 198 | * @throws JSONException 199 | */ 200 | public static JSONArray toJSONArray(JSONTokener x) throws JSONException { 201 | return toJSONArray(rowToJSONArray(x), x); 202 | } 203 | 204 | /** 205 | * Produce a JSONArray of JSONObjects from a comma delimited text string 206 | * using a supplied JSONArray as the source of element names. 207 | * @param names A JSONArray of strings. 208 | * @param string The comma delimited text. 209 | * @return A JSONArray of JSONObjects. 210 | * @throws JSONException 211 | */ 212 | public static JSONArray toJSONArray(JSONArray names, String string) 213 | throws JSONException { 214 | return toJSONArray(names, new JSONTokener(string)); 215 | } 216 | 217 | /** 218 | * Produce a JSONArray of JSONObjects from a comma delimited text string 219 | * using a supplied JSONArray as the source of element names. 220 | * @param names A JSONArray of strings. 221 | * @param x A JSONTokener of the source text. 222 | * @return A JSONArray of JSONObjects. 223 | * @throws JSONException 224 | */ 225 | public static JSONArray toJSONArray(JSONArray names, JSONTokener x) 226 | throws JSONException { 227 | if (names == null || names.length() == 0) { 228 | return null; 229 | } 230 | JSONArray ja = new JSONArray(); 231 | for (;;) { 232 | JSONObject jo = rowToJSONObject(names, x); 233 | if (jo == null) { 234 | break; 235 | } 236 | ja.put(jo); 237 | } 238 | if (ja.length() == 0) { 239 | return null; 240 | } 241 | return ja; 242 | } 243 | 244 | 245 | /** 246 | * Produce a comma delimited text from a JSONArray of JSONObjects. The 247 | * first row will be a list of names obtained by inspecting the first 248 | * JSONObject. 249 | * @param ja A JSONArray of JSONObjects. 250 | * @return A comma delimited text. 251 | * @throws JSONException 252 | */ 253 | public static String toString(JSONArray ja) throws JSONException { 254 | JSONObject jo = ja.optJSONObject(0); 255 | if (jo != null) { 256 | JSONArray names = jo.names(); 257 | if (names != null) { 258 | return rowToString(names) + toString(names, ja); 259 | } 260 | } 261 | return null; 262 | } 263 | 264 | /** 265 | * Produce a comma delimited text from a JSONArray of JSONObjects using 266 | * a provided list of names. The list of names is not included in the 267 | * output. 268 | * @param names A JSONArray of strings. 269 | * @param ja A JSONArray of JSONObjects. 270 | * @return A comma delimited text. 271 | * @throws JSONException 272 | */ 273 | public static String toString(JSONArray names, JSONArray ja) 274 | throws JSONException { 275 | if (names == null || names.length() == 0) { 276 | return null; 277 | } 278 | StringBuffer sb = new StringBuffer(); 279 | for (int i = 0; i < ja.length(); i += 1) { 280 | JSONObject jo = ja.optJSONObject(i); 281 | if (jo != null) { 282 | sb.append(rowToString(jo.toJSONArray(names))); 283 | } 284 | } 285 | return sb.toString(); 286 | } 287 | } 288 | -------------------------------------------------------------------------------- /java-version/src/org/json/Cookie.java: -------------------------------------------------------------------------------- 1 | package org.json; 2 | 3 | /* 4 | Copyright (c) 2002 JSON.org 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | The Software shall be used for Good, not Evil. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | SOFTWARE. 25 | */ 26 | 27 | /** 28 | * Convert a web browser cookie specification to a JSONObject and back. 29 | * JSON and Cookies are both notations for name/value pairs. 30 | * @author JSON.org 31 | * @version 2015-12-09 32 | */ 33 | public class Cookie { 34 | 35 | /** 36 | * Produce a copy of a string in which the characters '+', '%', '=', ';' 37 | * and control characters are replaced with "%hh". This is a gentle form 38 | * of URL encoding, attempting to cause as little distortion to the 39 | * string as possible. The characters '=' and ';' are meta characters in 40 | * cookies. By convention, they are escaped using the URL-encoding. This is 41 | * only a convention, not a standard. Often, cookies are expected to have 42 | * encoded values. We encode '=' and ';' because we must. We encode '%' and 43 | * '+' because they are meta characters in URL encoding. 44 | * @param string The source string. 45 | * @return The escaped result. 46 | */ 47 | public static String escape(String string) { 48 | char c; 49 | String s = string.trim(); 50 | int length = s.length(); 51 | StringBuilder sb = new StringBuilder(length); 52 | for (int i = 0; i < length; i += 1) { 53 | c = s.charAt(i); 54 | if (c < ' ' || c == '+' || c == '%' || c == '=' || c == ';') { 55 | sb.append('%'); 56 | sb.append(Character.forDigit((char)((c >>> 4) & 0x0f), 16)); 57 | sb.append(Character.forDigit((char)(c & 0x0f), 16)); 58 | } else { 59 | sb.append(c); 60 | } 61 | } 62 | return sb.toString(); 63 | } 64 | 65 | 66 | /** 67 | * Convert a cookie specification string into a JSONObject. The string 68 | * will contain a name value pair separated by '='. The name and the value 69 | * will be unescaped, possibly converting '+' and '%' sequences. The 70 | * cookie properties may follow, separated by ';', also represented as 71 | * name=value (except the secure property, which does not have a value). 72 | * The name will be stored under the key "name", and the value will be 73 | * stored under the key "value". This method does not do checking or 74 | * validation of the parameters. It only converts the cookie string into 75 | * a JSONObject. 76 | * @param string The cookie specification string. 77 | * @return A JSONObject containing "name", "value", and possibly other 78 | * members. 79 | * @throws JSONException 80 | */ 81 | public static JSONObject toJSONObject(String string) throws JSONException { 82 | String name; 83 | JSONObject jo = new JSONObject(); 84 | Object value; 85 | JSONTokener x = new JSONTokener(string); 86 | jo.put("name", x.nextTo('=')); 87 | x.next('='); 88 | jo.put("value", x.nextTo(';')); 89 | x.next(); 90 | while (x.more()) { 91 | name = unescape(x.nextTo("=;")); 92 | if (x.next() != '=') { 93 | if (name.equals("secure")) { 94 | value = Boolean.TRUE; 95 | } else { 96 | throw x.syntaxError("Missing '=' in cookie parameter."); 97 | } 98 | } else { 99 | value = unescape(x.nextTo(';')); 100 | x.next(); 101 | } 102 | jo.put(name, value); 103 | } 104 | return jo; 105 | } 106 | 107 | 108 | /** 109 | * Convert a JSONObject into a cookie specification string. The JSONObject 110 | * must contain "name" and "value" members. 111 | * If the JSONObject contains "expires", "domain", "path", or "secure" 112 | * members, they will be appended to the cookie specification string. 113 | * All other members are ignored. 114 | * @param jo A JSONObject 115 | * @return A cookie specification string 116 | * @throws JSONException 117 | */ 118 | public static String toString(JSONObject jo) throws JSONException { 119 | StringBuilder sb = new StringBuilder(); 120 | 121 | sb.append(escape(jo.getString("name"))); 122 | sb.append("="); 123 | sb.append(escape(jo.getString("value"))); 124 | if (jo.has("expires")) { 125 | sb.append(";expires="); 126 | sb.append(jo.getString("expires")); 127 | } 128 | if (jo.has("domain")) { 129 | sb.append(";domain="); 130 | sb.append(escape(jo.getString("domain"))); 131 | } 132 | if (jo.has("path")) { 133 | sb.append(";path="); 134 | sb.append(escape(jo.getString("path"))); 135 | } 136 | if (jo.optBoolean("secure")) { 137 | sb.append(";secure"); 138 | } 139 | return sb.toString(); 140 | } 141 | 142 | /** 143 | * Convert %hh sequences to single characters, and 144 | * convert plus to space. 145 | * @param string A string that may contain 146 | * + (plus) and 147 | * %hh sequences. 148 | * @return The unescaped string. 149 | */ 150 | public static String unescape(String string) { 151 | int length = string.length(); 152 | StringBuilder sb = new StringBuilder(length); 153 | for (int i = 0; i < length; ++i) { 154 | char c = string.charAt(i); 155 | if (c == '+') { 156 | c = ' '; 157 | } else if (c == '%' && i + 2 < length) { 158 | int d = JSONTokener.dehexchar(string.charAt(i + 1)); 159 | int e = JSONTokener.dehexchar(string.charAt(i + 2)); 160 | if (d >= 0 && e >= 0) { 161 | c = (char)(d * 16 + e); 162 | i += 2; 163 | } 164 | } 165 | sb.append(c); 166 | } 167 | return sb.toString(); 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /java-version/src/org/json/CookieList.java: -------------------------------------------------------------------------------- 1 | package org.json; 2 | 3 | /* 4 | Copyright (c) 2002 JSON.org 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | The Software shall be used for Good, not Evil. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | SOFTWARE. 25 | */ 26 | 27 | /** 28 | * Convert a web browser cookie list string to a JSONObject and back. 29 | * @author JSON.org 30 | * @version 2015-12-09 31 | */ 32 | public class CookieList { 33 | 34 | /** 35 | * Convert a cookie list into a JSONObject. A cookie list is a sequence 36 | * of name/value pairs. The names are separated from the values by '='. 37 | * The pairs are separated by ';'. The names and the values 38 | * will be unescaped, possibly converting '+' and '%' sequences. 39 | * 40 | * To add a cookie to a cookie list, 41 | * cookielistJSONObject.put(cookieJSONObject.getString("name"), 42 | * cookieJSONObject.getString("value")); 43 | * @param string A cookie list string 44 | * @return A JSONObject 45 | * @throws JSONException 46 | */ 47 | public static JSONObject toJSONObject(String string) throws JSONException { 48 | JSONObject jo = new JSONObject(); 49 | JSONTokener x = new JSONTokener(string); 50 | while (x.more()) { 51 | String name = Cookie.unescape(x.nextTo('=')); 52 | x.next('='); 53 | jo.put(name, Cookie.unescape(x.nextTo(';'))); 54 | x.next(); 55 | } 56 | return jo; 57 | } 58 | 59 | /** 60 | * Convert a JSONObject into a cookie list. A cookie list is a sequence 61 | * of name/value pairs. The names are separated from the values by '='. 62 | * The pairs are separated by ';'. The characters '%', '+', '=', and ';' 63 | * in the names and values are replaced by "%hh". 64 | * @param jo A JSONObject 65 | * @return A cookie list string 66 | * @throws JSONException 67 | */ 68 | public static String toString(JSONObject jo) throws JSONException { 69 | boolean b = false; 70 | final StringBuilder sb = new StringBuilder(); 71 | // Don't use the new entrySet API to maintain Android support 72 | for (final String key : jo.keySet()) { 73 | final Object value = jo.opt(key); 74 | if (!JSONObject.NULL.equals(value)) { 75 | if (b) { 76 | sb.append(';'); 77 | } 78 | sb.append(Cookie.escape(key)); 79 | sb.append("="); 80 | sb.append(Cookie.escape(value.toString())); 81 | b = true; 82 | } 83 | } 84 | return sb.toString(); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /java-version/src/org/json/HTTP.java: -------------------------------------------------------------------------------- 1 | package org.json; 2 | 3 | /* 4 | Copyright (c) 2002 JSON.org 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | The Software shall be used for Good, not Evil. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | SOFTWARE. 25 | */ 26 | 27 | import java.util.Locale; 28 | 29 | /** 30 | * Convert an HTTP header to a JSONObject and back. 31 | * @author JSON.org 32 | * @version 2015-12-09 33 | */ 34 | public class HTTP { 35 | 36 | /** Carriage return/line feed. */ 37 | public static final String CRLF = "\r\n"; 38 | 39 | /** 40 | * Convert an HTTP header string into a JSONObject. It can be a request 41 | * header or a response header. A request header will contain 42 | *

{
 43 |      *    Method: "POST" (for example),
 44 |      *    "Request-URI": "/" (for example),
 45 |      *    "HTTP-Version": "HTTP/1.1" (for example)
 46 |      * }
47 | * A response header will contain 48 | *
{
 49 |      *    "HTTP-Version": "HTTP/1.1" (for example),
 50 |      *    "Status-Code": "200" (for example),
 51 |      *    "Reason-Phrase": "OK" (for example)
 52 |      * }
53 | * In addition, the other parameters in the header will be captured, using 54 | * the HTTP field names as JSON names, so that
 55 |      *    Date: Sun, 26 May 2002 18:06:04 GMT
 56 |      *    Cookie: Q=q2=PPEAsg--; B=677gi6ouf29bn&b=2&f=s
 57 |      *    Cache-Control: no-cache
58 | * become 59 | *
{...
 60 |      *    Date: "Sun, 26 May 2002 18:06:04 GMT",
 61 |      *    Cookie: "Q=q2=PPEAsg--; B=677gi6ouf29bn&b=2&f=s",
 62 |      *    "Cache-Control": "no-cache",
 63 |      * ...}
64 | * It does no further checking or conversion. It does not parse dates. 65 | * It does not do '%' transforms on URLs. 66 | * @param string An HTTP header string. 67 | * @return A JSONObject containing the elements and attributes 68 | * of the XML string. 69 | * @throws JSONException 70 | */ 71 | public static JSONObject toJSONObject(String string) throws JSONException { 72 | JSONObject jo = new JSONObject(); 73 | HTTPTokener x = new HTTPTokener(string); 74 | String token; 75 | 76 | token = x.nextToken(); 77 | if (token.toUpperCase(Locale.ROOT).startsWith("HTTP")) { 78 | 79 | // Response 80 | 81 | jo.put("HTTP-Version", token); 82 | jo.put("Status-Code", x.nextToken()); 83 | jo.put("Reason-Phrase", x.nextTo('\0')); 84 | x.next(); 85 | 86 | } else { 87 | 88 | // Request 89 | 90 | jo.put("Method", token); 91 | jo.put("Request-URI", x.nextToken()); 92 | jo.put("HTTP-Version", x.nextToken()); 93 | } 94 | 95 | // Fields 96 | 97 | while (x.more()) { 98 | String name = x.nextTo(':'); 99 | x.next(':'); 100 | jo.put(name, x.nextTo('\0')); 101 | x.next(); 102 | } 103 | return jo; 104 | } 105 | 106 | 107 | /** 108 | * Convert a JSONObject into an HTTP header. A request header must contain 109 | *
{
110 |      *    Method: "POST" (for example),
111 |      *    "Request-URI": "/" (for example),
112 |      *    "HTTP-Version": "HTTP/1.1" (for example)
113 |      * }
114 | * A response header must contain 115 | *
{
116 |      *    "HTTP-Version": "HTTP/1.1" (for example),
117 |      *    "Status-Code": "200" (for example),
118 |      *    "Reason-Phrase": "OK" (for example)
119 |      * }
120 | * Any other members of the JSONObject will be output as HTTP fields. 121 | * The result will end with two CRLF pairs. 122 | * @param jo A JSONObject 123 | * @return An HTTP header string. 124 | * @throws JSONException if the object does not contain enough 125 | * information. 126 | */ 127 | public static String toString(JSONObject jo) throws JSONException { 128 | StringBuilder sb = new StringBuilder(); 129 | if (jo.has("Status-Code") && jo.has("Reason-Phrase")) { 130 | sb.append(jo.getString("HTTP-Version")); 131 | sb.append(' '); 132 | sb.append(jo.getString("Status-Code")); 133 | sb.append(' '); 134 | sb.append(jo.getString("Reason-Phrase")); 135 | } else if (jo.has("Method") && jo.has("Request-URI")) { 136 | sb.append(jo.getString("Method")); 137 | sb.append(' '); 138 | sb.append('"'); 139 | sb.append(jo.getString("Request-URI")); 140 | sb.append('"'); 141 | sb.append(' '); 142 | sb.append(jo.getString("HTTP-Version")); 143 | } else { 144 | throw new JSONException("Not enough material for an HTTP header."); 145 | } 146 | sb.append(CRLF); 147 | // Don't use the new entrySet API to maintain Android support 148 | for (final String key : jo.keySet()) { 149 | String value = jo.optString(key); 150 | if (!"HTTP-Version".equals(key) && !"Status-Code".equals(key) && 151 | !"Reason-Phrase".equals(key) && !"Method".equals(key) && 152 | !"Request-URI".equals(key) && !JSONObject.NULL.equals(value)) { 153 | sb.append(key); 154 | sb.append(": "); 155 | sb.append(jo.optString(key)); 156 | sb.append(CRLF); 157 | } 158 | } 159 | sb.append(CRLF); 160 | return sb.toString(); 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /java-version/src/org/json/HTTPTokener.java: -------------------------------------------------------------------------------- 1 | package org.json; 2 | 3 | /* 4 | Copyright (c) 2002 JSON.org 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | The Software shall be used for Good, not Evil. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | SOFTWARE. 25 | */ 26 | 27 | /** 28 | * The HTTPTokener extends the JSONTokener to provide additional methods 29 | * for the parsing of HTTP headers. 30 | * @author JSON.org 31 | * @version 2015-12-09 32 | */ 33 | public class HTTPTokener extends JSONTokener { 34 | 35 | /** 36 | * Construct an HTTPTokener from a string. 37 | * @param string A source string. 38 | */ 39 | public HTTPTokener(String string) { 40 | super(string); 41 | } 42 | 43 | 44 | /** 45 | * Get the next token or string. This is used in parsing HTTP headers. 46 | * @throws JSONException 47 | * @return A String. 48 | */ 49 | public String nextToken() throws JSONException { 50 | char c; 51 | char q; 52 | StringBuilder sb = new StringBuilder(); 53 | do { 54 | c = next(); 55 | } while (Character.isWhitespace(c)); 56 | if (c == '"' || c == '\'') { 57 | q = c; 58 | for (;;) { 59 | c = next(); 60 | if (c < ' ') { 61 | throw syntaxError("Unterminated string."); 62 | } 63 | if (c == q) { 64 | return sb.toString(); 65 | } 66 | sb.append(c); 67 | } 68 | } 69 | for (;;) { 70 | if (c == 0 || Character.isWhitespace(c)) { 71 | return sb.toString(); 72 | } 73 | sb.append(c); 74 | c = next(); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /java-version/src/org/json/JSONException.java: -------------------------------------------------------------------------------- 1 | package org.json; 2 | 3 | /** 4 | * The JSONException is thrown by the JSON.org classes when things are amiss. 5 | * 6 | * @author JSON.org 7 | * @version 2015-12-09 8 | */ 9 | public class JSONException extends RuntimeException { 10 | /** Serialization ID */ 11 | private static final long serialVersionUID = 0; 12 | 13 | /** 14 | * Constructs a JSONException with an explanatory message. 15 | * 16 | * @param message 17 | * Detail about the reason for the exception. 18 | */ 19 | public JSONException(final String message) { 20 | super(message); 21 | } 22 | 23 | /** 24 | * Constructs a JSONException with an explanatory message and cause. 25 | * 26 | * @param message 27 | * Detail about the reason for the exception. 28 | * @param cause 29 | * The cause. 30 | */ 31 | public JSONException(final String message, final Throwable cause) { 32 | super(message, cause); 33 | } 34 | 35 | /** 36 | * Constructs a new JSONException with the specified cause. 37 | * 38 | * @param cause 39 | * The cause. 40 | */ 41 | public JSONException(final Throwable cause) { 42 | super(cause.getMessage(), cause); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /java-version/src/org/json/JSONML.java: -------------------------------------------------------------------------------- 1 | package org.json; 2 | 3 | /* 4 | Copyright (c) 2008 JSON.org 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | The Software shall be used for Good, not Evil. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | SOFTWARE. 25 | */ 26 | 27 | /** 28 | * This provides static methods to convert an XML text into a JSONArray or 29 | * JSONObject, and to covert a JSONArray or JSONObject into an XML text using 30 | * the JsonML transform. 31 | * 32 | * @author JSON.org 33 | * @version 2016-01-30 34 | */ 35 | public class JSONML { 36 | /** 37 | * Parse XML values and store them in a JSONArray. 38 | * @param x The XMLTokener containing the source string. 39 | * @param arrayForm true if array form, false if object form. 40 | * @param ja The JSONArray that is containing the current tag or null 41 | * if we are at the outermost level. 42 | * @param keepStrings Don't type-convert text nodes and attribute values 43 | * @return A JSONArray if the value is the outermost tag, otherwise null. 44 | * @throws JSONException 45 | */ 46 | private static Object parse( 47 | XMLTokener x, 48 | boolean arrayForm, 49 | JSONArray ja, 50 | boolean keepStrings 51 | ) throws JSONException { 52 | String attribute; 53 | char c; 54 | String closeTag = null; 55 | int i; 56 | JSONArray newja = null; 57 | JSONObject newjo = null; 58 | Object token; 59 | String tagName = null; 60 | 61 | // Test for and skip past these forms: 62 | // 63 | // 64 | // 65 | // 66 | 67 | while (true) { 68 | if (!x.more()) { 69 | throw x.syntaxError("Bad XML"); 70 | } 71 | token = x.nextContent(); 72 | if (token == XML.LT) { 73 | token = x.nextToken(); 74 | if (token instanceof Character) { 75 | if (token == XML.SLASH) { 76 | 77 | // Close tag "); 97 | } else { 98 | x.back(); 99 | } 100 | } else if (c == '[') { 101 | token = x.nextToken(); 102 | if (token.equals("CDATA") && x.next() == '[') { 103 | if (ja != null) { 104 | ja.put(x.nextCDATA()); 105 | } 106 | } else { 107 | throw x.syntaxError("Expected 'CDATA['"); 108 | } 109 | } else { 110 | i = 1; 111 | do { 112 | token = x.nextMeta(); 113 | if (token == null) { 114 | throw x.syntaxError("Missing '>' after ' 0); 121 | } 122 | } else if (token == XML.QUEST) { 123 | 124 | // "); 127 | } else { 128 | throw x.syntaxError("Misshaped tag"); 129 | } 130 | 131 | // Open tag < 132 | 133 | } else { 134 | if (!(token instanceof String)) { 135 | throw x.syntaxError("Bad tagName '" + token + "'."); 136 | } 137 | tagName = (String)token; 138 | newja = new JSONArray(); 139 | newjo = new JSONObject(); 140 | if (arrayForm) { 141 | newja.put(tagName); 142 | if (ja != null) { 143 | ja.put(newja); 144 | } 145 | } else { 146 | newjo.put("tagName", tagName); 147 | if (ja != null) { 148 | ja.put(newjo); 149 | } 150 | } 151 | token = null; 152 | for (;;) { 153 | if (token == null) { 154 | token = x.nextToken(); 155 | } 156 | if (token == null) { 157 | throw x.syntaxError("Misshaped tag"); 158 | } 159 | if (!(token instanceof String)) { 160 | break; 161 | } 162 | 163 | // attribute = value 164 | 165 | attribute = (String)token; 166 | if (!arrayForm && ("tagName".equals(attribute) || "childNode".equals(attribute))) { 167 | throw x.syntaxError("Reserved attribute."); 168 | } 169 | token = x.nextToken(); 170 | if (token == XML.EQ) { 171 | token = x.nextToken(); 172 | if (!(token instanceof String)) { 173 | throw x.syntaxError("Missing value"); 174 | } 175 | newjo.accumulate(attribute, keepStrings ? ((String)token) :XML.stringToValue((String)token)); 176 | token = null; 177 | } else { 178 | newjo.accumulate(attribute, ""); 179 | } 180 | } 181 | if (arrayForm && newjo.length() > 0) { 182 | newja.put(newjo); 183 | } 184 | 185 | // Empty tag <.../> 186 | 187 | if (token == XML.SLASH) { 188 | if (x.nextToken() != XML.GT) { 189 | throw x.syntaxError("Misshaped tag"); 190 | } 191 | if (ja == null) { 192 | if (arrayForm) { 193 | return newja; 194 | } 195 | return newjo; 196 | } 197 | 198 | // Content, between <...> and 199 | 200 | } else { 201 | if (token != XML.GT) { 202 | throw x.syntaxError("Misshaped tag"); 203 | } 204 | closeTag = (String)parse(x, arrayForm, newja, keepStrings); 205 | if (closeTag != null) { 206 | if (!closeTag.equals(tagName)) { 207 | throw x.syntaxError("Mismatched '" + tagName + 208 | "' and '" + closeTag + "'"); 209 | } 210 | tagName = null; 211 | if (!arrayForm && newja.length() > 0) { 212 | newjo.put("childNodes", newja); 213 | } 214 | if (ja == null) { 215 | if (arrayForm) { 216 | return newja; 217 | } 218 | return newjo; 219 | } 220 | } 221 | } 222 | } 223 | } else { 224 | if (ja != null) { 225 | ja.put(token instanceof String 226 | ? keepStrings ? XML.unescape((String)token) :XML.stringToValue((String)token) 227 | : token); 228 | } 229 | } 230 | } 231 | } 232 | 233 | 234 | /** 235 | * Convert a well-formed (but not necessarily valid) XML string into a 236 | * JSONArray using the JsonML transform. Each XML tag is represented as 237 | * a JSONArray in which the first element is the tag name. If the tag has 238 | * attributes, then the second element will be JSONObject containing the 239 | * name/value pairs. If the tag contains children, then strings and 240 | * JSONArrays will represent the child tags. 241 | * Comments, prologs, DTDs, and <[ [ ]]> are ignored. 242 | * @param string The source string. 243 | * @return A JSONArray containing the structured data from the XML string. 244 | * @throws JSONException Thrown on error converting to a JSONArray 245 | */ 246 | public static JSONArray toJSONArray(String string) throws JSONException { 247 | return (JSONArray)parse(new XMLTokener(string), true, null, false); 248 | } 249 | 250 | 251 | /** 252 | * Convert a well-formed (but not necessarily valid) XML string into a 253 | * JSONArray using the JsonML transform. Each XML tag is represented as 254 | * a JSONArray in which the first element is the tag name. If the tag has 255 | * attributes, then the second element will be JSONObject containing the 256 | * name/value pairs. If the tag contains children, then strings and 257 | * JSONArrays will represent the child tags. 258 | * As opposed to toJSONArray this method does not attempt to convert 259 | * any text node or attribute value to any type 260 | * but just leaves it as a string. 261 | * Comments, prologs, DTDs, and <[ [ ]]> are ignored. 262 | * @param string The source string. 263 | * @param keepStrings If true, then values will not be coerced into boolean 264 | * or numeric values and will instead be left as strings 265 | * @return A JSONArray containing the structured data from the XML string. 266 | * @throws JSONException Thrown on error converting to a JSONArray 267 | */ 268 | public static JSONArray toJSONArray(String string, boolean keepStrings) throws JSONException { 269 | return (JSONArray)parse(new XMLTokener(string), true, null, keepStrings); 270 | } 271 | 272 | 273 | /** 274 | * Convert a well-formed (but not necessarily valid) XML string into a 275 | * JSONArray using the JsonML transform. Each XML tag is represented as 276 | * a JSONArray in which the first element is the tag name. If the tag has 277 | * attributes, then the second element will be JSONObject containing the 278 | * name/value pairs. If the tag contains children, then strings and 279 | * JSONArrays will represent the child content and tags. 280 | * As opposed to toJSONArray this method does not attempt to convert 281 | * any text node or attribute value to any type 282 | * but just leaves it as a string. 283 | * Comments, prologs, DTDs, and <[ [ ]]> are ignored. 284 | * @param x An XMLTokener. 285 | * @param keepStrings If true, then values will not be coerced into boolean 286 | * or numeric values and will instead be left as strings 287 | * @return A JSONArray containing the structured data from the XML string. 288 | * @throws JSONException Thrown on error converting to a JSONArray 289 | */ 290 | public static JSONArray toJSONArray(XMLTokener x, boolean keepStrings) throws JSONException { 291 | return (JSONArray)parse(x, true, null, keepStrings); 292 | } 293 | 294 | 295 | /** 296 | * Convert a well-formed (but not necessarily valid) XML string into a 297 | * JSONArray using the JsonML transform. Each XML tag is represented as 298 | * a JSONArray in which the first element is the tag name. If the tag has 299 | * attributes, then the second element will be JSONObject containing the 300 | * name/value pairs. If the tag contains children, then strings and 301 | * JSONArrays will represent the child content and tags. 302 | * Comments, prologs, DTDs, and <[ [ ]]> are ignored. 303 | * @param x An XMLTokener. 304 | * @return A JSONArray containing the structured data from the XML string. 305 | * @throws JSONException Thrown on error converting to a JSONArray 306 | */ 307 | public static JSONArray toJSONArray(XMLTokener x) throws JSONException { 308 | return (JSONArray)parse(x, true, null, false); 309 | } 310 | 311 | 312 | /** 313 | * Convert a well-formed (but not necessarily valid) XML string into a 314 | * JSONObject using the JsonML transform. Each XML tag is represented as 315 | * a JSONObject with a "tagName" property. If the tag has attributes, then 316 | * the attributes will be in the JSONObject as properties. If the tag 317 | * contains children, the object will have a "childNodes" property which 318 | * will be an array of strings and JsonML JSONObjects. 319 | 320 | * Comments, prologs, DTDs, and <[ [ ]]> are ignored. 321 | * @param string The XML source text. 322 | * @return A JSONObject containing the structured data from the XML string. 323 | * @throws JSONException Thrown on error converting to a JSONObject 324 | */ 325 | public static JSONObject toJSONObject(String string) throws JSONException { 326 | return (JSONObject)parse(new XMLTokener(string), false, null, false); 327 | } 328 | 329 | 330 | /** 331 | * Convert a well-formed (but not necessarily valid) XML string into a 332 | * JSONObject using the JsonML transform. Each XML tag is represented as 333 | * a JSONObject with a "tagName" property. If the tag has attributes, then 334 | * the attributes will be in the JSONObject as properties. If the tag 335 | * contains children, the object will have a "childNodes" property which 336 | * will be an array of strings and JsonML JSONObjects. 337 | 338 | * Comments, prologs, DTDs, and <[ [ ]]> are ignored. 339 | * @param string The XML source text. 340 | * @param keepStrings If true, then values will not be coerced into boolean 341 | * or numeric values and will instead be left as strings 342 | * @return A JSONObject containing the structured data from the XML string. 343 | * @throws JSONException Thrown on error converting to a JSONObject 344 | */ 345 | public static JSONObject toJSONObject(String string, boolean keepStrings) throws JSONException { 346 | return (JSONObject)parse(new XMLTokener(string), false, null, keepStrings); 347 | } 348 | 349 | 350 | /** 351 | * Convert a well-formed (but not necessarily valid) XML string into a 352 | * JSONObject using the JsonML transform. Each XML tag is represented as 353 | * a JSONObject with a "tagName" property. If the tag has attributes, then 354 | * the attributes will be in the JSONObject as properties. If the tag 355 | * contains children, the object will have a "childNodes" property which 356 | * will be an array of strings and JsonML JSONObjects. 357 | 358 | * Comments, prologs, DTDs, and <[ [ ]]> are ignored. 359 | * @param x An XMLTokener of the XML source text. 360 | * @return A JSONObject containing the structured data from the XML string. 361 | * @throws JSONException Thrown on error converting to a JSONObject 362 | */ 363 | public static JSONObject toJSONObject(XMLTokener x) throws JSONException { 364 | return (JSONObject)parse(x, false, null, false); 365 | } 366 | 367 | 368 | /** 369 | * Convert a well-formed (but not necessarily valid) XML string into a 370 | * JSONObject using the JsonML transform. Each XML tag is represented as 371 | * a JSONObject with a "tagName" property. If the tag has attributes, then 372 | * the attributes will be in the JSONObject as properties. If the tag 373 | * contains children, the object will have a "childNodes" property which 374 | * will be an array of strings and JsonML JSONObjects. 375 | 376 | * Comments, prologs, DTDs, and <[ [ ]]> are ignored. 377 | * @param x An XMLTokener of the XML source text. 378 | * @param keepStrings If true, then values will not be coerced into boolean 379 | * or numeric values and will instead be left as strings 380 | * @return A JSONObject containing the structured data from the XML string. 381 | * @throws JSONException Thrown on error converting to a JSONObject 382 | */ 383 | public static JSONObject toJSONObject(XMLTokener x, boolean keepStrings) throws JSONException { 384 | return (JSONObject)parse(x, false, null, keepStrings); 385 | } 386 | 387 | 388 | /** 389 | * Reverse the JSONML transformation, making an XML text from a JSONArray. 390 | * @param ja A JSONArray. 391 | * @return An XML string. 392 | * @throws JSONException Thrown on error converting to a string 393 | */ 394 | public static String toString(JSONArray ja) throws JSONException { 395 | int i; 396 | JSONObject jo; 397 | int length; 398 | Object object; 399 | StringBuilder sb = new StringBuilder(); 400 | String tagName; 401 | 402 | // Emit = length) { 438 | sb.append('/'); 439 | sb.append('>'); 440 | } else { 441 | sb.append('>'); 442 | do { 443 | object = ja.get(i); 444 | i += 1; 445 | if (object != null) { 446 | if (object instanceof String) { 447 | sb.append(XML.escape(object.toString())); 448 | } else if (object instanceof JSONObject) { 449 | sb.append(toString((JSONObject)object)); 450 | } else if (object instanceof JSONArray) { 451 | sb.append(toString((JSONArray)object)); 452 | } else { 453 | sb.append(object.toString()); 454 | } 455 | } 456 | } while (i < length); 457 | sb.append('<'); 458 | sb.append('/'); 459 | sb.append(tagName); 460 | sb.append('>'); 461 | } 462 | return sb.toString(); 463 | } 464 | 465 | /** 466 | * Reverse the JSONML transformation, making an XML text from a JSONObject. 467 | * The JSONObject must contain a "tagName" property. If it has children, 468 | * then it must have a "childNodes" property containing an array of objects. 469 | * The other properties are attributes with string values. 470 | * @param jo A JSONObject. 471 | * @return An XML string. 472 | * @throws JSONException Thrown on error converting to a string 473 | */ 474 | public static String toString(JSONObject jo) throws JSONException { 475 | StringBuilder sb = new StringBuilder(); 476 | int i; 477 | JSONArray ja; 478 | int length; 479 | Object object; 480 | String tagName; 481 | Object value; 482 | 483 | //Emit '); 518 | } else { 519 | sb.append('>'); 520 | length = ja.length(); 521 | for (i = 0; i < length; i += 1) { 522 | object = ja.get(i); 523 | if (object != null) { 524 | if (object instanceof String) { 525 | sb.append(XML.escape(object.toString())); 526 | } else if (object instanceof JSONObject) { 527 | sb.append(toString((JSONObject)object)); 528 | } else if (object instanceof JSONArray) { 529 | sb.append(toString((JSONArray)object)); 530 | } else { 531 | sb.append(object.toString()); 532 | } 533 | } 534 | } 535 | sb.append('<'); 536 | sb.append('/'); 537 | sb.append(tagName); 538 | sb.append('>'); 539 | } 540 | return sb.toString(); 541 | } 542 | } 543 | -------------------------------------------------------------------------------- /java-version/src/org/json/JSONPointer.java: -------------------------------------------------------------------------------- 1 | package org.json; 2 | 3 | import static java.lang.String.format; 4 | 5 | import java.io.UnsupportedEncodingException; 6 | import java.net.URLDecoder; 7 | import java.net.URLEncoder; 8 | import java.util.ArrayList; 9 | import java.util.Collections; 10 | import java.util.List; 11 | 12 | /* 13 | Copyright (c) 2002 JSON.org 14 | 15 | Permission is hereby granted, free of charge, to any person obtaining a copy 16 | of this software and associated documentation files (the "Software"), to deal 17 | in the Software without restriction, including without limitation the rights 18 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 19 | copies of the Software, and to permit persons to whom the Software is 20 | furnished to do so, subject to the following conditions: 21 | 22 | The above copyright notice and this permission notice shall be included in all 23 | copies or substantial portions of the Software. 24 | 25 | The Software shall be used for Good, not Evil. 26 | 27 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 28 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 29 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 30 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 31 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 32 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 33 | SOFTWARE. 34 | */ 35 | 36 | /** 37 | * A JSON Pointer is a simple query language defined for JSON documents by 38 | * RFC 6901. 39 | * 40 | * In a nutshell, JSONPointer allows the user to navigate into a JSON document 41 | * using strings, and retrieve targeted objects, like a simple form of XPATH. 42 | * Path segments are separated by the '/' char, which signifies the root of 43 | * the document when it appears as the first char of the string. Array 44 | * elements are navigated using ordinals, counting from 0. JSONPointer strings 45 | * may be extended to any arbitrary number of segments. If the navigation 46 | * is successful, the matched item is returned. A matched item may be a 47 | * JSONObject, a JSONArray, or a JSON value. If the JSONPointer string building 48 | * fails, an appropriate exception is thrown. If the navigation fails to find 49 | * a match, a JSONPointerException is thrown. 50 | * 51 | * @author JSON.org 52 | * @version 2016-05-14 53 | */ 54 | public class JSONPointer { 55 | 56 | // used for URL encoding and decoding 57 | private static final String ENCODING = "utf-8"; 58 | 59 | /** 60 | * This class allows the user to build a JSONPointer in steps, using 61 | * exactly one segment in each step. 62 | */ 63 | public static class Builder { 64 | 65 | // Segments for the eventual JSONPointer string 66 | private final List refTokens = new ArrayList(); 67 | 68 | /** 69 | * Creates a {@code JSONPointer} instance using the tokens previously set using the 70 | * {@link #append(String)} method calls. 71 | */ 72 | public JSONPointer build() { 73 | return new JSONPointer(this.refTokens); 74 | } 75 | 76 | /** 77 | * Adds an arbitrary token to the list of reference tokens. It can be any non-null value. 78 | * 79 | * Unlike in the case of JSON string or URI fragment representation of JSON pointers, the 80 | * argument of this method MUST NOT be escaped. If you want to query the property called 81 | * {@code "a~b"} then you should simply pass the {@code "a~b"} string as-is, there is no 82 | * need to escape it as {@code "a~0b"}. 83 | * 84 | * @param token the new token to be appended to the list 85 | * @return {@code this} 86 | * @throws NullPointerException if {@code token} is null 87 | */ 88 | public Builder append(String token) { 89 | if (token == null) { 90 | throw new NullPointerException("token cannot be null"); 91 | } 92 | this.refTokens.add(token); 93 | return this; 94 | } 95 | 96 | /** 97 | * Adds an integer to the reference token list. Although not necessarily, mostly this token will 98 | * denote an array index. 99 | * 100 | * @param arrayIndex the array index to be added to the token list 101 | * @return {@code this} 102 | */ 103 | public Builder append(int arrayIndex) { 104 | this.refTokens.add(String.valueOf(arrayIndex)); 105 | return this; 106 | } 107 | } 108 | 109 | /** 110 | * Static factory method for {@link Builder}. Example usage: 111 | * 112 | *

113 |      * JSONPointer pointer = JSONPointer.builder()
114 |      *       .append("obj")
115 |      *       .append("other~key").append("another/key")
116 |      *       .append("\"")
117 |      *       .append(0)
118 |      *       .build();
119 |      * 
120 | * 121 | * @return a builder instance which can be used to construct a {@code JSONPointer} instance by chained 122 | * {@link Builder#append(String)} calls. 123 | */ 124 | public static Builder builder() { 125 | return new Builder(); 126 | } 127 | 128 | // Segments for the JSONPointer string 129 | private final List refTokens; 130 | 131 | /** 132 | * Pre-parses and initializes a new {@code JSONPointer} instance. If you want to 133 | * evaluate the same JSON Pointer on different JSON documents then it is recommended 134 | * to keep the {@code JSONPointer} instances due to performance considerations. 135 | * 136 | * @param pointer the JSON String or URI Fragment representation of the JSON pointer. 137 | * @throws IllegalArgumentException if {@code pointer} is not a valid JSON pointer 138 | */ 139 | public JSONPointer(final String pointer) { 140 | if (pointer == null) { 141 | throw new NullPointerException("pointer cannot be null"); 142 | } 143 | if (pointer.isEmpty() || pointer.equals("#")) { 144 | this.refTokens = Collections.emptyList(); 145 | return; 146 | } 147 | String refs; 148 | if (pointer.startsWith("#/")) { 149 | refs = pointer.substring(2); 150 | try { 151 | refs = URLDecoder.decode(refs, ENCODING); 152 | } catch (UnsupportedEncodingException e) { 153 | throw new RuntimeException(e); 154 | } 155 | } else if (pointer.startsWith("/")) { 156 | refs = pointer.substring(1); 157 | } else { 158 | throw new IllegalArgumentException("a JSON pointer should start with '/' or '#/'"); 159 | } 160 | this.refTokens = new ArrayList(); 161 | int slashIdx = -1; 162 | int prevSlashIdx = 0; 163 | do { 164 | prevSlashIdx = slashIdx + 1; 165 | slashIdx = refs.indexOf('/', prevSlashIdx); 166 | if(prevSlashIdx == slashIdx || prevSlashIdx == refs.length()) { 167 | // found 2 slashes in a row ( obj//next ) 168 | // or single slash at the end of a string ( obj/test/ ) 169 | this.refTokens.add(""); 170 | } else if (slashIdx >= 0) { 171 | final String token = refs.substring(prevSlashIdx, slashIdx); 172 | this.refTokens.add(unescape(token)); 173 | } else { 174 | // last item after separator, or no separator at all. 175 | final String token = refs.substring(prevSlashIdx); 176 | this.refTokens.add(unescape(token)); 177 | } 178 | } while (slashIdx >= 0); 179 | // using split does not take into account consecutive separators or "ending nulls" 180 | //for (String token : refs.split("/")) { 181 | // this.refTokens.add(unescape(token)); 182 | //} 183 | } 184 | 185 | public JSONPointer(List refTokens) { 186 | this.refTokens = new ArrayList(refTokens); 187 | } 188 | 189 | private String unescape(String token) { 190 | return token.replace("~1", "/").replace("~0", "~") 191 | .replace("\\\"", "\"") 192 | .replace("\\\\", "\\"); 193 | } 194 | 195 | /** 196 | * Evaluates this JSON Pointer on the given {@code document}. The {@code document} 197 | * is usually a {@link JSONObject} or a {@link JSONArray} instance, but the empty 198 | * JSON Pointer ({@code ""}) can be evaluated on any JSON values and in such case the 199 | * returned value will be {@code document} itself. 200 | * 201 | * @param document the JSON document which should be the subject of querying. 202 | * @return the result of the evaluation 203 | * @throws JSONPointerException if an error occurs during evaluation 204 | */ 205 | public Object queryFrom(Object document) throws JSONPointerException { 206 | if (this.refTokens.isEmpty()) { 207 | return document; 208 | } 209 | Object current = document; 210 | for (String token : this.refTokens) { 211 | if (current instanceof JSONObject) { 212 | current = ((JSONObject) current).opt(unescape(token)); 213 | } else if (current instanceof JSONArray) { 214 | current = readByIndexToken(current, token); 215 | } else { 216 | throw new JSONPointerException(format( 217 | "value [%s] is not an array or object therefore its key %s cannot be resolved", current, 218 | token)); 219 | } 220 | } 221 | return current; 222 | } 223 | 224 | /** 225 | * Matches a JSONArray element by ordinal position 226 | * @param current the JSONArray to be evaluated 227 | * @param indexToken the array index in string form 228 | * @return the matched object. If no matching item is found a 229 | * @throws JSONPointerException is thrown if the index is out of bounds 230 | */ 231 | private Object readByIndexToken(Object current, String indexToken) throws JSONPointerException { 232 | try { 233 | int index = Integer.parseInt(indexToken); 234 | JSONArray currentArr = (JSONArray) current; 235 | if (index >= currentArr.length()) { 236 | throw new JSONPointerException(format("index %d is out of bounds - the array has %d elements", index, 237 | currentArr.length())); 238 | } 239 | try { 240 | return currentArr.get(index); 241 | } catch (JSONException e) { 242 | throw new JSONPointerException("Error reading value at index position " + index, e); 243 | } 244 | } catch (NumberFormatException e) { 245 | throw new JSONPointerException(format("%s is not an array index", indexToken), e); 246 | } 247 | } 248 | 249 | /** 250 | * Returns a string representing the JSONPointer path value using string 251 | * representation 252 | */ 253 | @Override 254 | public String toString() { 255 | StringBuilder rval = new StringBuilder(""); 256 | for (String token: this.refTokens) { 257 | rval.append('/').append(escape(token)); 258 | } 259 | return rval.toString(); 260 | } 261 | 262 | /** 263 | * Escapes path segment values to an unambiguous form. 264 | * The escape char to be inserted is '~'. The chars to be escaped 265 | * are ~, which maps to ~0, and /, which maps to ~1. Backslashes 266 | * and double quote chars are also escaped. 267 | * @param token the JSONPointer segment value to be escaped 268 | * @return the escaped value for the token 269 | */ 270 | private String escape(String token) { 271 | return token.replace("~", "~0") 272 | .replace("/", "~1") 273 | .replace("\\", "\\\\") 274 | .replace("\"", "\\\""); 275 | } 276 | 277 | /** 278 | * Returns a string representing the JSONPointer path value using URI 279 | * fragment identifier representation 280 | */ 281 | public String toURIFragment() { 282 | try { 283 | StringBuilder rval = new StringBuilder("#"); 284 | for (String token : this.refTokens) { 285 | rval.append('/').append(URLEncoder.encode(token, ENCODING)); 286 | } 287 | return rval.toString(); 288 | } catch (UnsupportedEncodingException e) { 289 | throw new RuntimeException(e); 290 | } 291 | } 292 | 293 | } 294 | -------------------------------------------------------------------------------- /java-version/src/org/json/JSONPointerException.java: -------------------------------------------------------------------------------- 1 | package org.json; 2 | 3 | /* 4 | Copyright (c) 2002 JSON.org 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | The Software shall be used for Good, not Evil. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | SOFTWARE. 25 | */ 26 | 27 | /** 28 | * The JSONPointerException is thrown by {@link JSONPointer} if an error occurs 29 | * during evaluating a pointer. 30 | * 31 | * @author JSON.org 32 | * @version 2016-05-13 33 | */ 34 | public class JSONPointerException extends JSONException { 35 | private static final long serialVersionUID = 8872944667561856751L; 36 | 37 | public JSONPointerException(String message) { 38 | super(message); 39 | } 40 | 41 | public JSONPointerException(String message, Throwable cause) { 42 | super(message, cause); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /java-version/src/org/json/JSONPropertyIgnore.java: -------------------------------------------------------------------------------- 1 | package org.json; 2 | 3 | /* 4 | Copyright (c) 2018 JSON.org 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | The Software shall be used for Good, not Evil. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | SOFTWARE. 25 | */ 26 | 27 | import static java.lang.annotation.ElementType.METHOD; 28 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 29 | 30 | import java.lang.annotation.Documented; 31 | import java.lang.annotation.Retention; 32 | import java.lang.annotation.Target; 33 | 34 | @Documented 35 | @Retention(RUNTIME) 36 | @Target({METHOD}) 37 | /** 38 | * Use this annotation on a getter method to override the Bean name 39 | * parser for Bean -> JSONObject mapping. If this annotation is 40 | * present at any level in the class hierarchy, then the method will 41 | * not be serialized from the bean into the JSONObject. 42 | */ 43 | public @interface JSONPropertyIgnore { } 44 | -------------------------------------------------------------------------------- /java-version/src/org/json/JSONPropertyName.java: -------------------------------------------------------------------------------- 1 | package org.json; 2 | 3 | /* 4 | Copyright (c) 2018 JSON.org 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | The Software shall be used for Good, not Evil. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | SOFTWARE. 25 | */ 26 | 27 | import static java.lang.annotation.ElementType.METHOD; 28 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 29 | 30 | import java.lang.annotation.Documented; 31 | import java.lang.annotation.Retention; 32 | import java.lang.annotation.Target; 33 | 34 | @Documented 35 | @Retention(RUNTIME) 36 | @Target({METHOD}) 37 | /** 38 | * Use this annotation on a getter method to override the Bean name 39 | * parser for Bean -> JSONObject mapping. A value set to empty string "" 40 | * will have the Bean parser fall back to the default field name processing. 41 | */ 42 | public @interface JSONPropertyName { 43 | /** 44 | * @return The name of the property as to be used in the JSON Object. 45 | */ 46 | String value(); 47 | } 48 | -------------------------------------------------------------------------------- /java-version/src/org/json/JSONString.java: -------------------------------------------------------------------------------- 1 | package org.json; 2 | /** 3 | * The JSONString interface allows a toJSONString() 4 | * method so that a class can change the behavior of 5 | * JSONObject.toString(), JSONArray.toString(), 6 | * and JSONWriter.value(Object). The 7 | * toJSONString method will be used instead of the default behavior 8 | * of using the Object's toString() method and quoting the result. 9 | */ 10 | public interface JSONString { 11 | /** 12 | * The toJSONString method allows a class to produce its own JSON 13 | * serialization. 14 | * 15 | * @return A strictly syntactically correct JSON text. 16 | */ 17 | public String toJSONString(); 18 | } 19 | -------------------------------------------------------------------------------- /java-version/src/org/json/JSONStringer.java: -------------------------------------------------------------------------------- 1 | package org.json; 2 | 3 | /* 4 | Copyright (c) 2006 JSON.org 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | The Software shall be used for Good, not Evil. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | SOFTWARE. 25 | */ 26 | 27 | import java.io.StringWriter; 28 | 29 | /** 30 | * JSONStringer provides a quick and convenient way of producing JSON text. 31 | * The texts produced strictly conform to JSON syntax rules. No whitespace is 32 | * added, so the results are ready for transmission or storage. Each instance of 33 | * JSONStringer can produce one JSON text. 34 | *

35 | * A JSONStringer instance provides a value method for appending 36 | * values to the 37 | * text, and a key 38 | * method for adding keys before values in objects. There are array 39 | * and endArray methods that make and bound array values, and 40 | * object and endObject methods which make and bound 41 | * object values. All of these methods return the JSONWriter instance, 42 | * permitting cascade style. For example,

43 |  * myString = new JSONStringer()
44 |  *     .object()
45 |  *         .key("JSON")
46 |  *         .value("Hello, World!")
47 |  *     .endObject()
48 |  *     .toString();
which produces the string
49 |  * {"JSON":"Hello, World!"}
50 | *

51 | * The first method called must be array or object. 52 | * There are no methods for adding commas or colons. JSONStringer adds them for 53 | * you. Objects and arrays can be nested up to 20 levels deep. 54 | *

55 | * This can sometimes be easier than using a JSONObject to build a string. 56 | * @author JSON.org 57 | * @version 2015-12-09 58 | */ 59 | public class JSONStringer extends JSONWriter { 60 | /** 61 | * Make a fresh JSONStringer. It can be used to build one JSON text. 62 | */ 63 | public JSONStringer() { 64 | super(new StringWriter()); 65 | } 66 | 67 | /** 68 | * Return the JSON text. This method is used to obtain the product of the 69 | * JSONStringer instance. It will return null if there was a 70 | * problem in the construction of the JSON text (such as the calls to 71 | * array were not properly balanced with calls to 72 | * endArray). 73 | * @return The JSON text. 74 | */ 75 | @Override 76 | public String toString() { 77 | return this.mode == 'd' ? this.writer.toString() : null; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /java-version/src/org/json/JSONTokener.java: -------------------------------------------------------------------------------- 1 | package org.json; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | import java.io.InputStreamReader; 7 | import java.io.Reader; 8 | import java.io.StringReader; 9 | 10 | /* 11 | Copyright (c) 2002 JSON.org 12 | 13 | Permission is hereby granted, free of charge, to any person obtaining a copy 14 | of this software and associated documentation files (the "Software"), to deal 15 | in the Software without restriction, including without limitation the rights 16 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 | copies of the Software, and to permit persons to whom the Software is 18 | furnished to do so, subject to the following conditions: 19 | 20 | The above copyright notice and this permission notice shall be included in all 21 | copies or substantial portions of the Software. 22 | 23 | The Software shall be used for Good, not Evil. 24 | 25 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 26 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 27 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 28 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 29 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 30 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31 | SOFTWARE. 32 | */ 33 | 34 | /** 35 | * A JSONTokener takes a source string and extracts characters and tokens from 36 | * it. It is used by the JSONObject and JSONArray constructors to parse 37 | * JSON source strings. 38 | * @author JSON.org 39 | * @version 2014-05-03 40 | */ 41 | public class JSONTokener { 42 | /** current read character position on the current line. */ 43 | private long character; 44 | /** flag to indicate if the end of the input has been found. */ 45 | private boolean eof; 46 | /** current read index of the input. */ 47 | private long index; 48 | /** current line of the input. */ 49 | private long line; 50 | /** previous character read from the input. */ 51 | private char previous; 52 | /** Reader for the input. */ 53 | private final Reader reader; 54 | /** flag to indicate that a previous character was requested. */ 55 | private boolean usePrevious; 56 | /** the number of characters read in the previous line. */ 57 | private long characterPreviousLine; 58 | 59 | 60 | /** 61 | * Construct a JSONTokener from a Reader. The caller must close the Reader. 62 | * 63 | * @param reader A reader. 64 | */ 65 | public JSONTokener(Reader reader) { 66 | this.reader = reader.markSupported() 67 | ? reader 68 | : new BufferedReader(reader); 69 | this.eof = false; 70 | this.usePrevious = false; 71 | this.previous = 0; 72 | this.index = 0; 73 | this.character = 1; 74 | this.characterPreviousLine = 0; 75 | this.line = 1; 76 | } 77 | 78 | 79 | /** 80 | * Construct a JSONTokener from an InputStream. The caller must close the input stream. 81 | * @param inputStream The source. 82 | */ 83 | public JSONTokener(InputStream inputStream) { 84 | this(new InputStreamReader(inputStream)); 85 | } 86 | 87 | 88 | /** 89 | * Construct a JSONTokener from a string. 90 | * 91 | * @param s A source string. 92 | */ 93 | public JSONTokener(String s) { 94 | this(new StringReader(s)); 95 | } 96 | 97 | 98 | /** 99 | * Back up one character. This provides a sort of lookahead capability, 100 | * so that you can test for a digit or letter before attempting to parse 101 | * the next number or identifier. 102 | * @throws JSONException Thrown if trying to step back more than 1 step 103 | * or if already at the start of the string 104 | */ 105 | public void back() throws JSONException { 106 | if (this.usePrevious || this.index <= 0) { 107 | throw new JSONException("Stepping back two steps is not supported"); 108 | } 109 | this.decrementIndexes(); 110 | this.usePrevious = true; 111 | this.eof = false; 112 | } 113 | 114 | /** 115 | * Decrements the indexes for the {@link #back()} method based on the previous character read. 116 | */ 117 | private void decrementIndexes() { 118 | this.index--; 119 | if(this.previous=='\r' || this.previous == '\n') { 120 | this.line--; 121 | this.character=this.characterPreviousLine ; 122 | } else if(this.character > 0){ 123 | this.character--; 124 | } 125 | } 126 | 127 | /** 128 | * Get the hex value of a character (base16). 129 | * @param c A character between '0' and '9' or between 'A' and 'F' or 130 | * between 'a' and 'f'. 131 | * @return An int between 0 and 15, or -1 if c was not a hex digit. 132 | */ 133 | public static int dehexchar(char c) { 134 | if (c >= '0' && c <= '9') { 135 | return c - '0'; 136 | } 137 | if (c >= 'A' && c <= 'F') { 138 | return c - ('A' - 10); 139 | } 140 | if (c >= 'a' && c <= 'f') { 141 | return c - ('a' - 10); 142 | } 143 | return -1; 144 | } 145 | 146 | /** 147 | * Checks if the end of the input has been reached. 148 | * 149 | * @return true if at the end of the file and we didn't step back 150 | */ 151 | public boolean end() { 152 | return this.eof && !this.usePrevious; 153 | } 154 | 155 | 156 | /** 157 | * Determine if the source string still contains characters that next() 158 | * can consume. 159 | * @return true if not yet at the end of the source. 160 | * @throws JSONException thrown if there is an error stepping forward 161 | * or backward while checking for more data. 162 | */ 163 | public boolean more() throws JSONException { 164 | if(this.usePrevious) { 165 | return true; 166 | } 167 | try { 168 | this.reader.mark(1); 169 | } catch (IOException e) { 170 | throw new JSONException("Unable to preserve stream position", e); 171 | } 172 | try { 173 | // -1 is EOF, but next() can not consume the null character '\0' 174 | if(this.reader.read() <= 0) { 175 | this.eof = true; 176 | return false; 177 | } 178 | this.reader.reset(); 179 | } catch (IOException e) { 180 | throw new JSONException("Unable to read the next character from the stream", e); 181 | } 182 | return true; 183 | } 184 | 185 | 186 | /** 187 | * Get the next character in the source string. 188 | * 189 | * @return The next character, or 0 if past the end of the source string. 190 | * @throws JSONException Thrown if there is an error reading the source string. 191 | */ 192 | public char next() throws JSONException { 193 | int c; 194 | if (this.usePrevious) { 195 | this.usePrevious = false; 196 | c = this.previous; 197 | } else { 198 | try { 199 | c = this.reader.read(); 200 | } catch (IOException exception) { 201 | throw new JSONException(exception); 202 | } 203 | } 204 | if (c <= 0) { // End of stream 205 | this.eof = true; 206 | return 0; 207 | } 208 | this.incrementIndexes(c); 209 | this.previous = (char) c; 210 | return this.previous; 211 | } 212 | 213 | /** 214 | * Increments the internal indexes according to the previous character 215 | * read and the character passed as the current character. 216 | * @param c the current character read. 217 | */ 218 | private void incrementIndexes(int c) { 219 | if(c > 0) { 220 | this.index++; 221 | if(c=='\r') { 222 | this.line++; 223 | this.characterPreviousLine = this.character; 224 | this.character=0; 225 | }else if (c=='\n') { 226 | if(this.previous != '\r') { 227 | this.line++; 228 | this.characterPreviousLine = this.character; 229 | } 230 | this.character=0; 231 | } else { 232 | this.character++; 233 | } 234 | } 235 | } 236 | 237 | /** 238 | * Consume the next character, and check that it matches a specified 239 | * character. 240 | * @param c The character to match. 241 | * @return The character. 242 | * @throws JSONException if the character does not match. 243 | */ 244 | public char next(char c) throws JSONException { 245 | char n = this.next(); 246 | if (n != c) { 247 | if(n > 0) { 248 | throw this.syntaxError("Expected '" + c + "' and instead saw '" + 249 | n + "'"); 250 | } 251 | throw this.syntaxError("Expected '" + c + "' and instead saw ''"); 252 | } 253 | return n; 254 | } 255 | 256 | 257 | /** 258 | * Get the next n characters. 259 | * 260 | * @param n The number of characters to take. 261 | * @return A string of n characters. 262 | * @throws JSONException 263 | * Substring bounds error if there are not 264 | * n characters remaining in the source string. 265 | */ 266 | public String next(int n) throws JSONException { 267 | if (n == 0) { 268 | return ""; 269 | } 270 | 271 | char[] chars = new char[n]; 272 | int pos = 0; 273 | 274 | while (pos < n) { 275 | chars[pos] = this.next(); 276 | if (this.end()) { 277 | throw this.syntaxError("Substring bounds error"); 278 | } 279 | pos += 1; 280 | } 281 | return new String(chars); 282 | } 283 | 284 | 285 | /** 286 | * Get the next char in the string, skipping whitespace. 287 | * @throws JSONException Thrown if there is an error reading the source string. 288 | * @return A character, or 0 if there are no more characters. 289 | */ 290 | public char nextClean() throws JSONException { 291 | for (;;) { 292 | char c = this.next(); 293 | if (c == 0 || c > ' ') { 294 | return c; 295 | } 296 | } 297 | } 298 | 299 | 300 | /** 301 | * Return the characters up to the next close quote character. 302 | * Backslash processing is done. The formal JSON format does not 303 | * allow strings in single quotes, but an implementation is allowed to 304 | * accept them. 305 | * @param quote The quoting character, either 306 | * " (double quote) or 307 | * ' (single quote). 308 | * @return A String. 309 | * @throws JSONException Unterminated string. 310 | */ 311 | public String nextString(char quote) throws JSONException { 312 | char c; 313 | StringBuilder sb = new StringBuilder(); 314 | for (;;) { 315 | c = this.next(); 316 | switch (c) { 317 | case 0: 318 | case '\n': 319 | case '\r': 320 | throw this.syntaxError("Unterminated string"); 321 | case '\\': 322 | c = this.next(); 323 | switch (c) { 324 | case 'b': 325 | sb.append('\b'); 326 | break; 327 | case 't': 328 | sb.append('\t'); 329 | break; 330 | case 'n': 331 | sb.append('\n'); 332 | break; 333 | case 'f': 334 | sb.append('\f'); 335 | break; 336 | case 'r': 337 | sb.append('\r'); 338 | break; 339 | case 'u': 340 | try { 341 | sb.append((char)Integer.parseInt(this.next(4), 16)); 342 | } catch (NumberFormatException e) { 343 | throw this.syntaxError("Illegal escape.", e); 344 | } 345 | break; 346 | case '"': 347 | case '\'': 348 | case '\\': 349 | case '/': 350 | sb.append(c); 351 | break; 352 | default: 353 | throw this.syntaxError("Illegal escape."); 354 | } 355 | break; 356 | default: 357 | if (c == quote) { 358 | return sb.toString(); 359 | } 360 | sb.append(c); 361 | } 362 | } 363 | } 364 | 365 | 366 | /** 367 | * Get the text up but not including the specified character or the 368 | * end of line, whichever comes first. 369 | * @param delimiter A delimiter character. 370 | * @return A string. 371 | * @throws JSONException Thrown if there is an error while searching 372 | * for the delimiter 373 | */ 374 | public String nextTo(char delimiter) throws JSONException { 375 | StringBuilder sb = new StringBuilder(); 376 | for (;;) { 377 | char c = this.next(); 378 | if (c == delimiter || c == 0 || c == '\n' || c == '\r') { 379 | if (c != 0) { 380 | this.back(); 381 | } 382 | return sb.toString().trim(); 383 | } 384 | sb.append(c); 385 | } 386 | } 387 | 388 | 389 | /** 390 | * Get the text up but not including one of the specified delimiter 391 | * characters or the end of line, whichever comes first. 392 | * @param delimiters A set of delimiter characters. 393 | * @return A string, trimmed. 394 | * @throws JSONException Thrown if there is an error while searching 395 | * for the delimiter 396 | */ 397 | public String nextTo(String delimiters) throws JSONException { 398 | char c; 399 | StringBuilder sb = new StringBuilder(); 400 | for (;;) { 401 | c = this.next(); 402 | if (delimiters.indexOf(c) >= 0 || c == 0 || 403 | c == '\n' || c == '\r') { 404 | if (c != 0) { 405 | this.back(); 406 | } 407 | return sb.toString().trim(); 408 | } 409 | sb.append(c); 410 | } 411 | } 412 | 413 | 414 | /** 415 | * Get the next value. The value can be a Boolean, Double, Integer, 416 | * JSONArray, JSONObject, Long, or String, or the JSONObject.NULL object. 417 | * @throws JSONException If syntax error. 418 | * 419 | * @return An object. 420 | */ 421 | public Object nextValue() throws JSONException { 422 | char c = this.nextClean(); 423 | String string; 424 | 425 | switch (c) { 426 | case '"': 427 | case '\'': 428 | return this.nextString(c); 429 | case '{': 430 | this.back(); 431 | return new JSONObject(this); 432 | case '[': 433 | this.back(); 434 | return new JSONArray(this); 435 | } 436 | 437 | /* 438 | * Handle unquoted text. This could be the values true, false, or 439 | * null, or it can be a number. An implementation (such as this one) 440 | * is allowed to also accept non-standard forms. 441 | * 442 | * Accumulate characters until we reach the end of the text or a 443 | * formatting character. 444 | */ 445 | 446 | StringBuilder sb = new StringBuilder(); 447 | while (c >= ' ' && ",:]}/\\\"[{;=#".indexOf(c) < 0) { 448 | sb.append(c); 449 | c = this.next(); 450 | } 451 | this.back(); 452 | 453 | string = sb.toString().trim(); 454 | if ("".equals(string)) { 455 | throw this.syntaxError("Missing value"); 456 | } 457 | return JSONObject.stringToValue(string); 458 | } 459 | 460 | 461 | /** 462 | * Skip characters until the next character is the requested character. 463 | * If the requested character is not found, no characters are skipped. 464 | * @param to A character to skip to. 465 | * @return The requested character, or zero if the requested character 466 | * is not found. 467 | * @throws JSONException Thrown if there is an error while searching 468 | * for the to character 469 | */ 470 | public char skipTo(char to) throws JSONException { 471 | char c; 472 | try { 473 | long startIndex = this.index; 474 | long startCharacter = this.character; 475 | long startLine = this.line; 476 | this.reader.mark(1000000); 477 | do { 478 | c = this.next(); 479 | if (c == 0) { 480 | // in some readers, reset() may throw an exception if 481 | // the remaining portion of the input is greater than 482 | // the mark size (1,000,000 above). 483 | this.reader.reset(); 484 | this.index = startIndex; 485 | this.character = startCharacter; 486 | this.line = startLine; 487 | return 0; 488 | } 489 | } while (c != to); 490 | this.reader.mark(1); 491 | } catch (IOException exception) { 492 | throw new JSONException(exception); 493 | } 494 | this.back(); 495 | return c; 496 | } 497 | 498 | /** 499 | * Make a JSONException to signal a syntax error. 500 | * 501 | * @param message The error message. 502 | * @return A JSONException object, suitable for throwing 503 | */ 504 | public JSONException syntaxError(String message) { 505 | return new JSONException(message + this.toString()); 506 | } 507 | 508 | /** 509 | * Make a JSONException to signal a syntax error. 510 | * 511 | * @param message The error message. 512 | * @param causedBy The throwable that caused the error. 513 | * @return A JSONException object, suitable for throwing 514 | */ 515 | public JSONException syntaxError(String message, Throwable causedBy) { 516 | return new JSONException(message + this.toString(), causedBy); 517 | } 518 | 519 | /** 520 | * Make a printable string of this JSONTokener. 521 | * 522 | * @return " at {index} [character {character} line {line}]" 523 | */ 524 | @Override 525 | public String toString() { 526 | return " at " + this.index + " [character " + this.character + " line " + 527 | this.line + "]"; 528 | } 529 | } 530 | -------------------------------------------------------------------------------- /java-version/src/org/json/JSONWriter.java: -------------------------------------------------------------------------------- 1 | package org.json; 2 | 3 | import java.io.IOException; 4 | import java.math.BigDecimal; 5 | import java.util.Collection; 6 | import java.util.Map; 7 | 8 | /* 9 | Copyright (c) 2006 JSON.org 10 | 11 | Permission is hereby granted, free of charge, to any person obtaining a copy 12 | of this software and associated documentation files (the "Software"), to deal 13 | in the Software without restriction, including without limitation the rights 14 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 15 | copies of the Software, and to permit persons to whom the Software is 16 | furnished to do so, subject to the following conditions: 17 | 18 | The above copyright notice and this permission notice shall be included in all 19 | copies or substantial portions of the Software. 20 | 21 | The Software shall be used for Good, not Evil. 22 | 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 29 | SOFTWARE. 30 | */ 31 | 32 | /** 33 | * JSONWriter provides a quick and convenient way of producing JSON text. 34 | * The texts produced strictly conform to JSON syntax rules. No whitespace is 35 | * added, so the results are ready for transmission or storage. Each instance of 36 | * JSONWriter can produce one JSON text. 37 | *

38 | * A JSONWriter instance provides a value method for appending 39 | * values to the 40 | * text, and a key 41 | * method for adding keys before values in objects. There are array 42 | * and endArray methods that make and bound array values, and 43 | * object and endObject methods which make and bound 44 | * object values. All of these methods return the JSONWriter instance, 45 | * permitting a cascade style. For example,

 46 |  * new JSONWriter(myWriter)
 47 |  *     .object()
 48 |  *         .key("JSON")
 49 |  *         .value("Hello, World!")
 50 |  *     .endObject();
which writes
 51 |  * {"JSON":"Hello, World!"}
52 | *

53 | * The first method called must be array or object. 54 | * There are no methods for adding commas or colons. JSONWriter adds them for 55 | * you. Objects and arrays can be nested up to 200 levels deep. 56 | *

57 | * This can sometimes be easier than using a JSONObject to build a string. 58 | * @author JSON.org 59 | * @version 2016-08-08 60 | */ 61 | public class JSONWriter { 62 | private static final int maxdepth = 200; 63 | 64 | /** 65 | * The comma flag determines if a comma should be output before the next 66 | * value. 67 | */ 68 | private boolean comma; 69 | 70 | /** 71 | * The current mode. Values: 72 | * 'a' (array), 73 | * 'd' (done), 74 | * 'i' (initial), 75 | * 'k' (key), 76 | * 'o' (object). 77 | */ 78 | protected char mode; 79 | 80 | /** 81 | * The object/array stack. 82 | */ 83 | private final JSONObject stack[]; 84 | 85 | /** 86 | * The stack top index. A value of 0 indicates that the stack is empty. 87 | */ 88 | private int top; 89 | 90 | /** 91 | * The writer that will receive the output. 92 | */ 93 | protected Appendable writer; 94 | 95 | /** 96 | * Make a fresh JSONWriter. It can be used to build one JSON text. 97 | */ 98 | public JSONWriter(Appendable w) { 99 | this.comma = false; 100 | this.mode = 'i'; 101 | this.stack = new JSONObject[maxdepth]; 102 | this.top = 0; 103 | this.writer = w; 104 | } 105 | 106 | /** 107 | * Append a value. 108 | * @param string A string value. 109 | * @return this 110 | * @throws JSONException If the value is out of sequence. 111 | */ 112 | private JSONWriter append(String string) throws JSONException { 113 | if (string == null) { 114 | throw new JSONException("Null pointer"); 115 | } 116 | if (this.mode == 'o' || this.mode == 'a') { 117 | try { 118 | if (this.comma && this.mode == 'a') { 119 | this.writer.append(','); 120 | } 121 | this.writer.append(string); 122 | } catch (IOException e) { 123 | // Android as of API 25 does not support this exception constructor 124 | // however we won't worry about it. If an exception is happening here 125 | // it will just throw a "Method not found" exception instead. 126 | throw new JSONException(e); 127 | } 128 | if (this.mode == 'o') { 129 | this.mode = 'k'; 130 | } 131 | this.comma = true; 132 | return this; 133 | } 134 | throw new JSONException("Value out of sequence."); 135 | } 136 | 137 | /** 138 | * Begin appending a new array. All values until the balancing 139 | * endArray will be appended to this array. The 140 | * endArray method must be called to mark the array's end. 141 | * @return this 142 | * @throws JSONException If the nesting is too deep, or if the object is 143 | * started in the wrong place (for example as a key or after the end of the 144 | * outermost array or object). 145 | */ 146 | public JSONWriter array() throws JSONException { 147 | if (this.mode == 'i' || this.mode == 'o' || this.mode == 'a') { 148 | this.push(null); 149 | this.append("["); 150 | this.comma = false; 151 | return this; 152 | } 153 | throw new JSONException("Misplaced array."); 154 | } 155 | 156 | /** 157 | * End something. 158 | * @param m Mode 159 | * @param c Closing character 160 | * @return this 161 | * @throws JSONException If unbalanced. 162 | */ 163 | private JSONWriter end(char m, char c) throws JSONException { 164 | if (this.mode != m) { 165 | throw new JSONException(m == 'a' 166 | ? "Misplaced endArray." 167 | : "Misplaced endObject."); 168 | } 169 | this.pop(m); 170 | try { 171 | this.writer.append(c); 172 | } catch (IOException e) { 173 | // Android as of API 25 does not support this exception constructor 174 | // however we won't worry about it. If an exception is happening here 175 | // it will just throw a "Method not found" exception instead. 176 | throw new JSONException(e); 177 | } 178 | this.comma = true; 179 | return this; 180 | } 181 | 182 | /** 183 | * End an array. This method most be called to balance calls to 184 | * array. 185 | * @return this 186 | * @throws JSONException If incorrectly nested. 187 | */ 188 | public JSONWriter endArray() throws JSONException { 189 | return this.end('a', ']'); 190 | } 191 | 192 | /** 193 | * End an object. This method most be called to balance calls to 194 | * object. 195 | * @return this 196 | * @throws JSONException If incorrectly nested. 197 | */ 198 | public JSONWriter endObject() throws JSONException { 199 | return this.end('k', '}'); 200 | } 201 | 202 | /** 203 | * Append a key. The key will be associated with the next value. In an 204 | * object, every value must be preceded by a key. 205 | * @param string A key string. 206 | * @return this 207 | * @throws JSONException If the key is out of place. For example, keys 208 | * do not belong in arrays or if the key is null. 209 | */ 210 | public JSONWriter key(String string) throws JSONException { 211 | if (string == null) { 212 | throw new JSONException("Null key."); 213 | } 214 | if (this.mode == 'k') { 215 | try { 216 | JSONObject topObject = this.stack[this.top - 1]; 217 | // don't use the built in putOnce method to maintain Android support 218 | if(topObject.has(string)) { 219 | throw new JSONException("Duplicate key \"" + string + "\""); 220 | } 221 | topObject.put(string, true); 222 | if (this.comma) { 223 | this.writer.append(','); 224 | } 225 | this.writer.append(JSONObject.quote(string)); 226 | this.writer.append(':'); 227 | this.comma = false; 228 | this.mode = 'o'; 229 | return this; 230 | } catch (IOException e) { 231 | // Android as of API 25 does not support this exception constructor 232 | // however we won't worry about it. If an exception is happening here 233 | // it will just throw a "Method not found" exception instead. 234 | throw new JSONException(e); 235 | } 236 | } 237 | throw new JSONException("Misplaced key."); 238 | } 239 | 240 | 241 | /** 242 | * Begin appending a new object. All keys and values until the balancing 243 | * endObject will be appended to this object. The 244 | * endObject method must be called to mark the object's end. 245 | * @return this 246 | * @throws JSONException If the nesting is too deep, or if the object is 247 | * started in the wrong place (for example as a key or after the end of the 248 | * outermost array or object). 249 | */ 250 | public JSONWriter object() throws JSONException { 251 | if (this.mode == 'i') { 252 | this.mode = 'o'; 253 | } 254 | if (this.mode == 'o' || this.mode == 'a') { 255 | this.append("{"); 256 | this.push(new JSONObject()); 257 | this.comma = false; 258 | return this; 259 | } 260 | throw new JSONException("Misplaced object."); 261 | 262 | } 263 | 264 | 265 | /** 266 | * Pop an array or object scope. 267 | * @param c The scope to close. 268 | * @throws JSONException If nesting is wrong. 269 | */ 270 | private void pop(char c) throws JSONException { 271 | if (this.top <= 0) { 272 | throw new JSONException("Nesting error."); 273 | } 274 | char m = this.stack[this.top - 1] == null ? 'a' : 'k'; 275 | if (m != c) { 276 | throw new JSONException("Nesting error."); 277 | } 278 | this.top -= 1; 279 | this.mode = this.top == 0 280 | ? 'd' 281 | : this.stack[this.top - 1] == null 282 | ? 'a' 283 | : 'k'; 284 | } 285 | 286 | /** 287 | * Push an array or object scope. 288 | * @param jo The scope to open. 289 | * @throws JSONException If nesting is too deep. 290 | */ 291 | private void push(JSONObject jo) throws JSONException { 292 | if (this.top >= maxdepth) { 293 | throw new JSONException("Nesting too deep."); 294 | } 295 | this.stack[this.top] = jo; 296 | this.mode = jo == null ? 'a' : 'k'; 297 | this.top += 1; 298 | } 299 | 300 | /** 301 | * Make a JSON text of an Object value. If the object has an 302 | * value.toJSONString() method, then that method will be used to produce the 303 | * JSON text. The method is required to produce a strictly conforming text. 304 | * If the object does not contain a toJSONString method (which is the most 305 | * common case), then a text will be produced by other means. If the value 306 | * is an array or Collection, then a JSONArray will be made from it and its 307 | * toJSONString method will be called. If the value is a MAP, then a 308 | * JSONObject will be made from it and its toJSONString method will be 309 | * called. Otherwise, the value's toString method will be called, and the 310 | * result will be quoted. 311 | * 312 | *

313 | * Warning: This method assumes that the data structure is acyclical. 314 | * 315 | * @param value 316 | * The value to be serialized. 317 | * @return a printable, displayable, transmittable representation of the 318 | * object, beginning with { (left 319 | * brace) and ending with } (right 320 | * brace). 321 | * @throws JSONException 322 | * If the value is or contains an invalid number. 323 | */ 324 | public static String valueToString(Object value) throws JSONException { 325 | if (value == null || value.equals(null)) { 326 | return "null"; 327 | } 328 | if (value instanceof JSONString) { 329 | Object object; 330 | try { 331 | object = ((JSONString) value).toJSONString(); 332 | } catch (Exception e) { 333 | throw new JSONException(e); 334 | } 335 | if (object instanceof String) { 336 | return (String) object; 337 | } 338 | throw new JSONException("Bad value from toJSONString: " + object); 339 | } 340 | if (value instanceof Number) { 341 | // not all Numbers may match actual JSON Numbers. i.e. Fractions or Complex 342 | final String numberAsString = JSONObject.numberToString((Number) value); 343 | try { 344 | // Use the BigDecimal constructor for it's parser to validate the format. 345 | @SuppressWarnings("unused") 346 | BigDecimal unused = new BigDecimal(numberAsString); 347 | // Close enough to a JSON number that we will return it unquoted 348 | return numberAsString; 349 | } catch (NumberFormatException ex){ 350 | // The Number value is not a valid JSON number. 351 | // Instead we will quote it as a string 352 | return JSONObject.quote(numberAsString); 353 | } 354 | } 355 | if (value instanceof Boolean || value instanceof JSONObject 356 | || value instanceof JSONArray) { 357 | return value.toString(); 358 | } 359 | if (value instanceof Map) { 360 | Map map = (Map) value; 361 | return new JSONObject(map).toString(); 362 | } 363 | if (value instanceof Collection) { 364 | Collection coll = (Collection) value; 365 | return new JSONArray(coll).toString(); 366 | } 367 | if (value.getClass().isArray()) { 368 | return new JSONArray(value).toString(); 369 | } 370 | if(value instanceof Enum){ 371 | return JSONObject.quote(((Enum)value).name()); 372 | } 373 | return JSONObject.quote(value.toString()); 374 | } 375 | 376 | /** 377 | * Append either the value true or the value 378 | * false. 379 | * @param b A boolean. 380 | * @return this 381 | * @throws JSONException 382 | */ 383 | public JSONWriter value(boolean b) throws JSONException { 384 | return this.append(b ? "true" : "false"); 385 | } 386 | 387 | /** 388 | * Append a double value. 389 | * @param d A double. 390 | * @return this 391 | * @throws JSONException If the number is not finite. 392 | */ 393 | public JSONWriter value(double d) throws JSONException { 394 | return this.value(Double.valueOf(d)); 395 | } 396 | 397 | /** 398 | * Append a long value. 399 | * @param l A long. 400 | * @return this 401 | * @throws JSONException 402 | */ 403 | public JSONWriter value(long l) throws JSONException { 404 | return this.append(Long.toString(l)); 405 | } 406 | 407 | 408 | /** 409 | * Append an object value. 410 | * @param object The object to append. It can be null, or a Boolean, Number, 411 | * String, JSONObject, or JSONArray, or an object that implements JSONString. 412 | * @return this 413 | * @throws JSONException If the value is out of sequence. 414 | */ 415 | public JSONWriter value(Object object) throws JSONException { 416 | return this.append(valueToString(object)); 417 | } 418 | } 419 | -------------------------------------------------------------------------------- /java-version/src/org/json/Property.java: -------------------------------------------------------------------------------- 1 | package org.json; 2 | 3 | /* 4 | Copyright (c) 2002 JSON.org 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | The Software shall be used for Good, not Evil. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | SOFTWARE. 25 | */ 26 | 27 | import java.util.Enumeration; 28 | import java.util.Properties; 29 | 30 | /** 31 | * Converts a Property file data into JSONObject and back. 32 | * @author JSON.org 33 | * @version 2015-05-05 34 | */ 35 | public class Property { 36 | /** 37 | * Converts a property file object into a JSONObject. The property file object is a table of name value pairs. 38 | * @param properties java.util.Properties 39 | * @return JSONObject 40 | * @throws JSONException 41 | */ 42 | public static JSONObject toJSONObject(java.util.Properties properties) throws JSONException { 43 | // can't use the new constructor for Android support 44 | // JSONObject jo = new JSONObject(properties == null ? 0 : properties.size()); 45 | JSONObject jo = new JSONObject(); 46 | if (properties != null && !properties.isEmpty()) { 47 | Enumeration enumProperties = properties.propertyNames(); 48 | while(enumProperties.hasMoreElements()) { 49 | String name = (String)enumProperties.nextElement(); 50 | jo.put(name, properties.getProperty(name)); 51 | } 52 | } 53 | return jo; 54 | } 55 | 56 | /** 57 | * Converts the JSONObject into a property file object. 58 | * @param jo JSONObject 59 | * @return java.util.Properties 60 | * @throws JSONException 61 | */ 62 | public static Properties toProperties(JSONObject jo) throws JSONException { 63 | Properties properties = new Properties(); 64 | if (jo != null) { 65 | // Don't use the new entrySet API to maintain Android support 66 | for (final String key : jo.keySet()) { 67 | Object value = jo.opt(key); 68 | if (!JSONObject.NULL.equals(value)) { 69 | properties.put(key, value.toString()); 70 | } 71 | } 72 | } 73 | return properties; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /java-version/src/org/json/XML.java: -------------------------------------------------------------------------------- 1 | package org.json; 2 | 3 | /* 4 | Copyright (c) 2015 JSON.org 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | The Software shall be used for Good, not Evil. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | SOFTWARE. 25 | */ 26 | 27 | import java.io.Reader; 28 | import java.io.StringReader; 29 | import java.util.Iterator; 30 | 31 | /** 32 | * This provides static methods to convert an XML text into a JSONObject, and to 33 | * covert a JSONObject into an XML text. 34 | * 35 | * @author JSON.org 36 | * @version 2016-08-10 37 | */ 38 | public class XML { 39 | /** The Character '&'. */ 40 | public static final Character AMP = '&'; 41 | 42 | /** The Character '''. */ 43 | public static final Character APOS = '\''; 44 | 45 | /** The Character '!'. */ 46 | public static final Character BANG = '!'; 47 | 48 | /** The Character '='. */ 49 | public static final Character EQ = '='; 50 | 51 | /** The Character '>'. */ 52 | public static final Character GT = '>'; 53 | 54 | /** The Character '<'. */ 55 | public static final Character LT = '<'; 56 | 57 | /** The Character '?'. */ 58 | public static final Character QUEST = '?'; 59 | 60 | /** The Character '"'. */ 61 | public static final Character QUOT = '"'; 62 | 63 | /** The Character '/'. */ 64 | public static final Character SLASH = '/'; 65 | 66 | /** 67 | * Creates an iterator for navigating Code Points in a string instead of 68 | * characters. Once Java7 support is dropped, this can be replaced with 69 | * 70 | * string.codePoints() 71 | * 72 | * which is available in Java8 and above. 73 | * 74 | * @see http://stackoverflow.com/a/21791059/6030888 76 | */ 77 | private static Iterable codePointIterator(final String string) { 78 | return new Iterable() { 79 | @Override 80 | public Iterator iterator() { 81 | return new Iterator() { 82 | private int nextIndex = 0; 83 | private int length = string.length(); 84 | 85 | @Override 86 | public boolean hasNext() { 87 | return this.nextIndex < this.length; 88 | } 89 | 90 | @Override 91 | public Integer next() { 92 | int result = string.codePointAt(this.nextIndex); 93 | this.nextIndex += Character.charCount(result); 94 | return result; 95 | } 96 | 97 | @Override 98 | public void remove() { 99 | throw new UnsupportedOperationException(); 100 | } 101 | }; 102 | } 103 | }; 104 | } 105 | 106 | /** 107 | * Replace special characters with XML escapes: 108 | * 109 | *

110 |      * & (ampersand) is replaced by &amp;
111 |      * < (less than) is replaced by &lt;
112 |      * > (greater than) is replaced by &gt;
113 |      * " (double quote) is replaced by &quot;
114 |      * ' (single quote / apostrophe) is replaced by &apos;
115 |      * 
116 | * 117 | * @param string 118 | * The string to be escaped. 119 | * @return The escaped string. 120 | */ 121 | public static String escape(String string) { 122 | StringBuilder sb = new StringBuilder(string.length()); 123 | for (final int cp : codePointIterator(string)) { 124 | switch (cp) { 125 | case '&': 126 | sb.append("&"); 127 | break; 128 | case '<': 129 | sb.append("<"); 130 | break; 131 | case '>': 132 | sb.append(">"); 133 | break; 134 | case '"': 135 | sb.append("""); 136 | break; 137 | case '\'': 138 | sb.append("'"); 139 | break; 140 | default: 141 | if (mustEscape(cp)) { 142 | sb.append("&#x"); 143 | sb.append(Integer.toHexString(cp)); 144 | sb.append(';'); 145 | } else { 146 | sb.appendCodePoint(cp); 147 | } 148 | } 149 | } 150 | return sb.toString(); 151 | } 152 | 153 | /** 154 | * @param cp code point to test 155 | * @return true if the code point is not valid for an XML 156 | */ 157 | private static boolean mustEscape(int cp) { 158 | /* Valid range from https://www.w3.org/TR/REC-xml/#charsets 159 | * 160 | * #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] 161 | * 162 | * any Unicode character, excluding the surrogate blocks, FFFE, and FFFF. 163 | */ 164 | // isISOControl is true when (cp >= 0 && cp <= 0x1F) || (cp >= 0x7F && cp <= 0x9F) 165 | // all ISO control characters are out of range except tabs and new lines 166 | return (Character.isISOControl(cp) 167 | && cp != 0x9 168 | && cp != 0xA 169 | && cp != 0xD 170 | ) || !( 171 | // valid the range of acceptable characters that aren't control 172 | (cp >= 0x20 && cp <= 0xD7FF) 173 | || (cp >= 0xE000 && cp <= 0xFFFD) 174 | || (cp >= 0x10000 && cp <= 0x10FFFF) 175 | ) 176 | ; 177 | } 178 | 179 | /** 180 | * Removes XML escapes from the string. 181 | * 182 | * @param string 183 | * string to remove escapes from 184 | * @return string with converted entities 185 | */ 186 | public static String unescape(String string) { 187 | StringBuilder sb = new StringBuilder(string.length()); 188 | for (int i = 0, length = string.length(); i < length; i++) { 189 | char c = string.charAt(i); 190 | if (c == '&') { 191 | final int semic = string.indexOf(';', i); 192 | if (semic > i) { 193 | final String entity = string.substring(i + 1, semic); 194 | sb.append(XMLTokener.unescapeEntity(entity)); 195 | // skip past the entity we just parsed. 196 | i += entity.length() + 1; 197 | } else { 198 | // this shouldn't happen in most cases since the parser 199 | // errors on unclosed entries. 200 | sb.append(c); 201 | } 202 | } else { 203 | // not part of an entity 204 | sb.append(c); 205 | } 206 | } 207 | return sb.toString(); 208 | } 209 | 210 | /** 211 | * Throw an exception if the string contains whitespace. Whitespace is not 212 | * allowed in tagNames and attributes. 213 | * 214 | * @param string 215 | * A string. 216 | * @throws JSONException Thrown if the string contains whitespace or is empty. 217 | */ 218 | public static void noSpace(String string) throws JSONException { 219 | int i, length = string.length(); 220 | if (length == 0) { 221 | throw new JSONException("Empty string."); 222 | } 223 | for (i = 0; i < length; i += 1) { 224 | if (Character.isWhitespace(string.charAt(i))) { 225 | throw new JSONException("'" + string 226 | + "' contains a space character."); 227 | } 228 | } 229 | } 230 | 231 | /** 232 | * Scan the content following the named tag, attaching it to the context. 233 | * 234 | * @param x 235 | * The XMLTokener containing the source string. 236 | * @param context 237 | * The JSONObject that will include the new material. 238 | * @param name 239 | * The tag name. 240 | * @return true if the close tag is processed. 241 | * @throws JSONException 242 | */ 243 | private static boolean parse(XMLTokener x, JSONObject context, String name, boolean keepStrings) 244 | throws JSONException { 245 | char c; 246 | int i; 247 | JSONObject jsonobject = null; 248 | String string; 249 | String tagName; 250 | Object token; 251 | 252 | // Test for and skip past these forms: 253 | // 254 | // 255 | // 256 | // 257 | // Report errors for these forms: 258 | // <> 259 | // <= 260 | // << 261 | 262 | token = x.nextToken(); 263 | 264 | // "); 271 | return false; 272 | } 273 | x.back(); 274 | } else if (c == '[') { 275 | token = x.nextToken(); 276 | if ("CDATA".equals(token)) { 277 | if (x.next() == '[') { 278 | string = x.nextCDATA(); 279 | if (string.length() > 0) { 280 | context.accumulate("content", string); 281 | } 282 | return false; 283 | } 284 | } 285 | throw x.syntaxError("Expected 'CDATA['"); 286 | } 287 | i = 1; 288 | do { 289 | token = x.nextMeta(); 290 | if (token == null) { 291 | throw x.syntaxError("Missing '>' after ' 0); 298 | return false; 299 | } else if (token == QUEST) { 300 | 301 | // "); 303 | return false; 304 | } else if (token == SLASH) { 305 | 306 | // Close tag 352 | if (x.nextToken() != GT) { 353 | throw x.syntaxError("Misshaped tag"); 354 | } 355 | if (jsonobject.length() > 0) { 356 | context.accumulate(tagName, jsonobject); 357 | } else { 358 | context.accumulate(tagName, ""); 359 | } 360 | return false; 361 | 362 | } else if (token == GT) { 363 | // Content, between <...> and 364 | for (;;) { 365 | token = x.nextContent(); 366 | if (token == null) { 367 | if (tagName != null) { 368 | throw x.syntaxError("Unclosed tag " + tagName); 369 | } 370 | return false; 371 | } else if (token instanceof String) { 372 | string = (String) token; 373 | if (string.length() > 0) { 374 | jsonobject.accumulate("content", 375 | keepStrings ? string : stringToValue(string)); 376 | } 377 | 378 | } else if (token == LT) { 379 | // Nested element 380 | if (parse(x, jsonobject, tagName,keepStrings)) { 381 | if (jsonobject.length() == 0) { 382 | context.accumulate(tagName, ""); 383 | } else if (jsonobject.length() == 1 384 | && jsonobject.opt("content") != null) { 385 | context.accumulate(tagName, 386 | jsonobject.opt("content")); 387 | } else { 388 | context.accumulate(tagName, jsonobject); 389 | } 390 | return false; 391 | } 392 | } 393 | } 394 | } else { 395 | throw x.syntaxError("Misshaped tag"); 396 | } 397 | } 398 | } 399 | } 400 | 401 | /** 402 | * This method is the same as {@link JSONObject#stringToValue(String)}. 403 | * 404 | * @param string String to convert 405 | * @return JSON value of this string or the string 406 | */ 407 | // To maintain compatibility with the Android API, this method is a direct copy of 408 | // the one in JSONObject. Changes made here should be reflected there. 409 | public static Object stringToValue(String string) { 410 | if (string.equals("")) { 411 | return string; 412 | } 413 | if (string.equalsIgnoreCase("true")) { 414 | return Boolean.TRUE; 415 | } 416 | if (string.equalsIgnoreCase("false")) { 417 | return Boolean.FALSE; 418 | } 419 | if (string.equalsIgnoreCase("null")) { 420 | return JSONObject.NULL; 421 | } 422 | 423 | /* 424 | * If it might be a number, try converting it. If a number cannot be 425 | * produced, then the value will just be a string. 426 | */ 427 | 428 | char initial = string.charAt(0); 429 | if ((initial >= '0' && initial <= '9') || initial == '-') { 430 | try { 431 | // if we want full Big Number support this block can be replaced with: 432 | // return stringToNumber(string); 433 | if (string.indexOf('.') > -1 || string.indexOf('e') > -1 434 | || string.indexOf('E') > -1 || "-0".equals(string)) { 435 | Double d = Double.valueOf(string); 436 | if (!d.isInfinite() && !d.isNaN()) { 437 | return d; 438 | } 439 | } else { 440 | Long myLong = Long.valueOf(string); 441 | if (string.equals(myLong.toString())) { 442 | if (myLong.longValue() == myLong.intValue()) { 443 | return Integer.valueOf(myLong.intValue()); 444 | } 445 | return myLong; 446 | } 447 | } 448 | } catch (Exception ignore) { 449 | } 450 | } 451 | return string; 452 | } 453 | 454 | /** 455 | * Convert a well-formed (but not necessarily valid) XML string into a 456 | * JSONObject. Some information may be lost in this transformation because 457 | * JSON is a data format and XML is a document format. XML uses elements, 458 | * attributes, and content text, while JSON uses unordered collections of 459 | * name/value pairs and arrays of values. JSON does not does not like to 460 | * distinguish between elements and attributes. Sequences of similar 461 | * elements are represented as JSONArrays. Content text may be placed in a 462 | * "content" member. Comments, prologs, DTDs, and <[ [ ]]> 463 | * are ignored. 464 | * 465 | * @param string 466 | * The source string. 467 | * @return A JSONObject containing the structured data from the XML string. 468 | * @throws JSONException Thrown if there is an errors while parsing the string 469 | */ 470 | public static JSONObject toJSONObject(String string) throws JSONException { 471 | return toJSONObject(string, false); 472 | } 473 | 474 | /** 475 | * Convert a well-formed (but not necessarily valid) XML into a 476 | * JSONObject. Some information may be lost in this transformation because 477 | * JSON is a data format and XML is a document format. XML uses elements, 478 | * attributes, and content text, while JSON uses unordered collections of 479 | * name/value pairs and arrays of values. JSON does not does not like to 480 | * distinguish between elements and attributes. Sequences of similar 481 | * elements are represented as JSONArrays. Content text may be placed in a 482 | * "content" member. Comments, prologs, DTDs, and <[ [ ]]> 483 | * are ignored. 484 | * 485 | * @param reader The XML source reader. 486 | * @return A JSONObject containing the structured data from the XML string. 487 | * @throws JSONException Thrown if there is an errors while parsing the string 488 | */ 489 | public static JSONObject toJSONObject(Reader reader) throws JSONException { 490 | return toJSONObject(reader, false); 491 | } 492 | 493 | /** 494 | * Convert a well-formed (but not necessarily valid) XML into a 495 | * JSONObject. Some information may be lost in this transformation because 496 | * JSON is a data format and XML is a document format. XML uses elements, 497 | * attributes, and content text, while JSON uses unordered collections of 498 | * name/value pairs and arrays of values. JSON does not does not like to 499 | * distinguish between elements and attributes. Sequences of similar 500 | * elements are represented as JSONArrays. Content text may be placed in a 501 | * "content" member. Comments, prologs, DTDs, and <[ [ ]]> 502 | * are ignored. 503 | * 504 | * All values are converted as strings, for 1, 01, 29.0 will not be coerced to 505 | * numbers but will instead be the exact value as seen in the XML document. 506 | * 507 | * @param reader The XML source reader. 508 | * @param keepStrings If true, then values will not be coerced into boolean 509 | * or numeric values and will instead be left as strings 510 | * @return A JSONObject containing the structured data from the XML string. 511 | * @throws JSONException Thrown if there is an errors while parsing the string 512 | */ 513 | public static JSONObject toJSONObject(Reader reader, boolean keepStrings) throws JSONException { 514 | JSONObject jo = new JSONObject(); 515 | XMLTokener x = new XMLTokener(reader); 516 | while (x.more()) { 517 | x.skipPast("<"); 518 | if(x.more()) { 519 | parse(x, jo, null, keepStrings); 520 | } 521 | } 522 | return jo; 523 | } 524 | 525 | /** 526 | * Convert a well-formed (but not necessarily valid) XML string into a 527 | * JSONObject. Some information may be lost in this transformation because 528 | * JSON is a data format and XML is a document format. XML uses elements, 529 | * attributes, and content text, while JSON uses unordered collections of 530 | * name/value pairs and arrays of values. JSON does not does not like to 531 | * distinguish between elements and attributes. Sequences of similar 532 | * elements are represented as JSONArrays. Content text may be placed in a 533 | * "content" member. Comments, prologs, DTDs, and <[ [ ]]> 534 | * are ignored. 535 | * 536 | * All values are converted as strings, for 1, 01, 29.0 will not be coerced to 537 | * numbers but will instead be the exact value as seen in the XML document. 538 | * 539 | * @param string 540 | * The source string. 541 | * @param keepStrings If true, then values will not be coerced into boolean 542 | * or numeric values and will instead be left as strings 543 | * @return A JSONObject containing the structured data from the XML string. 544 | * @throws JSONException Thrown if there is an errors while parsing the string 545 | */ 546 | public static JSONObject toJSONObject(String string, boolean keepStrings) throws JSONException { 547 | return toJSONObject(new StringReader(string), keepStrings); 548 | } 549 | 550 | /** 551 | * Convert a JSONObject into a well-formed, element-normal XML string. 552 | * 553 | * @param object 554 | * A JSONObject. 555 | * @return A string. 556 | * @throws JSONException Thrown if there is an error parsing the string 557 | */ 558 | public static String toString(Object object) throws JSONException { 559 | return toString(object, null); 560 | } 561 | 562 | /** 563 | * Convert a JSONObject into a well-formed, element-normal XML string. 564 | * 565 | * @param object 566 | * A JSONObject. 567 | * @param tagName 568 | * The optional name of the enclosing tag. 569 | * @return A string. 570 | * @throws JSONException Thrown if there is an error parsing the string 571 | */ 572 | public static String toString(final Object object, final String tagName) 573 | throws JSONException { 574 | StringBuilder sb = new StringBuilder(); 575 | JSONArray ja; 576 | JSONObject jo; 577 | String string; 578 | 579 | if (object instanceof JSONObject) { 580 | 581 | // Emit 582 | if (tagName != null) { 583 | sb.append('<'); 584 | sb.append(tagName); 585 | sb.append('>'); 586 | } 587 | 588 | // Loop thru the keys. 589 | // don't use the new entrySet accessor to maintain Android Support 590 | jo = (JSONObject) object; 591 | for (final String key : jo.keySet()) { 592 | Object value = jo.opt(key); 593 | if (value == null) { 594 | value = ""; 595 | } else if (value.getClass().isArray()) { 596 | value = new JSONArray(value); 597 | } 598 | 599 | // Emit content in body 600 | if ("content".equals(key)) { 601 | if (value instanceof JSONArray) { 602 | ja = (JSONArray) value; 603 | int jaLength = ja.length(); 604 | // don't use the new iterator API to maintain support for Android 605 | for (int i = 0; i < jaLength; i++) { 606 | if (i > 0) { 607 | sb.append('\n'); 608 | } 609 | Object val = ja.opt(i); 610 | sb.append(escape(val.toString())); 611 | } 612 | } else { 613 | sb.append(escape(value.toString())); 614 | } 615 | 616 | // Emit an array of similar keys 617 | 618 | } else if (value instanceof JSONArray) { 619 | ja = (JSONArray) value; 620 | int jaLength = ja.length(); 621 | // don't use the new iterator API to maintain support for Android 622 | for (int i = 0; i < jaLength; i++) { 623 | Object val = ja.opt(i); 624 | if (val instanceof JSONArray) { 625 | sb.append('<'); 626 | sb.append(key); 627 | sb.append('>'); 628 | sb.append(toString(val)); 629 | sb.append("'); 632 | } else { 633 | sb.append(toString(val, key)); 634 | } 635 | } 636 | } else if ("".equals(value)) { 637 | sb.append('<'); 638 | sb.append(key); 639 | sb.append("/>"); 640 | 641 | // Emit a new tag 642 | 643 | } else { 644 | sb.append(toString(value, key)); 645 | } 646 | } 647 | if (tagName != null) { 648 | 649 | // Emit the close tag 650 | sb.append("'); 653 | } 654 | return sb.toString(); 655 | 656 | } 657 | 658 | if (object != null && (object instanceof JSONArray || object.getClass().isArray())) { 659 | if(object.getClass().isArray()) { 660 | ja = new JSONArray(object); 661 | } else { 662 | ja = (JSONArray) object; 663 | } 664 | int jaLength = ja.length(); 665 | // don't use the new iterator API to maintain support for Android 666 | for (int i = 0; i < jaLength; i++) { 667 | Object val = ja.opt(i); 668 | // XML does not have good support for arrays. If an array 669 | // appears in a place where XML is lacking, synthesize an 670 | // element. 671 | sb.append(toString(val, tagName == null ? "array" : tagName)); 672 | } 673 | return sb.toString(); 674 | } 675 | 676 | string = (object == null) ? "null" : escape(object.toString()); 677 | return (tagName == null) ? "\"" + string + "\"" 678 | : (string.length() == 0) ? "<" + tagName + "/>" : "<" + tagName 679 | + ">" + string + ""; 680 | 681 | } 682 | } 683 | -------------------------------------------------------------------------------- /java-version/src/org/json/XMLTokener.java: -------------------------------------------------------------------------------- 1 | package org.json; 2 | 3 | /* 4 | Copyright (c) 2002 JSON.org 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | The Software shall be used for Good, not Evil. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | SOFTWARE. 25 | */ 26 | 27 | import java.io.Reader; 28 | 29 | /** 30 | * The XMLTokener extends the JSONTokener to provide additional methods 31 | * for the parsing of XML texts. 32 | * @author JSON.org 33 | * @version 2015-12-09 34 | */ 35 | public class XMLTokener extends JSONTokener { 36 | 37 | 38 | /** The table of entity values. It initially contains Character values for 39 | * amp, apos, gt, lt, quot. 40 | */ 41 | public static final java.util.HashMap entity; 42 | 43 | static { 44 | entity = new java.util.HashMap(8); 45 | entity.put("amp", XML.AMP); 46 | entity.put("apos", XML.APOS); 47 | entity.put("gt", XML.GT); 48 | entity.put("lt", XML.LT); 49 | entity.put("quot", XML.QUOT); 50 | } 51 | 52 | /** 53 | * Construct an XMLTokener from a Reader. 54 | * @param r A source reader. 55 | */ 56 | public XMLTokener(Reader r) { 57 | super(r); 58 | } 59 | 60 | /** 61 | * Construct an XMLTokener from a string. 62 | * @param s A source string. 63 | */ 64 | public XMLTokener(String s) { 65 | super(s); 66 | } 67 | 68 | /** 69 | * Get the text in the CDATA block. 70 | * @return The string up to the ]]>. 71 | * @throws JSONException If the ]]> is not found. 72 | */ 73 | public String nextCDATA() throws JSONException { 74 | char c; 75 | int i; 76 | StringBuilder sb = new StringBuilder(); 77 | while (more()) { 78 | c = next(); 79 | sb.append(c); 80 | i = sb.length() - 3; 81 | if (i >= 0 && sb.charAt(i) == ']' && 82 | sb.charAt(i + 1) == ']' && sb.charAt(i + 2) == '>') { 83 | sb.setLength(i); 84 | return sb.toString(); 85 | } 86 | } 87 | throw syntaxError("Unclosed CDATA"); 88 | } 89 | 90 | 91 | /** 92 | * Get the next XML outer token, trimming whitespace. There are two kinds 93 | * of tokens: the '<' character which begins a markup tag, and the content 94 | * text between markup tags. 95 | * 96 | * @return A string, or a '<' Character, or null if there is no more 97 | * source text. 98 | * @throws JSONException 99 | */ 100 | public Object nextContent() throws JSONException { 101 | char c; 102 | StringBuilder sb; 103 | do { 104 | c = next(); 105 | } while (Character.isWhitespace(c)); 106 | if (c == 0) { 107 | return null; 108 | } 109 | if (c == '<') { 110 | return XML.LT; 111 | } 112 | sb = new StringBuilder(); 113 | for (;;) { 114 | if (c == 0) { 115 | return sb.toString().trim(); 116 | } 117 | if (c == '<') { 118 | back(); 119 | return sb.toString().trim(); 120 | } 121 | if (c == '&') { 122 | sb.append(nextEntity(c)); 123 | } else { 124 | sb.append(c); 125 | } 126 | c = next(); 127 | } 128 | } 129 | 130 | 131 | /** 132 | * Return the next entity. These entities are translated to Characters: 133 | * & ' > < ". 134 | * @param ampersand An ampersand character. 135 | * @return A Character or an entity String if the entity is not recognized. 136 | * @throws JSONException If missing ';' in XML entity. 137 | */ 138 | public Object nextEntity(char ampersand) throws JSONException { 139 | StringBuilder sb = new StringBuilder(); 140 | for (;;) { 141 | char c = next(); 142 | if (Character.isLetterOrDigit(c) || c == '#') { 143 | sb.append(Character.toLowerCase(c)); 144 | } else if (c == ';') { 145 | break; 146 | } else { 147 | throw syntaxError("Missing ';' in XML entity: &" + sb); 148 | } 149 | } 150 | String string = sb.toString(); 151 | return unescapeEntity(string); 152 | } 153 | 154 | /** 155 | * Unescapes an XML entity encoding; 156 | * @param e entity (only the actual entity value, not the preceding & or ending ; 157 | * @return 158 | */ 159 | static String unescapeEntity(String e) { 160 | // validate 161 | if (e == null || e.isEmpty()) { 162 | return ""; 163 | } 164 | // if our entity is an encoded unicode point, parse it. 165 | if (e.charAt(0) == '#') { 166 | int cp; 167 | if (e.charAt(1) == 'x') { 168 | // hex encoded unicode 169 | cp = Integer.parseInt(e.substring(2), 16); 170 | } else { 171 | // decimal encoded unicode 172 | cp = Integer.parseInt(e.substring(1)); 173 | } 174 | return new String(new int[] {cp},0,1); 175 | } 176 | Character knownEntity = entity.get(e); 177 | if(knownEntity==null) { 178 | // we don't know the entity so keep it encoded 179 | return '&' + e + ';'; 180 | } 181 | return knownEntity.toString(); 182 | } 183 | 184 | 185 | /** 186 | * Returns the next XML meta token. This is used for skipping over 187 | * and structures. 188 | * @return Syntax characters (< > / = ! ?) are returned as 189 | * Character, and strings and names are returned as Boolean. We don't care 190 | * what the values actually are. 191 | * @throws JSONException If a string is not properly closed or if the XML 192 | * is badly structured. 193 | */ 194 | public Object nextMeta() throws JSONException { 195 | char c; 196 | char q; 197 | do { 198 | c = next(); 199 | } while (Character.isWhitespace(c)); 200 | switch (c) { 201 | case 0: 202 | throw syntaxError("Misshaped meta tag"); 203 | case '<': 204 | return XML.LT; 205 | case '>': 206 | return XML.GT; 207 | case '/': 208 | return XML.SLASH; 209 | case '=': 210 | return XML.EQ; 211 | case '!': 212 | return XML.BANG; 213 | case '?': 214 | return XML.QUEST; 215 | case '"': 216 | case '\'': 217 | q = c; 218 | for (;;) { 219 | c = next(); 220 | if (c == 0) { 221 | throw syntaxError("Unterminated string"); 222 | } 223 | if (c == q) { 224 | return Boolean.TRUE; 225 | } 226 | } 227 | default: 228 | for (;;) { 229 | c = next(); 230 | if (Character.isWhitespace(c)) { 231 | return Boolean.TRUE; 232 | } 233 | switch (c) { 234 | case 0: 235 | case '<': 236 | case '>': 237 | case '/': 238 | case '=': 239 | case '!': 240 | case '?': 241 | case '"': 242 | case '\'': 243 | back(); 244 | return Boolean.TRUE; 245 | } 246 | } 247 | } 248 | } 249 | 250 | 251 | /** 252 | * Get the next XML Token. These tokens are found inside of angle 253 | * brackets. It may be one of these characters: / > = ! ? or it 254 | * may be a string wrapped in single quotes or double quotes, or it may be a 255 | * name. 256 | * @return a String or a Character. 257 | * @throws JSONException If the XML is not well formed. 258 | */ 259 | public Object nextToken() throws JSONException { 260 | char c; 261 | char q; 262 | StringBuilder sb; 263 | do { 264 | c = next(); 265 | } while (Character.isWhitespace(c)); 266 | switch (c) { 267 | case 0: 268 | throw syntaxError("Misshaped element"); 269 | case '<': 270 | throw syntaxError("Misplaced '<'"); 271 | case '>': 272 | return XML.GT; 273 | case '/': 274 | return XML.SLASH; 275 | case '=': 276 | return XML.EQ; 277 | case '!': 278 | return XML.BANG; 279 | case '?': 280 | return XML.QUEST; 281 | 282 | // Quoted string 283 | 284 | case '"': 285 | case '\'': 286 | q = c; 287 | sb = new StringBuilder(); 288 | for (;;) { 289 | c = next(); 290 | if (c == 0) { 291 | throw syntaxError("Unterminated string"); 292 | } 293 | if (c == q) { 294 | return sb.toString(); 295 | } 296 | if (c == '&') { 297 | sb.append(nextEntity(c)); 298 | } else { 299 | sb.append(c); 300 | } 301 | } 302 | default: 303 | 304 | // Name 305 | 306 | sb = new StringBuilder(); 307 | for (;;) { 308 | sb.append(c); 309 | c = next(); 310 | if (Character.isWhitespace(c)) { 311 | return sb.toString(); 312 | } 313 | switch (c) { 314 | case 0: 315 | return sb.toString(); 316 | case '>': 317 | case '/': 318 | case '=': 319 | case '!': 320 | case '?': 321 | case '[': 322 | case ']': 323 | back(); 324 | return sb.toString(); 325 | case '<': 326 | case '"': 327 | case '\'': 328 | throw syntaxError("Bad character in a name"); 329 | } 330 | } 331 | } 332 | } 333 | 334 | 335 | /** 336 | * Skip characters until past the requested string. 337 | * If it is not found, we are left at the end of the source with a result of false. 338 | * @param to A string to skip past. 339 | */ 340 | // The Android implementation of JSONTokener has a public method of public void skipPast(String to) 341 | // even though ours does not have that method, to have API compatibility, our method in the subclass 342 | // should match. 343 | public void skipPast(String to) { 344 | boolean b; 345 | char c; 346 | int i; 347 | int j; 348 | int offset = 0; 349 | int length = to.length(); 350 | char[] circle = new char[length]; 351 | 352 | /* 353 | * First fill the circle buffer with as many characters as are in the 354 | * to string. If we reach an early end, bail. 355 | */ 356 | 357 | for (i = 0; i < length; i += 1) { 358 | c = next(); 359 | if (c == 0) { 360 | return; 361 | } 362 | circle[i] = c; 363 | } 364 | 365 | /* We will loop, possibly for all of the remaining characters. */ 366 | 367 | for (;;) { 368 | j = offset; 369 | b = true; 370 | 371 | /* Compare the circle buffer with the to string. */ 372 | 373 | for (i = 0; i < length; i += 1) { 374 | if (circle[j] != to.charAt(i)) { 375 | b = false; 376 | break; 377 | } 378 | j += 1; 379 | if (j >= length) { 380 | j -= length; 381 | } 382 | } 383 | 384 | /* If we exit the loop with b intact, then victory is ours. */ 385 | 386 | if (b) { 387 | return; 388 | } 389 | 390 | /* Get the next character. If there isn't one, then defeat is ours. */ 391 | 392 | c = next(); 393 | if (c == 0) { 394 | return; 395 | } 396 | /* 397 | * Shove the character in the circle buffer and advance the 398 | * circle offset. The offset is mod n. 399 | */ 400 | circle[offset] = c; 401 | offset += 1; 402 | if (offset >= length) { 403 | offset -= length; 404 | } 405 | } 406 | } 407 | } 408 | -------------------------------------------------------------------------------- /java-version/src/test/Test.java: -------------------------------------------------------------------------------- 1 | package test; 2 | 3 | import java.io.IOException; 4 | 5 | import org.json.JSONArray; 6 | import org.json.JSONException; 7 | import org.json.JSONObject; 8 | 9 | import com.bgw.translator.MessageTranslator; 10 | 11 | public class Test { 12 | public static void main(String[] args) throws IOException { 13 | String configStr = "{\"f41\":{\"format\":\"%-8s\", \"variable\":\"card_acceptor_terminal\", \"options\":\"\", \"field_length\":\"8\", \"type\":\"STRING\"},\"f63\":{\"format\":\"%-32s%-30s%-50s%-18s\", \"variable\":\"locket_code, locket_name, locket_address, locket_phone\", \"options\":\"\", \"field_length\":\"130\", \"type\":\"LLLVAR\"},\"f32\":{\"format\":\"%-11s\", \"variable\":\"acq_institution_code\", \"options\":\"\", \"field_length\":\"11\", \"type\":\"LLVAR\"},\"f42\":{\"format\":\"%15s\", \"variable\":\"acceptor_identification_code\", \"options\":\"\", \"field_length\":\"15\", \"type\":\"STRING\"},\"f121\":{\"format\":\"%-32s\", \"variable\":\"payment_reference\", \"options\":\"\", \"field_length\":\"32\", \"type\":\"LLLVAR\"},\"f12\":{\"format\":\"%-6s\", \"variable\":\"local_time\", \"options\":\"\", \"field_length\":\"6\", \"type\":\"STRING\"},\"f120\":{\"format\":\"%-20s\", \"variable\":\"product_code\", \"options\":\"\", \"field_length\":\"20\", \"type\":\"LLLVAR\"},\"f11\":{\"format\":\"%06d\", \"variable\":\"stan\", \"options\":\"\", \"field_length\":\"6\", \"type\":\"NUMERIC\"},\"f33\":{\"format\":\"%-11s\", \"variable\":\"fwd_institution_code\", \"options\":\"\", \"field_length\":\"11\", \"type\":\"LLVAR\"},\"f13\":{\"format\":\"%-4s\", \"variable\":\"local_date\", \"options\":\"\", \"field_length\":\"4\", \"type\":\"STRING\"},\"f49\":{\"format\":\"%03d\", \"variable\":\"transaction_currency_code\", \"options\":\"\", \"field_length\":\"3\", \"type\":\"NUMERIC\"},\"f15\":{\"format\":\"%-4s\", \"variable\":\"settlement_date\", \"options\":\"\", \"field_length\":\"4\", \"type\":\"STRING\"},\"f37\":{\"format\":\"%012d\", \"variable\":\"reference_number\", \"options\":\"\", \"field_length\":\"12\", \"type\":\"NUMERIC\"},\"f48\":{\"format\":\"%11s%12s%01d\", \"variable\":\"meter_id, customer_id, id_selector\", \"options\":\"\", \"field_length\":\"24\", \"type\":\"LLLVAR\"},\"f2\":{\"format\":\"%-19s\", \"variable\":\"pan\", \"options\":\"\", \"field_length\":\"19\", \"type\":\"LLVAR\"},\"f18\":{\"format\":\"%04d\", \"variable\":\"merchant_type\", \"options\":\"\", \"field_length\":\"4\", \"type\":\"NUMERIC\"},\"f3\":{\"format\":\"%06d\", \"variable\":\"processing_code\", \"options\":\"\", \"field_length\":\"6\", \"type\":\"NUMERIC\"},\"f4\":{\"format\":\"%012d\", \"variable\":\"amount\", \"options\":\"\", \"field_length\":\"12\", \"type\":\"NUMERIC\"},\"f7\":{\"format\":\"%-10s\", \"variable\":\"transmission_date_time\", \"options\":\"\", \"field_length\":\"10\", \"type\":\"STRING\"},\"f127\":{\"format\":\"%-20s%-32s\", \"variable\":\"username, password\", \"options\":\"\", \"field_length\":\"52\", \"type\":\"LLLVAR\"}}"; 14 | 15 | MessageTranslator mt = new MessageTranslator(); 16 | String mti_id = "0210"; 17 | String iso = "0200F23A400188C180060000000000000182196048200000002731 300000000000020000092513425200007213425209250926602111597 1112345 000000000072DEVALT0120090010080000014514987654321149999999911030E8597E3B2F1646505FDD6E210000090MUP210ZBE957561167FCD8506326E4AHAMDANIE LESTALUHUANI R1 00000090000000090000000011653600505151106123 0600000000000000000000000000130 ALTO Jalan Anggrek Neli Murni 02199999 02000500050001 03214987654321 052tester1 tester1 "; 18 | String iso_new = ""; 19 | String xml = ""; 20 | JSONObject config = new JSONObject(); 21 | JSONObject json = new JSONObject(); 22 | 23 | 24 | try 25 | { 26 | config = new JSONObject(configStr); 27 | json = mt.parseISO8583(iso, config); 28 | iso_new = new String(mt.buildISO8583(json, config, mti_id)); 29 | xml = mt.buildXML(json, "data"); 30 | 31 | System.out.println("Demonstration of conversion of ISO 8583 - JSON - XML"); 32 | System.out.println("Config : "); 33 | System.out.println(config.toString()); 34 | System.out.println("============================================================="); 35 | 36 | System.out.println("Original ISO 8583 : "); 37 | System.out.println("'"+iso+"'"); 38 | System.out.println("Convert ISO to JSON"); 39 | System.out.println("JSON : "); 40 | System.out.println(json.toString()); 41 | System.out.println("============================================================="); 42 | 43 | System.out.println("Now, convert JSON to new ISO"); 44 | System.out.println("New ISO 8583 : "); 45 | System.out.println("'"+iso_new+"'"); 46 | System.out.println("============================================================="); 47 | 48 | System.out.println("Now, convert JSON to XML"); 49 | System.out.println("XML : "); 50 | System.out.println(xml); 51 | System.out.println("============================================================="); 52 | 53 | } 54 | catch (JSONException e) 55 | { 56 | e.printStackTrace(); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /php-version/index.php: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | Test 9 | 10 | 11 | 12 | parseISO($message1, $config); 16 | 17 | $message2 = $translator->buildISO($json, null, '0210'); 18 | ?> 19 | 20 |
21 | Original ISO :
22 | 
25 | 
26 |

Parsed Into JSON

27 |
28 | JSON : 
29 | 
32 | 
33 |

Converted Into ISO

34 |
35 | New ISO :
36 | 
39 | 
40 | 41 | -------------------------------------------------------------------------------- /php-version/lib/MessageTranslator.php: -------------------------------------------------------------------------------- 1 | iso_config = json_decode($iso_config, true); 14 | } 15 | $keys = array_keys($this->iso_config); 16 | if(in_array(0, $keys)) 17 | { 18 | $tmp = $this->iso_config; 19 | $this->iso_config = array(); 20 | foreach($tmp as $key=>$value) 21 | { 22 | $this->iso_config['f'.$value['field']] = $value; 23 | } 24 | } 25 | } 26 | function parseISO($message, $iso_config = null) 27 | { 28 | if($iso_config !== null) 29 | { 30 | $this->setConfig($iso_config); 31 | } 32 | $this->parse($message); 33 | $data = array(); 34 | foreach($this->iso_config as $field_str=>$config) 35 | { 36 | $field = substr($field_str, 1); 37 | $raw_data = $this->values[$field]; 38 | $variables = $config['variable']; 39 | $formats = $config['format']; 40 | $array_variable = explode(",", preg_replace('/\s+/', '', $variables)); 41 | $array_format = explode("%", $formats); 42 | $offset = 0; 43 | foreach($array_variable as $idx=>$variable) 44 | { 45 | $fmt = preg_replace("/[^0-9]/", "", $array_format[$idx+1]); 46 | $len = abs($fmt * 1); 47 | $variable = trim($variable); 48 | $data[$variable] = substr($raw_data, $offset, $len); 49 | $offset += $len; 50 | } 51 | } 52 | return $data; 53 | } 54 | function buildISO($json, $iso_config = null, $mti) 55 | { 56 | if($iso_config !== null) 57 | { 58 | $this->setConfig($iso_config); 59 | } 60 | $this->setType($mti); 61 | $data = array(); 62 | 63 | foreach($this->iso_config as $field_str=>$config) 64 | { 65 | $field = substr($field_str, 1); 66 | $raw_data = ""; 67 | $variables = $config['variable']; 68 | $formats = $config['format']; 69 | $array_variable = explode(",", preg_replace('/\s+/', '', $variables)); 70 | $array_format = explode("%", $formats); 71 | $offset = 0; 72 | foreach($array_variable as $idx=>$variable) 73 | { 74 | $fmt = $array_format[$idx+1]; 75 | $len = abs($fmt * 1); 76 | $format = "%".$fmt; 77 | $variable = trim($variable); 78 | $data = @$json[$variable]; 79 | if(stripos($fmt, "d") !== false) 80 | { 81 | $data = $data * 1; 82 | } 83 | $raw_data .= sprintf($format, $data); 84 | } 85 | $this->addBit($field, $raw_data); 86 | } 87 | return $this->getISO(); 88 | } 89 | 90 | } 91 | ?> -------------------------------------------------------------------------------- /php-version/lib/RoyISO8583.php: -------------------------------------------------------------------------------- 1 | array('b', 64, 0), 5 | 2 => array('an', 19, 1), 6 | 3 => array('n', 6, 0), 7 | 4 => array('n', 12, 0), 8 | 5 => array('n', 12, 0), 9 | 6 => array('n', 12, 0), 10 | 7 => array('an', 10, 0), 11 | 8 => array('n', 8, 0), 12 | 9 => array('n', 8, 0), 13 | 10 => array('n', 8, 0), 14 | 11 => array('n', 6, 0), 15 | 12 => array('n', 6, 0), 16 | 13 => array('n', 4, 0), 17 | 14 => array('n', 4, 0), 18 | 15 => array('n', 4, 0), 19 | 16 => array('n', 4, 0), 20 | 17 => array('n', 4, 0), 21 | 18 => array('n', 4, 0), 22 | 19 => array('n', 3, 0), 23 | 20 => array('n', 3, 0), 24 | 21 => array('n', 3, 0), 25 | 22 => array('n', 3, 0), 26 | 23 => array('n', 3, 0), 27 | 24 => array('n', 3, 0), 28 | 25 => array('n', 2, 0), 29 | 26 => array('n', 2, 0), 30 | 27 => array('n', 1, 0), 31 | 28 => array('n', 8, 0), 32 | 29 => array('an', 9, 0), 33 | 30 => array('n', 8, 0), 34 | 31 => array('an', 9, 0), 35 | 32 => array('n', 11, 1), 36 | 33 => array('n', 11, 1), 37 | 34 => array('an', 28, 1), 38 | 35 => array('z', 37, 1), 39 | 36 => array('n', 104, 1), 40 | 37 => array('an', 12, 0), 41 | 38 => array('an', 6, 0), 42 | 39 => array('an', 2, 0), 43 | 40 => array('an', 3, 0), 44 | 41 => array('ans', 8, 0), 45 | 42 => array('ans', 15, 0), 46 | 43 => array('ans', 40, 0), 47 | 44 => array('an', 25, 1), 48 | 45 => array('an', 76, 1), 49 | 46 => array('an', 999, 1), 50 | 47 => array('an', 999, 1), 51 | 48 => array('ans', 119, 1), 52 | 49 => array('an', 3, 0), 53 | 50 => array('an', 3, 0), 54 | 51 => array('a', 3, 0), 55 | 52 => array('an', 16, 0), 56 | 53 => array('an', 18, 0), 57 | 54 => array('an', 120, 0), 58 | 55 => array('ans', 999, 1), 59 | 56 => array('ans', 999, 1), 60 | 57 => array('ans', 999, 1), 61 | 58 => array('ans', 999, 1), 62 | 59 => array('ans', 99, 1), 63 | 60 => array('ans', 60, 1), 64 | 61 => array('ans', 99, 1), 65 | 62 => array('ans', 999, 1), 66 | 63 => array('ans', 999, 1), 67 | 64 => array('b', 16, 0), 68 | 65 => array('b', 16, 0), 69 | 66 => array('n', 1, 0), 70 | 67 => array('n', 2, 0), 71 | 68 => array('n', 3, 0), 72 | 69 => array('n', 3, 0), 73 | 70 => array('n', 3, 0), 74 | 71 => array('n', 4, 0), 75 | 72 => array('ans', 999, 1), 76 | 73 => array('n', 6, 0), 77 | 74 => array('n', 10, 0), 78 | 75 => array('n', 10, 0), 79 | 76 => array('n', 10, 0), 80 | 77 => array('n', 10, 0), 81 | 78 => array('n', 10, 0), 82 | 79 => array('n', 10, 0), 83 | 80 => array('n', 10, 0), 84 | 81 => array('n', 10, 0), 85 | 82 => array('n', 12, 0), 86 | 83 => array('n', 12, 0), 87 | 84 => array('n', 12, 0), 88 | 85 => array('n', 12, 0), 89 | 86 => array('n', 15, 0), 90 | 87 => array('an', 16, 0), 91 | 88 => array('n', 16, 0), 92 | 89 => array('n', 16, 0), 93 | 90 => array('an', 42, 0), 94 | 91 => array('an', 1, 0), 95 | 92 => array('n', 2, 0), 96 | 93 => array('n', 5, 0), 97 | 94 => array('an', 7, 0), 98 | 95 => array('an', 42, 0), 99 | 96 => array('an', 8, 0), 100 | 97 => array('an', 17, 0), 101 | 98 => array('ans', 25, 0), 102 | 99 => array('n', 11, 1), 103 | 100 => array('n', 11, 1), 104 | 101 => array('ans', 17, 0), 105 | 102 => array('ans', 28, 1), 106 | 103 => array('ans', 28, 1), 107 | 104 => array('an', 100, 1), 108 | 105 => array('ans', 999, 1), 109 | 106 => array('ans', 999, 1), 110 | 107 => array('ans', 999, 1), 111 | 108 => array('ans', 999, 1), 112 | 109 => array('ans', 999, 1), 113 | 110 => array('ans', 999, 1), 114 | 111 => array('ans', 999, 1), 115 | 112 => array('ans', 999, 1), 116 | 113 => array('n', 11, 1), 117 | 114 => array('ans', 999, 1), 118 | 115 => array('ans', 999, 1), 119 | 116 => array('ans', 999, 1), 120 | 117 => array('ans', 999, 1), 121 | 118 => array('ans', 999, 1), 122 | 119 => array('ans', 999, 1), 123 | 120 => array('ans', 999, 1), 124 | 121 => array('ans', 999, 1), 125 | 122 => array('ans', 999, 1), 126 | 123 => array('ans', 999, 1), 127 | 124 => array('ans', 255, 1), 128 | 125 => array('ans', 50, 1), 129 | 126 => array('ans', 6, 1), 130 | 127 => array('ans', 999, 1), 131 | 128 => array('b', 16, 0) 132 | ); 133 | 134 | public $fields = array(); 135 | public $values = array(); 136 | public function addBit($bit, $value = null) 137 | { 138 | $this->fields[] = $bit*1; 139 | $this->fields = array_unique($this->fields); 140 | if($value !== null) 141 | { 142 | if($this->general_config[$bit][0] == 'n') 143 | { 144 | // numeric 145 | $val = $value*1; 146 | if($this->general_config[$bit][2] == 0) 147 | { 148 | // fix length 149 | $value = sprintf("%0".$this->general_config[$bit][1]."d", $val); 150 | } 151 | } 152 | else 153 | { 154 | // non numeric 155 | if($this->general_config[$bit][2] == 0) 156 | { 157 | // fix length 158 | $value = str_pad($value, $this->general_config[$bit][1], ' ', STR_PAD_RIGHT); 159 | } 160 | } 161 | $this->values[$bit] = $value; 162 | } 163 | else 164 | { 165 | $this->values[$bit] = null; 166 | } 167 | sort($this->fields, SORT_NUMERIC ); 168 | ksort($this->values, SORT_NUMERIC ); 169 | } 170 | public function addValue($bit, $value) 171 | { 172 | $this->addBit($bit, $value); 173 | } 174 | public function addData($bit, $value) 175 | { 176 | $this->addBit($bit, $value); 177 | } 178 | public $maxField = 1; 179 | 180 | public $segment1 = array(0,0); 181 | public $segment2 = array(0,0); 182 | public $segment3 = array(0,0); 183 | 184 | function getBitmap() 185 | { 186 | $tmp = sprintf("%064d", 0); 187 | $tmp2 = sprintf("%064d", 0); 188 | foreach ($this->values as $key=>$val) 189 | { 190 | if($key<65) 191 | { 192 | $tmp[$key-1] = 1; 193 | } 194 | else 195 | { 196 | $tmp[0] = 1; 197 | $tmp2[$key-65] = 1; 198 | } 199 | } 200 | $result = ""; 201 | if($tmp[0]==1) 202 | { 203 | while ($tmp2!='') 204 | { 205 | $result .= base_convert(substr($tmp2, 0, 4), 2, 16); 206 | $tmp2 = substr($tmp2, 4, strlen($tmp2)-4); 207 | } 208 | } 209 | $main = ""; 210 | while ($tmp!='') 211 | { 212 | $main .= base_convert(substr($tmp, 0, 4), 2, 16); 213 | $tmp = substr($tmp, 4, strlen($tmp)-4); 214 | } 215 | $this->_bitmap = strtoupper($main. $result); 216 | 217 | return $this->_bitmap; 218 | } 219 | public $type = "0000"; 220 | public $valid = array('mti'=>false, 'bitmap'=>false, 'data'=>false); 221 | public function parse3($message) 222 | { 223 | // parse type and bitmap 224 | $fields = array(); 225 | 226 | $this->iso = $message; 227 | 228 | $this->valid['bitmap'] = false; 229 | $inp = substr($this->iso, 4, 32); 230 | if (strlen($inp)>=16) 231 | { 232 | $primary = ''; 233 | $secondary = ''; 234 | for ($i=0; $i<16; $i++) 235 | { 236 | $primary .= sprintf("%04d", base_convert($inp[$i], 16, 2)); 237 | } 238 | if ($primary[0]==1 && strlen($inp)>=32) 239 | { 240 | for ($i=16; $i<32; $i++) 241 | { 242 | $secondary .= sprintf("%04d", base_convert($inp[$i], 16, 2)); 243 | } 244 | $this->valid['bitmap'] = true; 245 | } 246 | if ($secondary=='') 247 | { 248 | $this->valid['bitmap'] = true; 249 | } 250 | } 251 | //save to data element with ? character 252 | $tmp = $primary. $secondary; 253 | for ($i=0; $ivalues[$i+1] = '?'; 258 | $this->fields[] = $i+1; 259 | } 260 | } 261 | $this->bitmap = $tmp; 262 | 263 | $bitmapLength = strlen($this->bitmap); 264 | 265 | // parse body 266 | $message = substr($message, $bitmapLength+4); 267 | foreach($this->fields as $field) 268 | { 269 | $element = $this->general_config[$field]; 270 | if($element[2] == 1) 271 | { 272 | // dynamic length 273 | $fl = $element[1]; 274 | $shift = strlen(sprintf("%d", $fl)); 275 | $field_length = substr($message, 0, $shift)*1; 276 | $message = substr($message, $shift); 277 | if(strlen($message) >= $field_length) 278 | { 279 | $data = substr($message, 0, $field_length); 280 | $message = substr($message, $field_length); 281 | } 282 | else 283 | { 284 | $data = $message; 285 | } 286 | } 287 | else 288 | { 289 | // fix length 290 | $field_length = $element[1]; 291 | $data = substr($message, 0, $field_length); 292 | $message = substr($message, $field_length); 293 | } 294 | $this->addValue($field, $data); 295 | } 296 | } 297 | public function parse($message) 298 | { 299 | // parse type and bitmap 300 | $fields = array(); 301 | 302 | $ln = ""; 303 | 304 | $segment10Str = ""; 305 | $segment11Str = ""; 306 | $segment10Int = 0; 307 | $segment11Int = 0; 308 | 309 | $segment20Str = ""; 310 | $segment21Str = ""; 311 | $segment20Int = 0; 312 | $segment21Int = 0; 313 | 314 | $segment30Str = ""; 315 | $segment31Str = ""; 316 | $segment30Int = 0; 317 | $segment31Int = 0; 318 | 319 | $typeStr = substr($message, 0, 4); 320 | $this->type = $typeStr; 321 | $segment10Str = substr($message, 4, 8); 322 | $segment11Str = substr($message, 12, 8); 323 | $segment10Int = hexdec($segment10Str); 324 | $segment11Int = hexdec($segment11Str); 325 | $this->segment1[0] = $segment10Int; 326 | $this->segment1[1] = $segment11Int; 327 | 328 | if(sprintf("%08x", ($this->segment1[0] & 0x80000000)) == "80000000") 329 | { 330 | $segment20Str = substr($message, 20, 8); 331 | $segment21Str = substr($message, 28, 8); 332 | $segment20Int = hexdec($segment20Str); 333 | $segment21Int = hexdec($segment21Str); 334 | $this->segment2[0] = $segment20Int; 335 | $this->segment2[1] = $segment21Int; 336 | } 337 | if(sprintf("%08x", ($this->segment2[0] & 0x80000000)) == "80000000") 338 | { 339 | $segment30Str = substr($message, 36, 8); 340 | $segment31Str = substr($message, 44, 8); 341 | $segment30Int = hexdec($segment30Str); 342 | $segment31Int = hexdec($segment31Str); 343 | $this->segment3[0] = $segment30Int; 344 | $this->segment3[1] = $segment31Int; 345 | } 346 | $iter = 0; 347 | // get field list from bitmap 348 | $i = 0; 349 | $k = 0; 350 | 351 | $k = $this->segment1[0]; 352 | for($i = 1; $i <= 32; $i++) 353 | { 354 | if(sprintf("%08x", ($k & 0x80000000)) == "80000000" && $i > 1) 355 | { 356 | $this->addBit($i); 357 | } 358 | $k = $k - 0x80000000; 359 | $k = $k << 1; 360 | } 361 | $k = $this->segment1[1]; 362 | for($i = 33; $i <= 64; $i++) 363 | { 364 | if(sprintf("%08x", ($k & 0x80000000)) == "80000000") 365 | { 366 | $this->addBit($i); 367 | } 368 | $k = $k - 0x80000000; 369 | $k = $k << 1; 370 | } 371 | $bitmapLength = 16; 372 | if(sprintf("%08x", ($this->segment1[0] & 0x80000000)) == "80000000") 373 | { 374 | $bitmapLength = 32; 375 | $k = $this->segment2[0]; 376 | for($i = 65; $i <= 96; $i++) 377 | { 378 | if(sprintf("%08x", ($k & 0x80000000)) == "80000000") 379 | { 380 | $this->addBit($i); 381 | } 382 | $k = $k - 0x80000000; 383 | $k = $k << 1; 384 | } 385 | $k = $this->segment2[1]; 386 | for($i = 97; $i <= 128; $i++) 387 | { 388 | if(sprintf("%08x", ($k & 0x80000000)) == "80000000") 389 | { 390 | $this->addBit($i); 391 | } 392 | $k = $k - 0x80000000; 393 | $k = $k << 1; 394 | } 395 | if(sprintf("%08x", ($this->segment2[0] & 0x80000000)) == "80000000") 396 | { 397 | $bitmapLength = 48; 398 | $k = $this->segment3[0]; 399 | for($i = 129; $i <= 160; $i++) 400 | { 401 | if(sprintf("%08x", ($k & 0x80000000)) == "80000000") 402 | { 403 | $this->addBit($i); 404 | } 405 | $k = $k - 0x80000000; 406 | $k = $k << 1; 407 | } 408 | $k = $this->segment3[1]; 409 | for($i = 161; $i <= 192; $i++) 410 | { 411 | if(sprintf("%08x", ($k & 0x80000000)) == "80000000") 412 | { 413 | $this->addBit($i); 414 | } 415 | $k = $k - 0x80000000; 416 | $k = $k << 1; 417 | } 418 | } 419 | } 420 | 421 | 422 | // parse body 423 | $message = substr($message, $bitmapLength+4); 424 | foreach($this->fields as $field) 425 | { 426 | $element = $this->general_config[$field]; 427 | if($element[2] == 1) 428 | { 429 | // dynamic length 430 | $fl = $element[1]; 431 | $shift = strlen(sprintf("%d", $fl)); 432 | $field_length = substr($message, 0, $shift)*1; 433 | $message = substr($message, $shift); 434 | if(strlen($message) >= $field_length) 435 | { 436 | $data = substr($message, 0, $field_length); 437 | $message = substr($message, $field_length); 438 | } 439 | else 440 | { 441 | $data = $message; 442 | } 443 | } 444 | else 445 | { 446 | // fix length 447 | $field_length = $element[1]; 448 | $data = substr($message, 0, $field_length); 449 | $message = substr($message, $field_length); 450 | } 451 | $this->addValue($field, $data); 452 | } 453 | } 454 | public function maxField() 455 | { 456 | if(count($this->fields)) 457 | { 458 | return max($this->fields); 459 | } 460 | else 461 | { 462 | return 0; 463 | } 464 | } 465 | public function getField() 466 | { 467 | $header = ""; 468 | $header .= $this->type; 469 | $maxField = $this->maxField(); 470 | $seg1 = sprintf("%08x%08x", $this->segment1[0], $this->segment1[1]); 471 | $header .= $seg1; 472 | if($maxField > 64) 473 | { 474 | $seg2 = sprintf("%08x%08x", $this->segment2[0], $this->segment2[1]); 475 | $header .= $seg2; 476 | } 477 | if($maxField > 128) 478 | { 479 | $seg3 = sprintf("%08x%08x", $this->segment3[0], $this->segment3[1]); 480 | $header .= $seg3; 481 | } 482 | return $header; 483 | } 484 | function getBody() 485 | { 486 | $body = ""; 487 | $this->fields = array_unique($this->fields); 488 | sort($this->fields, SORT_NUMERIC); 489 | foreach($this->fields as $field) 490 | { 491 | if($this->general_config[$field][2] == 1) 492 | { 493 | // dynamic 494 | $value = $this->values[$field]; 495 | $length = strlen($value); 496 | $sl = strlen(sprintf("%d", $this->general_config[$field][1])); 497 | $sf = sprintf("%0".$sl."d", $length); 498 | $body .= $sf; 499 | $body .= $value; 500 | } 501 | else 502 | { 503 | // fix length 504 | $value = $this->values[$field]; 505 | $length = $this->general_config[$field][1]; 506 | if($this->general_config[$field][0] == 'n') 507 | { 508 | $val = $value * 1; 509 | $body .= sprintf("%0".$length."d", $val); 510 | } 511 | else 512 | { 513 | $body .= str_pad($value, $length, ' ', STR_PAD_RIGHT); 514 | } 515 | } 516 | } 517 | return $body; 518 | } 519 | public function getBitmapField() 520 | { 521 | } 522 | public function binary_to_hexadecimal($binary) 523 | { 524 | $len=strlen($binary); 525 | $rows=($len/4)-1; 526 | if (($len%4)>0) { 527 | $pad=$len+(4-($len%4)); 528 | $binary=str_pad($binary,$pad,"0",STR_PAD_LEFT); 529 | $len=strlen($binary); 530 | $rows=($len/4)-1; 531 | } 532 | $x=0; 533 | for ($x=0;$x<=$rows;$x++) { 534 | $s=($x*4); 535 | $bins=$binary[$s].$binary[$s+1].$binary[$s+2].$binary[$s+3]; 536 | $num=base_convert($bins,2,10); 537 | if ($num>9) { 538 | die("the string is not a proper binary coded decimal\n"); 539 | } else { 540 | $res.=$num; 541 | } 542 | } 543 | return $res; 544 | } 545 | public function getData() 546 | { 547 | return $this->values; 548 | } 549 | public function getISO() 550 | { 551 | return $this->getType().$this->getBitmap().$this->getBody(); 552 | } 553 | public function setISO($iso) 554 | { 555 | return $this->parse($iso); 556 | } 557 | public function setType($type) 558 | { 559 | $this->type = $type; 560 | } 561 | public function getType() 562 | { 563 | return sprintf("%04d", $this->type); 564 | } 565 | } 566 | ?> 567 | --------------------------------------------------------------------------------