ARSCLib/src/main/java/com/reandroid/json/JSONWriter.java
2023-01-22 15:27:26 -05:00

225 lines
7.4 KiB
Java

/*
* Copyright (c) 2002 JSON.org (now "Public Domain")
* This is NOT property of REAndroid
* This package is renamed from org.json.* to avoid class conflict when used on anroid platforms
*/
package com.reandroid.json;
import java.io.IOException;
import java.util.Collection;
import java.util.Map;
public class JSONWriter {
private static final int maxdepth = 200;
private boolean comma;
protected char mode;
private final JSONObject stack[];
private int top;
protected Appendable writer;
public JSONWriter(Appendable w) {
this.comma = false;
this.mode = 'i';
this.stack = new JSONObject[maxdepth];
this.top = 0;
this.writer = w;
}
private JSONWriter append(String string) throws JSONException {
if (string == null) {
throw new JSONException("Null pointer");
}
if (this.mode == 'o' || this.mode == 'a') {
try {
if (this.comma && this.mode == 'a') {
this.writer.append(',');
}
this.writer.append(string);
} catch (IOException e) {
// Android as of API 25 does not support this exception constructor
// however we won't worry about it. If an exception is happening here
// it will just throw a "Method not found" exception instead.
throw new JSONException(e);
}
if (this.mode == 'o') {
this.mode = 'k';
}
this.comma = true;
return this;
}
throw new JSONException("Value out of sequence.");
}
public JSONWriter array() throws JSONException {
if (this.mode == 'i' || this.mode == 'o' || this.mode == 'a') {
this.push(null);
this.append("[");
this.comma = false;
return this;
}
throw new JSONException("Misplaced array.");
}
private JSONWriter end(char m, char c) throws JSONException {
if (this.mode != m) {
throw new JSONException(m == 'a'
? "Misplaced endArray."
: "Misplaced endObject.");
}
this.pop(m);
try {
this.writer.append(c);
} catch (IOException e) {
// Android as of API 25 does not support this exception constructor
// however we won't worry about it. If an exception is happening here
// it will just throw a "Method not found" exception instead.
throw new JSONException(e);
}
this.comma = true;
return this;
}
public JSONWriter endArray() throws JSONException {
return this.end('a', ']');
}
public JSONWriter endObject() throws JSONException {
return this.end('k', '}');
}
public JSONWriter key(String string) throws JSONException {
if (string == null) {
throw new JSONException("Null key.");
}
if (this.mode == 'k') {
try {
JSONObject topObject = this.stack[this.top - 1];
// don't use the built in putOnce method to maintain Android support
if(topObject.has(string)) {
throw new JSONException("Duplicate key \"" + string + "\"");
}
topObject.put(string, true);
if (this.comma) {
this.writer.append(',');
}
this.writer.append(JSONObject.quote(string));
this.writer.append(':');
this.comma = false;
this.mode = 'o';
return this;
} catch (IOException e) {
// Android as of API 25 does not support this exception constructor
// however we won't worry about it. If an exception is happening here
// it will just throw a "Method not found" exception instead.
throw new JSONException(e);
}
}
throw new JSONException("Misplaced key.");
}
public JSONWriter object() throws JSONException {
if (this.mode == 'i') {
this.mode = 'o';
}
if (this.mode == 'o' || this.mode == 'a') {
this.append("{");
this.push(new JSONObject());
this.comma = false;
return this;
}
throw new JSONException("Misplaced object.");
}
private void pop(char c) throws JSONException {
if (this.top <= 0) {
throw new JSONException("Nesting error.");
}
char m = this.stack[this.top - 1] == null ? 'a' : 'k';
if (m != c) {
throw new JSONException("Nesting error.");
}
this.top -= 1;
this.mode = this.top == 0
? 'd'
: this.stack[this.top - 1] == null
? 'a'
: 'k';
}
private void push(JSONObject jo) throws JSONException {
if (this.top >= maxdepth) {
throw new JSONException("Nesting too deep.");
}
this.stack[this.top] = jo;
this.mode = jo == null ? 'a' : 'k';
this.top += 1;
}
public static String valueToString(Object value) throws JSONException {
if (value == null || value.equals(null)) {
return "null";
}
if (value instanceof JSONString) {
String object;
try {
object = ((JSONString) value).toJSONString();
} catch (Exception e) {
throw new JSONException(e);
}
if (object != null) {
return object;
}
throw new JSONException("Bad value from toJSONString: " + object);
}
if (value instanceof Number) {
// not all Numbers may match actual JSON Numbers. i.e. Fractions or Complex
final String numberAsString = JSONObject.numberToString((Number) value);
if(JSONObject.NUMBER_PATTERN.matcher(numberAsString).matches()) {
// Close enough to a JSON number that we will return it unquoted
return numberAsString;
}
// The Number value is not a valid JSON number.
// Instead we will quote it as a string
return JSONObject.quote(numberAsString);
}
if (value instanceof Boolean || value instanceof JSONObject
|| value instanceof JSONArray) {
return value.toString();
}
if (value instanceof Map) {
Map<?, ?> map = (Map<?, ?>) value;
return new JSONObject(map).toString();
}
if (value instanceof Collection) {
Collection<?> coll = (Collection<?>) value;
return new JSONArray(coll).toString();
}
if (value.getClass().isArray()) {
return new JSONArray(value).toString();
}
if(value instanceof Enum<?>){
return JSONObject.quote(((Enum<?>)value).name());
}
return JSONObject.quote(value.toString());
}
public JSONWriter value(boolean b) throws JSONException {
return this.append(b ? "true" : "false");
}
public JSONWriter value(double d) throws JSONException {
return this.value(Double.valueOf(d));
}
public JSONWriter value(long l) throws JSONException {
return this.append(Long.toString(l));
}
public JSONWriter value(Object object) throws JSONException {
return this.append(valueToString(object));
}
}