├── .gitignore
├── LICENSE
├── README.md
├── pom.xml
└── src
└── main
└── java
├── javapns
├── Push.java
├── communication
│ ├── AppleServer.java
│ ├── AppleServerBasicImpl.java
│ ├── ConnectionToAppleServer.java
│ ├── KeystoreManager.java
│ ├── ProxyManager.java
│ ├── ServerTrustingTrustManager.java
│ ├── WrappedKeystore.java
│ ├── exceptions
│ │ ├── CommunicationException.java
│ │ ├── InvalidCertificateChainException.java
│ │ ├── InvalidKeystoreFormatException.java
│ │ ├── InvalidKeystorePasswordException.java
│ │ ├── InvalidKeystoreReferenceException.java
│ │ ├── KeystoreException.java
│ │ └── package.html
│ └── package.html
├── devices
│ ├── Device.java
│ ├── DeviceFactory.java
│ ├── Devices.java
│ ├── exceptions
│ │ ├── DuplicateDeviceException.java
│ │ ├── InvalidDeviceTokenFormatException.java
│ │ ├── NullDeviceTokenException.java
│ │ ├── NullIdException.java
│ │ ├── UnknownDeviceException.java
│ │ └── package.html
│ ├── implementations
│ │ ├── basic
│ │ │ ├── BasicDevice.java
│ │ │ ├── BasicDeviceFactory.java
│ │ │ └── package.html
│ │ ├── jpa
│ │ │ ├── injection.xml
│ │ │ ├── package.html
│ │ │ └── readme.txt
│ │ └── package.html
│ └── package.html
├── feedback
│ ├── AppleFeedbackServer.java
│ ├── AppleFeedbackServerBasicImpl.java
│ ├── ConnectionToFeedbackServer.java
│ ├── FeedbackServiceManager.java
│ └── package.html
├── notification
│ ├── AppleNotificationServer.java
│ ├── AppleNotificationServerBasicImpl.java
│ ├── ConnectionToNotificationServer.java
│ ├── NewsstandNotificationPayload.java
│ ├── Payload.java
│ ├── PayloadPerDevice.java
│ ├── PushNotificationBigPayload.java
│ ├── PushNotificationManager.java
│ ├── PushNotificationPayload.java
│ ├── PushedNotification.java
│ ├── PushedNotifications.java
│ ├── ResponsePacket.java
│ ├── ResponsePacketReader.java
│ ├── exceptions
│ │ ├── ErrorResponsePacketReceivedException.java
│ │ ├── PayloadAlertAlreadyExistsException.java
│ │ ├── PayloadIsEmptyException.java
│ │ ├── PayloadMaxSizeExceededException.java
│ │ ├── PayloadMaxSizeProbablyExceededException.java
│ │ └── package.html
│ ├── management
│ │ ├── APNPayload.java
│ │ ├── CalDAVPayload.java
│ │ ├── CalendarSubscriptionPayload.java
│ │ ├── EmailPayload.java
│ │ ├── LDAPPayload.java
│ │ ├── MobileConfigPayload.java
│ │ ├── PasswordPolicyPayload.java
│ │ ├── RemovalPasswordPayload.java
│ │ ├── RestrictionsPayload.java
│ │ ├── SCEPPayload.java
│ │ ├── VPNPayload.java
│ │ ├── WebClipPayload.java
│ │ ├── WiFiPayload.java
│ │ └── package.html
│ ├── package.html
│ └── transmission
│ │ ├── NotificationProgressListener.java
│ │ ├── NotificationThread.java
│ │ ├── NotificationThreads.java
│ │ ├── PushQueue.java
│ │ └── package.html
├── overview.html
├── package.html
└── test
│ ├── FeedbackTest.java
│ ├── NotificationTest.java
│ ├── SpecificNotificationTests.java
│ ├── TestFoundation.java
│ └── package.html
└── org
└── json
├── CDL.java
├── Cookie.java
├── CookieList.java
├── HTTP.java
├── HTTPTokener.java
├── JSONArray.java
├── JSONException.java
├── JSONML.java
├── JSONNull.java
├── JSONObject.java
├── JSONRawValue.java
├── JSONString.java
├── JSONStringer.java
├── JSONTokener.java
├── JSONWriter.java
├── Test.java
├── XML.java
├── XMLTokener.java
└── package.html
/.gitignore:
--------------------------------------------------------------------------------
1 | *.class
2 |
3 | .project
4 | .classpath
5 | .settings
6 | target
7 |
8 | # Package Files #
9 | *.jar
10 | *.war
11 | *.ear
12 |
13 | .idea
14 | *.iml
15 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU LESSER GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
An object representing the result of a push notification to a specific payload to a single device.
10 | * 11 | *If any error occurred while trying to push the notification, an exception is attached.
12 | * 13 | *If Apple's Push Notification Service returned an error-response packet, it is linked to the related PushedNotification 14 | * so you can find out what the actual error was.
15 | * 16 | * @author Sylvain Pedneault 17 | */ 18 | public class PushedNotification { 19 | 20 | private Payload payload; 21 | private Device device; 22 | private ResponsePacket response; 23 | 24 | private int identifier; 25 | private long expiry; 26 | private int transmissionAttempts; 27 | private boolean transmissionCompleted; 28 | 29 | private Exception exception; 30 | 31 | 32 | protected PushedNotification(Device device, Payload payload) { 33 | this.device = device; 34 | this.payload = payload; 35 | } 36 | 37 | 38 | protected PushedNotification(Device device, Payload payload, int identifier) { 39 | this.device = device; 40 | this.payload = payload; 41 | this.identifier = identifier; 42 | } 43 | 44 | 45 | public PushedNotification(Device device, Payload payload, Exception exception) { 46 | this.device = device; 47 | this.payload = payload; 48 | this.exception = exception; 49 | } 50 | 51 | 52 | /** 53 | * Returns the payload that was pushed. 54 | * 55 | * @return the payload that was pushed 56 | */ 57 | public Payload getPayload() { 58 | return payload; 59 | } 60 | 61 | 62 | protected void setPayload(Payload payload) { 63 | this.payload = payload; 64 | } 65 | 66 | 67 | /** 68 | * Returns the device that the payload was pushed to. 69 | * @return the device that the payload was pushed to 70 | */ 71 | public Device getDevice() { 72 | return device; 73 | } 74 | 75 | 76 | protected void setDevice(Device device) { 77 | this.device = device; 78 | } 79 | 80 | 81 | /** 82 | * Returns the connection-unique identifier referred to by 83 | * error-response packets. 84 | * 85 | * @return a connection-unique identifier 86 | */ 87 | public int getIdentifier() { 88 | return identifier; 89 | } 90 | 91 | 92 | protected void setIdentifier(int identifier) { 93 | this.identifier = identifier; 94 | } 95 | 96 | 97 | /** 98 | * Returns the expiration date of the push notification. 99 | * 100 | * @return the expiration date of the push notification. 101 | */ 102 | public long getExpiry() { 103 | return expiry; 104 | } 105 | 106 | 107 | protected void setExpiry(long expiry) { 108 | this.expiry = expiry; 109 | } 110 | 111 | 112 | protected void setTransmissionAttempts(int transmissionAttempts) { 113 | this.transmissionAttempts = transmissionAttempts; 114 | } 115 | 116 | 117 | protected void addTransmissionAttempt() { 118 | transmissionAttempts++; 119 | } 120 | 121 | 122 | /** 123 | * Returns the number of attempts that have been made to transmit the notification. 124 | * @return a number of attempts 125 | */ 126 | public int getTransmissionAttempts() { 127 | return transmissionAttempts; 128 | } 129 | 130 | 131 | /** 132 | * Returns a human-friendly description of the number of attempts made to transmit the notification. 133 | * @return a human-friendly description of the number of attempts made to transmit the notification 134 | */ 135 | public String getLatestTransmissionAttempt() { 136 | if (transmissionAttempts == 0) return "no attempt yet"; 137 | switch (transmissionAttempts) { 138 | case 0: 139 | return "no attempt yet"; 140 | case 1: 141 | return "first attempt"; 142 | case 2: 143 | return "second attempt"; 144 | case 3: 145 | return "third attempt"; 146 | case 4: 147 | return "fourth attempt"; 148 | default: 149 | return "attempt #" + transmissionAttempts; 150 | } 151 | } 152 | 153 | 154 | protected void setTransmissionCompleted(boolean completed) { 155 | this.transmissionCompleted = completed; 156 | } 157 | 158 | 159 | /** 160 | * Indicates if the notification has been streamed successfully to Apple's server. 161 | * This does not indicate if an error-response was received or not, but simply 162 | * that the library successfully completed the transmission of the notification to 163 | * Apple's server. 164 | * @return true if the notification was successfully streamed to Apple, false otherwise 165 | */ 166 | public boolean isTransmissionCompleted() { 167 | return transmissionCompleted; 168 | } 169 | 170 | 171 | protected void setResponse(ResponsePacket response) { 172 | this.response = response; 173 | if (response != null && exception == null) exception = new ErrorResponsePacketReceivedException(response); 174 | } 175 | 176 | 177 | /** 178 | * If a response packet regarding this notification was received, 179 | * this method returns it. Otherwise it returns null. 180 | * 181 | * @return a response packet, if one was received for this notification 182 | */ 183 | public ResponsePacket getResponse() { 184 | return response; 185 | } 186 | 187 | 188 | /** 189 | *Returns true if no response packet was received for this notification, 190 | * or if one was received but is not an error-response (ie command 8), 191 | * or if one was received but its status is 0 (no error occurred).
192 | * 193 | *Returns false if an error-response packet is attached and has 194 | * a non-zero status code.
195 | * 196 | *Returns false if an exception is attached.
197 | * 198 | *Make sure you use the Feedback Service to cleanup your list of 199 | * invalid device tokens, as Apple's documentation says.
200 | * 201 | * @return true if push was successful, false otherwise 202 | */ 203 | public boolean isSuccessful() { 204 | if (!transmissionCompleted) return false; 205 | if (response == null) return true; 206 | if (!response.isValidErrorMessage()) return true; 207 | return false; 208 | } 209 | 210 | 211 | /** 212 | * Filters a list of pushed notifications and returns only the ones that were successful. 213 | * 214 | * @param notifications a list of pushed notifications 215 | * @return a filtered list containing only notifications that were succcessful 216 | */ 217 | public static ListA list of PushedNotification objects.
7 | * 8 | *This list can be configured to retain a maximum number of objects. When that maximum is reached, older objects are removed from the list before new ones are added.
9 | * 10 | *Internally, this list extends Vector.
11 | * 12 | * @author Sylvain Pedneault 13 | */ 14 | public class PushedNotifications extends VectorMDM is not involved in Apple Push Notification, but uses the 12 | same communication technologies as APN.
13 |Nevertheless, this package is provided in an effort to help 14 | javapns become more widely used.
15 | 16 | 17 | -------------------------------------------------------------------------------- /src/main/java/javapns/notification/package.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | Classes for pushing notifications through Apple servers. 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/main/java/javapns/notification/transmission/NotificationProgressListener.java: -------------------------------------------------------------------------------- 1 | package javapns.notification.transmission; 2 | 3 | /** 4 | *A Java library for interacting with Apple's Push Notification Service.
11 | 12 |The simplest way of pushing notifications with JavaPNS is to use the javapns.Push
class:
15 | import javapns.Push;
16 |
17 | public class PushTest {
18 |
19 | public static void main(String[] args) {
20 |
21 | Push.alert("Hello World!", "keystore.p12", "keystore_password", false, "Your token");
22 | }
23 | }
24 |
25 |
26 | For more details about using the library, see the on-line wiki at:
27 |
28 | http://code.google.com/p/javapns/w/list
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/src/main/java/javapns/package.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
7 |
8 |
9 | See the javapns.Push
class for easy push notifications.
Example: java -cp "[required libraries]" javapns.test.FeedbackTest keystore.p12 mypass
By default, this test uses the sandbox service. To switch, add "production" as a third parameter:
14 | *Example: java -cp "[required libraries]" javapns.test.FeedbackTest keystore.p12 mypass production
Example: java -cp "[required libraries]" javapns.test.NotificationTest keystore.p12 mypass 2ed202ac08ea9033665e853a3dc8bc4c5e78f7a6cf8d55910df230567037dcc4
By default, this test uses the sandbox service. To switch, add "production" as a fourth parameter:
19 | *Example: java -cp "[required libraries]" javapns.test.NotificationTest keystore.p12 mypass 2ed202ac08ea9033665e853a3dc8bc4c5e78f7a6cf8d55910df230567037dcc4 production
Also by default, this test pushes a simple alert. To send a complex payload, add "complex" as a fifth parameter:
22 | *Example: java -cp "[required libraries]" javapns.test.NotificationTest keystore.p12 mypass 2ed202ac08ea9033665e853a3dc8bc4c5e78f7a6cf8d55910df230567037dcc4 production complex
To send a simple payload to a large number of fake devices, add "threads" as a fifth parameter, the number of fake devices to construct, and the number of threads to use:
25 | *Example: java -cp "[required libraries]" javapns.test.NotificationTest keystore.p12 mypass 2ed202ac08ea9033665e853a3dc8bc4c5e78f7a6cf8d55910df230567037dcc4 sandbox threads 1000 5
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 2009-06-18
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 | break;
73 | }
74 | if (c == 0 || c == '\n' || c == '\r') {
75 | throw x.syntaxError("Missing close quote '" + q + "'.");
76 | }
77 | sb.append(c);
78 | }
79 | return sb.toString();
80 | case ',':
81 | x.back();
82 | return "";
83 | default:
84 | x.back();
85 | return x.nextTo(',');
86 | }
87 | }
88 |
89 | /**
90 | * Produce a JSONArray of strings from a row of comma delimited values.
91 | * @param x A JSONTokener of the source text.
92 | * @return A JSONArray of strings.
93 | * @throws JSONException
94 | */
95 | public static JSONArray rowToJSONArray(JSONTokener x) throws JSONException {
96 | JSONArray ja = new JSONArray();
97 | for (;;) {
98 | String value = getValue(x);
99 | if (value == null || (ja.length() == 0 && value.length() == 0)) {
100 | return null;
101 | }
102 | ja.put(value);
103 | for (;;) {
104 | char c = x.next();
105 | if (c == ',') {
106 | break;
107 | }
108 | if (c != ' ') {
109 | if (c == '\n' || c == '\r' || c == 0) {
110 | return ja;
111 | }
112 | throw x.syntaxError("Bad character '" + c + "' (" +
113 | (int)c + ").");
114 | }
115 | }
116 | }
117 | }
118 |
119 | /**
120 | * Produce a JSONObject from a row of comma delimited text, using a
121 | * parallel JSONArray of strings to provides the names of the elements.
122 | * @param names A JSONArray of names. This is commonly obtained from the
123 | * first row of a comma delimited text file using the rowToJSONArray
124 | * method.
125 | * @param x A JSONTokener of the source text.
126 | * @return A JSONObject combining the names and values.
127 | * @throws JSONException
128 | */
129 | public static JSONObject rowToJSONObject(JSONArray names, JSONTokener x)
130 | throws JSONException {
131 | JSONArray ja = rowToJSONArray(x);
132 | return ja != null ? ja.toJSONObject(names) : null;
133 | }
134 |
135 | /**
136 | * Produce a JSONArray of JSONObjects from a comma delimited text string,
137 | * using the first row as a source of names.
138 | * @param string The comma delimited text.
139 | * @return A JSONArray of JSONObjects.
140 | * @throws JSONException
141 | */
142 | public static JSONArray toJSONArray(String string) throws JSONException {
143 | return toJSONArray(new JSONTokener(string));
144 | }
145 |
146 | /**
147 | * Produce a JSONArray of JSONObjects from a comma delimited text string,
148 | * using the first row as a source of names.
149 | * @param x The JSONTokener containing the comma delimited text.
150 | * @return A JSONArray of JSONObjects.
151 | * @throws JSONException
152 | */
153 | public static JSONArray toJSONArray(JSONTokener x) throws JSONException {
154 | return toJSONArray(rowToJSONArray(x), x);
155 | }
156 |
157 | /**
158 | * Produce a JSONArray of JSONObjects from a comma delimited text string
159 | * using a supplied JSONArray as the source of element names.
160 | * @param names A JSONArray of strings.
161 | * @param string The comma delimited text.
162 | * @return A JSONArray of JSONObjects.
163 | * @throws JSONException
164 | */
165 | public static JSONArray toJSONArray(JSONArray names, String string)
166 | throws JSONException {
167 | return toJSONArray(names, new JSONTokener(string));
168 | }
169 |
170 | /**
171 | * Produce a JSONArray of JSONObjects from a comma delimited text string
172 | * using a supplied JSONArray as the source of element names.
173 | * @param names A JSONArray of strings.
174 | * @param x A JSONTokener of the source text.
175 | * @return A JSONArray of JSONObjects.
176 | * @throws JSONException
177 | */
178 | public static JSONArray toJSONArray(JSONArray names, JSONTokener x)
179 | throws JSONException {
180 | if (names == null || names.length() == 0) {
181 | return null;
182 | }
183 | JSONArray ja = new JSONArray();
184 | for (;;) {
185 | JSONObject jo = rowToJSONObject(names, x);
186 | if (jo == null) {
187 | break;
188 | }
189 | ja.put(jo);
190 | }
191 | if (ja.length() == 0) {
192 | return null;
193 | }
194 | return ja;
195 | }
196 |
197 |
198 | /**
199 | * Produce a comma delimited text row from a JSONArray. Values containing
200 | * the comma character will be quoted. Troublesome characters may be
201 | * removed.
202 | * @param ja A JSONArray of strings.
203 | * @return A string ending in NEWLINE.
204 | */
205 | public static String rowToString(JSONArray ja) {
206 | StringBuffer sb = new StringBuffer();
207 | for (int i = 0; i < ja.length(); i += 1) {
208 | if (i > 0) {
209 | sb.append(',');
210 | }
211 | Object o = ja.opt(i);
212 | if (o != null) {
213 | String s = o.toString();
214 | if (s.indexOf(',') >= 0 || s.indexOf('\n') >= 0 ||
215 | s.indexOf('\r') >= 0 || s.indexOf(0) >= 0 ||
216 | s.charAt(0) == '"') {
217 | sb.append('"');
218 | int length = s.length();
219 | for (int j = 0; j < length; j += 1) {
220 | char c = s.charAt(j);
221 | if (c >= ' ' && c != '"') {
222 | sb.append(c);
223 | }
224 | }
225 | sb.append('"');
226 | } else {
227 | sb.append(s);
228 | }
229 | }
230 | }
231 | sb.append('\n');
232 | return sb.toString();
233 | }
234 |
235 | /**
236 | * Produce a comma delimited text from a JSONArray of JSONObjects. The
237 | * first row will be a list of names obtained by inspecting the first
238 | * JSONObject.
239 | * @param ja A JSONArray of JSONObjects.
240 | * @return A comma delimited text.
241 | * @throws JSONException
242 | */
243 | public static String toString(JSONArray ja) throws JSONException {
244 | JSONObject jo = ja.optJSONObject(0);
245 | if (jo != null) {
246 | JSONArray names = jo.names();
247 | if (names != null) {
248 | return rowToString(names) + toString(names, ja);
249 | }
250 | }
251 | return null;
252 | }
253 |
254 | /**
255 | * Produce a comma delimited text from a JSONArray of JSONObjects using
256 | * a provided list of names. The list of names is not included in the
257 | * output.
258 | * @param names A JSONArray of strings.
259 | * @param ja A JSONArray of JSONObjects.
260 | * @return A comma delimited text.
261 | * @throws JSONException
262 | */
263 | public static String toString(JSONArray names, JSONArray ja)
264 | throws JSONException {
265 | if (names == null || names.length() == 0) {
266 | return null;
267 | }
268 | StringBuffer sb = new StringBuffer();
269 | for (int i = 0; i < ja.length(); i += 1) {
270 | JSONObject jo = ja.optJSONObject(i);
271 | if (jo != null) {
272 | sb.append(rowToString(jo.toJSONArray(names)));
273 | }
274 | }
275 | return sb.toString();
276 | }
277 | }
278 |
--------------------------------------------------------------------------------
/src/main/java/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 2008-09-18
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 | StringBuffer sb = new StringBuffer();
51 | int len = s.length();
52 | for (int i = 0; i < len; 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 n;
83 | JSONObject o = new JSONObject();
84 | Object v;
85 | JSONTokener x = new JSONTokener(string);
86 | o.put("name", x.nextTo('='));
87 | x.next('=');
88 | o.put("value", x.nextTo(';'));
89 | x.next();
90 | while (x.more()) {
91 | n = unescape(x.nextTo("=;"));
92 | if (x.next() != '=') {
93 | if (n.equals("secure")) {
94 | v = Boolean.TRUE;
95 | } else {
96 | throw x.syntaxError("Missing '=' in cookie parameter.");
97 | }
98 | } else {
99 | v = unescape(x.nextTo(';'));
100 | x.next();
101 | }
102 | o.put(n, v);
103 | }
104 | return o;
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 o A JSONObject
115 | * @return A cookie specification string
116 | * @throws JSONException
117 | */
118 | public static String toString(JSONObject o) throws JSONException {
119 | StringBuffer sb = new StringBuffer();
120 |
121 | sb.append(escape(o.getString("name")));
122 | sb.append("=");
123 | sb.append(escape(o.getString("value")));
124 | if (o.has("expires")) {
125 | sb.append(";expires=");
126 | sb.append(o.getString("expires"));
127 | }
128 | if (o.has("domain")) {
129 | sb.append(";domain=");
130 | sb.append(escape(o.getString("domain")));
131 | }
132 | if (o.has("path")) {
133 | sb.append(";path=");
134 | sb.append(escape(o.getString("path")));
135 | }
136 | if (o.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 s A string that may contain
146 | * +
(plus) and
147 | * %
hh sequences.
148 | * @return The unescaped string.
149 | */
150 | public static String unescape(String s) {
151 | int len = s.length();
152 | StringBuffer b = new StringBuffer();
153 | for (int i = 0; i < len; ++i) {
154 | char c = s.charAt(i);
155 | if (c == '+') {
156 | c = ' ';
157 | } else if (c == '%' && i + 2 < len) {
158 | int d = JSONTokener.dehexchar(s.charAt(i + 1));
159 | int e = JSONTokener.dehexchar(s.charAt(i + 2));
160 | if (d >= 0 && e >= 0) {
161 | c = (char)(d * 16 + e);
162 | i += 2;
163 | }
164 | }
165 | b.append(c);
166 | }
167 | return b.toString();
168 | }
169 | }
170 |
--------------------------------------------------------------------------------
/src/main/java/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 | import java.util.Iterator;
28 |
29 | /**
30 | * Convert a web browser cookie list string to a JSONObject and back.
31 | * @author JSON.org
32 | * @version 2008-09-18
33 | */
34 | public class CookieList {
35 |
36 | /**
37 | * Convert a cookie list into a JSONObject. A cookie list is a sequence
38 | * of name/value pairs. The names are separated from the values by '='.
39 | * The pairs are separated by ';'. The names and the values
40 | * will be unescaped, possibly converting '+' and '%' sequences.
41 | *
42 | * To add a cookie to a cooklist,
43 | * cookielistJSONObject.put(cookieJSONObject.getString("name"),
44 | * cookieJSONObject.getString("value"));
45 | * @param string A cookie list string
46 | * @return A JSONObject
47 | * @throws JSONException
48 | */
49 | public static JSONObject toJSONObject(String string) throws JSONException {
50 | JSONObject o = new JSONObject();
51 | JSONTokener x = new JSONTokener(string);
52 | while (x.more()) {
53 | String name = Cookie.unescape(x.nextTo('='));
54 | x.next('=');
55 | o.put(name, Cookie.unescape(x.nextTo(';')));
56 | x.next();
57 | }
58 | return o;
59 | }
60 |
61 |
62 | /**
63 | * Convert a JSONObject into a cookie list. A cookie list is a sequence
64 | * of name/value pairs. The names are separated from the values by '='.
65 | * The pairs are separated by ';'. The characters '%', '+', '=', and ';'
66 | * in the names and values are replaced by "%hh".
67 | * @param o A JSONObject
68 | * @return A cookie list string
69 | * @throws JSONException
70 | */
71 | public static String toString(JSONObject o) throws JSONException {
72 | boolean b = false;
73 | Iterator keys = o.keys();
74 | String s;
75 | StringBuffer sb = new StringBuffer();
76 | while (keys.hasNext()) {
77 | s = keys.next().toString();
78 | if (!o.isNull(s)) {
79 | if (b) {
80 | sb.append(';');
81 | }
82 | sb.append(Cookie.escape(s));
83 | sb.append("=");
84 | sb.append(Cookie.escape(o.getString(s)));
85 | b = true;
86 | }
87 | }
88 | return sb.toString();
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/src/main/java/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.Iterator;
28 |
29 | /**
30 | * Convert an HTTP header to a JSONObject and back.
31 | * @author JSON.org
32 | * @version 2008-09-18
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-cache58 | * 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 o = new JSONObject(); 73 | HTTPTokener x = new HTTPTokener(string); 74 | String t; 75 | 76 | t = x.nextToken(); 77 | if (t.toUpperCase().startsWith("HTTP")) { 78 | 79 | // Response 80 | 81 | o.put("HTTP-Version", t); 82 | o.put("Status-Code", x.nextToken()); 83 | o.put("Reason-Phrase", x.nextTo('\0')); 84 | x.next(); 85 | 86 | } else { 87 | 88 | // Request 89 | 90 | o.put("Method", t); 91 | o.put("Request-URI", x.nextToken()); 92 | o.put("HTTP-Version", x.nextToken()); 93 | } 94 | 95 | // Fields 96 | 97 | while (x.more()) { 98 | String name = x.nextTo(':'); 99 | x.next(':'); 100 | o.put(name, x.nextTo('\0')); 101 | x.next(); 102 | } 103 | return o; 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 o 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 o) throws JSONException { 128 | Iterator keys = o.keys(); 129 | String s; 130 | StringBuffer sb = new StringBuffer(); 131 | if (o.has("Status-Code") && o.has("Reason-Phrase")) { 132 | sb.append(o.getString("HTTP-Version")); 133 | sb.append(' '); 134 | sb.append(o.getString("Status-Code")); 135 | sb.append(' '); 136 | sb.append(o.getString("Reason-Phrase")); 137 | } else if (o.has("Method") && o.has("Request-URI")) { 138 | sb.append(o.getString("Method")); 139 | sb.append(' '); 140 | sb.append('"'); 141 | sb.append(o.getString("Request-URI")); 142 | sb.append('"'); 143 | sb.append(' '); 144 | sb.append(o.getString("HTTP-Version")); 145 | } else { 146 | throw new JSONException("Not enough material for an HTTP header."); 147 | } 148 | sb.append(CRLF); 149 | while (keys.hasNext()) { 150 | s = keys.next().toString(); 151 | if (!s.equals("HTTP-Version") && !s.equals("Status-Code") && 152 | !s.equals("Reason-Phrase") && !s.equals("Method") && 153 | !s.equals("Request-URI") && !o.isNull(s)) { 154 | sb.append(s); 155 | sb.append(": "); 156 | sb.append(o.getString(s)); 157 | sb.append(CRLF); 158 | } 159 | } 160 | sb.append(CRLF); 161 | return sb.toString(); 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /src/main/java/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 2008-09-18 32 | */ 33 | public class HTTPTokener extends JSONTokener { 34 | 35 | /** 36 | * Construct an HTTPTokener from a string. 37 | * @param s A source string. 38 | */ 39 | public HTTPTokener(String s) { 40 | super(s); 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 | StringBuffer sb = new StringBuffer(); 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 | -------------------------------------------------------------------------------- /src/main/java/org/json/JSONException.java: -------------------------------------------------------------------------------- 1 | package org.json; 2 | 3 | /** 4 | * The JSONException is thrown by the JSON.org classes then things are amiss. 5 | * @author JSON.org 6 | * @version 2008-09-18 7 | */ 8 | @SuppressWarnings("serial") 9 | public class JSONException extends Exception { 10 | private Throwable cause; 11 | 12 | /** 13 | * Constructs a JSONException with an explanatory message. 14 | * @param message Detail about the reason for the exception. 15 | */ 16 | public JSONException(String message) { 17 | super(message); 18 | } 19 | 20 | public JSONException(Throwable t) { 21 | super(t.getMessage()); 22 | this.cause = t; 23 | } 24 | 25 | public Throwable getCause() { 26 | return this.cause; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/org/json/JSONNull.java: -------------------------------------------------------------------------------- 1 | package org.json; 2 | 3 | public class JSONNull implements JSONRawValue { 4 | 5 | @Override 6 | public String toString() { 7 | return "null"; 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/org/json/JSONRawValue.java: -------------------------------------------------------------------------------- 1 | package org.json; 2 | 3 | public interface JSONRawValue { 4 | 5 | @Override 6 | public String toString(); 7 | 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/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 |
--------------------------------------------------------------------------------
/src/main/java/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 2008-09-18
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 | public String toString() {
76 | return this.mode == 'd' ? this.writer.toString() : null;
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/src/main/java/org/json/JSONWriter.java:
--------------------------------------------------------------------------------
1 | package org.json;
2 |
3 | import java.io.IOException;
4 | import java.io.Writer;
5 |
6 | /*
7 | Copyright (c) 2006 JSON.org
8 |
9 | Permission is hereby granted, free of charge, to any person obtaining a copy
10 | of this software and associated documentation files (the "Software"), to deal
11 | in the Software without restriction, including without limitation the rights
12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | copies of the Software, and to permit persons to whom the Software is
14 | furnished to do so, subject to the following conditions:
15 |
16 | The above copyright notice and this permission notice shall be included in all
17 | copies or substantial portions of the Software.
18 |
19 | The Software shall be used for Good, not Evil.
20 |
21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 | SOFTWARE.
28 | */
29 |
30 | /**
31 | * JSONWriter provides a quick and convenient way of producing JSON text.
32 | * The texts produced strictly conform to JSON syntax rules. No whitespace is
33 | * added, so the results are ready for transmission or storage. Each instance of
34 | * JSONWriter can produce one JSON text.
35 | *
36 | * A JSONWriter instance provides a value
method for appending
37 | * values to the
38 | * text, and a key
39 | * method for adding keys before values in objects. There are array
40 | * and endArray
methods that make and bound array values, and
41 | * object
and endObject
methods which make and bound
42 | * object values. All of these methods return the JSONWriter instance,
43 | * permitting a cascade style. For example,
44 | * new JSONWriter(myWriter) 45 | * .object() 46 | * .key("JSON") 47 | * .value("Hello, World!") 48 | * .endObject();which writes
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. JSONWriter 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 2008-09-22
58 | */
59 | public class JSONWriter {
60 | private static final int maxdepth = 20;
61 |
62 | /**
63 | * The comma flag determines if a comma should be output before the next
64 | * value.
65 | */
66 | private boolean comma;
67 |
68 | /**
69 | * The current mode. Values:
70 | * 'a' (array),
71 | * 'd' (done),
72 | * 'i' (initial),
73 | * 'k' (key),
74 | * 'o' (object).
75 | */
76 | protected char mode;
77 |
78 | /**
79 | * The object/array stack.
80 | */
81 | private JSONObject stack[];
82 |
83 | /**
84 | * The stack top index. A value of 0 indicates that the stack is empty.
85 | */
86 | private int top;
87 |
88 | /**
89 | * The writer that will receive the output.
90 | */
91 | protected Writer writer;
92 |
93 | /**
94 | * Make a fresh JSONWriter. It can be used to build one JSON text.
95 | */
96 | public JSONWriter(Writer w) {
97 | this.comma = false;
98 | this.mode = 'i';
99 | this.stack = new JSONObject[maxdepth];
100 | this.top = 0;
101 | this.writer = w;
102 | }
103 |
104 | /**
105 | * Append a value.
106 | * @param s A string value.
107 | * @return this
108 | * @throws JSONException If the value is out of sequence.
109 | */
110 | private JSONWriter append(String s) throws JSONException {
111 | if (s == null) {
112 | throw new JSONException("Null pointer");
113 | }
114 | if (this.mode == 'o' || this.mode == 'a') {
115 | try {
116 | if (this.comma && this.mode == 'a') {
117 | this.writer.write(',');
118 | }
119 | this.writer.write(s);
120 | } catch (IOException e) {
121 | throw new JSONException(e);
122 | }
123 | if (this.mode == 'o') {
124 | this.mode = 'k';
125 | }
126 | this.comma = true;
127 | return this;
128 | }
129 | throw new JSONException("Value out of sequence.");
130 | }
131 |
132 | /**
133 | * Begin appending a new array. All values until the balancing
134 | * endArray
will be appended to this array. The
135 | * endArray
method must be called to mark the array's end.
136 | * @return this
137 | * @throws JSONException If the nesting is too deep, or if the object is
138 | * started in the wrong place (for example as a key or after the end of the
139 | * outermost array or object).
140 | */
141 | public JSONWriter array() throws JSONException {
142 | if (this.mode == 'i' || this.mode == 'o' || this.mode == 'a') {
143 | this.push(null);
144 | this.append("[");
145 | this.comma = false;
146 | return this;
147 | }
148 | throw new JSONException("Misplaced array.");
149 | }
150 |
151 | /**
152 | * End something.
153 | * @param m Mode
154 | * @param c Closing character
155 | * @return this
156 | * @throws JSONException If unbalanced.
157 | */
158 | private JSONWriter end(char m, char c) throws JSONException {
159 | if (this.mode != m) {
160 | throw new JSONException(m == 'o' ? "Misplaced endObject." :
161 | "Misplaced endArray.");
162 | }
163 | this.pop(m);
164 | try {
165 | this.writer.write(c);
166 | } catch (IOException e) {
167 | throw new JSONException(e);
168 | }
169 | this.comma = true;
170 | return this;
171 | }
172 |
173 | /**
174 | * End an array. This method most be called to balance calls to
175 | * array
.
176 | * @return this
177 | * @throws JSONException If incorrectly nested.
178 | */
179 | public JSONWriter endArray() throws JSONException {
180 | return this.end('a', ']');
181 | }
182 |
183 | /**
184 | * End an object. This method most be called to balance calls to
185 | * object
.
186 | * @return this
187 | * @throws JSONException If incorrectly nested.
188 | */
189 | public JSONWriter endObject() throws JSONException {
190 | return this.end('k', '}');
191 | }
192 |
193 | /**
194 | * Append a key. The key will be associated with the next value. In an
195 | * object, every value must be preceded by a key.
196 | * @param s A key string.
197 | * @return this
198 | * @throws JSONException If the key is out of place. For example, keys
199 | * do not belong in arrays or if the key is null.
200 | */
201 | public JSONWriter key(String s) throws JSONException {
202 | if (s == null) {
203 | throw new JSONException("Null key.");
204 | }
205 | if (this.mode == 'k') {
206 | try {
207 | stack[top - 1].putOnce(s, Boolean.TRUE);
208 | if (this.comma) {
209 | this.writer.write(',');
210 | }
211 | this.writer.write(JSONObject.quote(s));
212 | this.writer.write(':');
213 | this.comma = false;
214 | this.mode = 'o';
215 | return this;
216 | } catch (IOException e) {
217 | throw new JSONException(e);
218 | }
219 | }
220 | throw new JSONException("Misplaced key.");
221 | }
222 |
223 |
224 | /**
225 | * Begin appending a new object. All keys and values until the balancing
226 | * endObject
will be appended to this object. The
227 | * endObject
method must be called to mark the object's end.
228 | * @return this
229 | * @throws JSONException If the nesting is too deep, or if the object is
230 | * started in the wrong place (for example as a key or after the end of the
231 | * outermost array or object).
232 | */
233 | public JSONWriter object() throws JSONException {
234 | if (this.mode == 'i') {
235 | this.mode = 'o';
236 | }
237 | if (this.mode == 'o' || this.mode == 'a') {
238 | this.append("{");
239 | this.push(new JSONObject());
240 | this.comma = false;
241 | return this;
242 | }
243 | throw new JSONException("Misplaced object.");
244 |
245 | }
246 |
247 |
248 | /**
249 | * Pop an array or object scope.
250 | * @param c The scope to close.
251 | * @throws JSONException If nesting is wrong.
252 | */
253 | private void pop(char c) throws JSONException {
254 | if (this.top <= 0) {
255 | throw new JSONException("Nesting error.");
256 | }
257 | char m = this.stack[this.top - 1] == null ? 'a' : 'k';
258 | if (m != c) {
259 | throw new JSONException("Nesting error.");
260 | }
261 | this.top -= 1;
262 | this.mode = this.top == 0 ? 'd' : this.stack[this.top - 1] == null ? 'a' : 'k';
263 | }
264 |
265 | /**
266 | * Push an array or object scope.
267 | * @param c The scope to open.
268 | * @throws JSONException If nesting is too deep.
269 | */
270 | private void push(JSONObject jo) throws JSONException {
271 | if (this.top >= maxdepth) {
272 | throw new JSONException("Nesting too deep.");
273 | }
274 | this.stack[this.top] = jo;
275 | this.mode = jo == null ? 'a' : 'k';
276 | this.top += 1;
277 | }
278 |
279 |
280 | /**
281 | * Append either the value true
or the value
282 | * false
.
283 | * @param b A boolean.
284 | * @return this
285 | * @throws JSONException
286 | */
287 | public JSONWriter value(boolean b) throws JSONException {
288 | return this.append(b ? "true" : "false");
289 | }
290 |
291 | /**
292 | * Append a double value.
293 | * @param d A double.
294 | * @return this
295 | * @throws JSONException If the number is not finite.
296 | */
297 | public JSONWriter value(double d) throws JSONException {
298 | return this.value(new Double(d));
299 | }
300 |
301 | /**
302 | * Append a long value.
303 | * @param l A long.
304 | * @return this
305 | * @throws JSONException
306 | */
307 | public JSONWriter value(long l) throws JSONException {
308 | return this.append(Long.toString(l));
309 | }
310 |
311 |
312 | /**
313 | * Append an object value.
314 | * @param o The object to append. It can be null, or a Boolean, Number,
315 | * String, JSONObject, or JSONArray, or an object with a toJSONString()
316 | * method.
317 | * @return this
318 | * @throws JSONException If the value is out of sequence.
319 | */
320 | public JSONWriter value(Object o) throws JSONException {
321 | return this.append(JSONObject.valueToString(o));
322 | }
323 | }
324 |
--------------------------------------------------------------------------------
/src/main/java/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 | /**
28 | * The XMLTokener extends the JSONTokener to provide additional methods
29 | * for the parsing of XML texts.
30 | * @author JSON.org
31 | * @version 2008-09-18
32 | */
33 | @SuppressWarnings("unchecked")
34 | public class XMLTokener extends JSONTokener {
35 |
36 |
37 | /** The table of entity values. It initially contains Character values for
38 | * amp, apos, gt, lt, quot.
39 | */
40 | public static final java.util.HashMap entity;
41 |
42 | static {
43 | entity = new java.util.HashMap(8);
44 | entity.put("amp", XML.AMP);
45 | entity.put("apos", XML.APOS);
46 | entity.put("gt", XML.GT);
47 | entity.put("lt", XML.LT);
48 | entity.put("quot", XML.QUOT);
49 | }
50 |
51 | /**
52 | * Construct an XMLTokener from a string.
53 | * @param s A source string.
54 | */
55 | public XMLTokener(String s) {
56 | super(s);
57 | }
58 |
59 | /**
60 | * Get the text in the CDATA block.
61 | * @return The string up to the ]]>
.
62 | * @throws JSONException If the ]]>
is not found.
63 | */
64 | public String nextCDATA() throws JSONException {
65 | char c;
66 | int i;
67 | StringBuffer sb = new StringBuffer();
68 | for (;;) {
69 | c = next();
70 | if (c == 0) {
71 | throw syntaxError("Unclosed CDATA");
72 | }
73 | sb.append(c);
74 | i = sb.length() - 3;
75 | if (i >= 0 && sb.charAt(i) == ']' &&
76 | sb.charAt(i + 1) == ']' && sb.charAt(i + 2) == '>') {
77 | sb.setLength(i);
78 | return sb.toString();
79 | }
80 | }
81 | }
82 |
83 |
84 | /**
85 | * Get the next XML outer token, trimming whitespace. There are two kinds
86 | * of tokens: the '<' character which begins a markup tag, and the content
87 | * text between markup tags.
88 | *
89 | * @return A string, or a '<' Character, or null if there is no more
90 | * source text.
91 | * @throws JSONException
92 | */
93 | public Object nextContent() throws JSONException {
94 | char c;
95 | StringBuffer sb;
96 | do {
97 | c = next();
98 | } while (Character.isWhitespace(c));
99 | if (c == 0) {
100 | return null;
101 | }
102 | if (c == '<') {
103 | return XML.LT;
104 | }
105 | sb = new StringBuffer();
106 | for (;;) {
107 | if (c == '<' || c == 0) {
108 | back();
109 | return sb.toString().trim();
110 | }
111 | if (c == '&') {
112 | sb.append(nextEntity(c));
113 | } else {
114 | sb.append(c);
115 | }
116 | c = next();
117 | }
118 | }
119 |
120 |
121 | /**
122 | * Return the next entity. These entities are translated to Characters:
123 | * & ' > < "
.
124 | * @param a An ampersand character.
125 | * @return A Character or an entity String if the entity is not recognized.
126 | * @throws JSONException If missing ';' in XML entity.
127 | */
128 | public Object nextEntity(char a) throws JSONException {
129 | StringBuffer sb = new StringBuffer();
130 | for (;;) {
131 | char c = next();
132 | if (Character.isLetterOrDigit(c) || c == '#') {
133 | sb.append(Character.toLowerCase(c));
134 | } else if (c == ';') {
135 | break;
136 | } else {
137 | throw syntaxError("Missing ';' in XML entity: &" + sb);
138 | }
139 | }
140 | String s = sb.toString();
141 | Object e = entity.get(s);
142 | return e != null ? e : a + s + ";";
143 | }
144 |
145 |
146 | /**
147 | * Returns the next XML meta token. This is used for skipping over
148 | * and ...?> structures.
149 | * @return Syntax characters (< > / = ! ?
) are returned as
150 | * Character, and strings and names are returned as Boolean. We don't care
151 | * what the values actually are.
152 | * @throws JSONException If a string is not properly closed or if the XML
153 | * is badly structured.
154 | */
155 | public Object nextMeta() throws JSONException {
156 | char c;
157 | char q;
158 | do {
159 | c = next();
160 | } while (Character.isWhitespace(c));
161 | switch (c) {
162 | case 0:
163 | throw syntaxError("Misshaped meta tag");
164 | case '<':
165 | return XML.LT;
166 | case '>':
167 | return XML.GT;
168 | case '/':
169 | return XML.SLASH;
170 | case '=':
171 | return XML.EQ;
172 | case '!':
173 | return XML.BANG;
174 | case '?':
175 | return XML.QUEST;
176 | case '"':
177 | case '\'':
178 | q = c;
179 | for (;;) {
180 | c = next();
181 | if (c == 0) {
182 | throw syntaxError("Unterminated string");
183 | }
184 | if (c == q) {
185 | return Boolean.TRUE;
186 | }
187 | }
188 | default:
189 | for (;;) {
190 | c = next();
191 | if (Character.isWhitespace(c)) {
192 | return Boolean.TRUE;
193 | }
194 | switch (c) {
195 | case 0:
196 | case '<':
197 | case '>':
198 | case '/':
199 | case '=':
200 | case '!':
201 | case '?':
202 | case '"':
203 | case '\'':
204 | back();
205 | return Boolean.TRUE;
206 | }
207 | }
208 | }
209 | }
210 |
211 |
212 | /**
213 | * Get the next XML Token. These tokens are found inside of angle
214 | * brackets. It may be one of these characters: / > = ! ?
or it
215 | * may be a string wrapped in single quotes or double quotes, or it may be a
216 | * name.
217 | * @return a String or a Character.
218 | * @throws JSONException If the XML is not well formed.
219 | */
220 | public Object nextToken() throws JSONException {
221 | char c;
222 | char q;
223 | StringBuffer sb;
224 | do {
225 | c = next();
226 | } while (Character.isWhitespace(c));
227 | switch (c) {
228 | case 0:
229 | throw syntaxError("Misshaped element");
230 | case '<':
231 | throw syntaxError("Misplaced '<'");
232 | case '>':
233 | return XML.GT;
234 | case '/':
235 | return XML.SLASH;
236 | case '=':
237 | return XML.EQ;
238 | case '!':
239 | return XML.BANG;
240 | case '?':
241 | return XML.QUEST;
242 |
243 | // Quoted string
244 |
245 | case '"':
246 | case '\'':
247 | q = c;
248 | sb = new StringBuffer();
249 | for (;;) {
250 | c = next();
251 | if (c == 0) {
252 | throw syntaxError("Unterminated string");
253 | }
254 | if (c == q) {
255 | return sb.toString();
256 | }
257 | if (c == '&') {
258 | sb.append(nextEntity(c));
259 | } else {
260 | sb.append(c);
261 | }
262 | }
263 | default:
264 |
265 | // Name
266 |
267 | sb = new StringBuffer();
268 | for (;;) {
269 | sb.append(c);
270 | c = next();
271 | if (Character.isWhitespace(c)) {
272 | return sb.toString();
273 | }
274 | switch (c) {
275 | case 0:
276 | return sb.toString();
277 | case '>':
278 | case '/':
279 | case '=':
280 | case '!':
281 | case '?':
282 | case '[':
283 | case ']':
284 | back();
285 | return sb.toString();
286 | case '<':
287 | case '"':
288 | case '\'':
289 | throw syntaxError("Bad character in a name");
290 | }
291 | }
292 | }
293 | }
294 |
295 |
296 | /**
297 | * Skip characters until past the requested string.
298 | * If it is not found, we are left at the end of the source with a result of false.
299 | * @param to A string to skip past.
300 | * @throws JSONException
301 | */
302 | public boolean skipPast(String to) throws JSONException {
303 | boolean b;
304 | char c;
305 | int i;
306 | int j;
307 | int offset = 0;
308 | int n = to.length();
309 | char[] circle = new char[n];
310 |
311 | /*
312 | * First fill the circle buffer with as many characters as are in the
313 | * to string. If we reach an early end, bail.
314 | */
315 |
316 | for (i = 0; i < n; i += 1) {
317 | c = next();
318 | if (c == 0) {
319 | return false;
320 | }
321 | circle[i] = c;
322 | }
323 | /*
324 | * We will loop, possibly for all of the remaining characters.
325 | */
326 | for (;;) {
327 | j = offset;
328 | b = true;
329 | /*
330 | * Compare the circle buffer with the to string.
331 | */
332 | for (i = 0; i < n; i += 1) {
333 | if (circle[j] != to.charAt(i)) {
334 | b = false;
335 | break;
336 | }
337 | j += 1;
338 | if (j >= n) {
339 | j -= n;
340 | }
341 | }
342 | /*
343 | * If we exit the loop with b intact, then victory is ours.
344 | */
345 | if (b) {
346 | return true;
347 | }
348 | /*
349 | * Get the next character. If there isn't one, then defeat is ours.
350 | */
351 | c = next();
352 | if (c == 0) {
353 | return false;
354 | }
355 | /*
356 | * Shove the character in the circle buffer and advance the
357 | * circle offset. The offset is mod n.
358 | */
359 | circle[offset] = c;
360 | offset += 1;
361 | if (offset >= n) {
362 | offset -= n;
363 | }
364 | }
365 | }
366 | }
367 |
--------------------------------------------------------------------------------
/src/main/java/org/json/package.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |