blob: 3ac36215e4892c8a3a260bb8c476cae3228961d9 [file] [log] [blame]
package org.eclipse.e4.core.services;
import java.math.BigDecimal;
import java.text.CharacterIterator;
import java.text.StringCharacterIterator;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
public final class JSONObject {
Map map = new HashMap();
public JSONObject() {
}
public void set(String name, JSONObject value) {
map.put(name, value.map);
}
public void set(String name, JSONObject[] values) {
List maps = new ArrayList();
for (int i = 0; i < values.length; i++) {
maps.add(values[i].map);
}
map.put(name, maps);
}
public void set(String name, String value) {
map.put(name, value);
}
public void set(String name, String[] values) {
map.put(name, Arrays.asList(values));
}
public JSONObject getObject(String name) {
Map resultMap = (Map) map.get(name);
JSONObject result = asJSONObject(resultMap);
return result;
}
private JSONObject asJSONObject(Map m) {
JSONObject result = new JSONObject();
result.map = m;
return result;
}
public JSONObject[] getObjects(String name) {
Collection collection = (Collection) map.get(name);
JSONObject[] result = new JSONObject[collection.size()];
int i = 0;
for (Iterator it = collection.iterator(); it.hasNext();) {
Map m = (Map) it.next();
result[i++] = asJSONObject(m);
}
return result;
}
public String getString(String name) {
return (String) map.get(name);
}
public String[] getStrings(String name) {
return (String[]) map.get(name);
}
private static final String EMPTY_STRING = ""; //$NON-NLS-1$
private static final String NULL = "null"; //$NON-NLS-1$
public static JSONObject deserialize(String jsonString) {
Object result = parse(new StringCharacterIterator(jsonString));
if (!(result instanceof Map)) {
throw new IllegalArgumentException("not an object");
}
JSONObject jsonObject = new JSONObject();
jsonObject.map = (Map) result;
return jsonObject;
}
public String serialize() {
StringBuffer buffer = new StringBuffer();
writeValue(map, buffer);
return buffer.toString();
}
private static RuntimeException error(String message, CharacterIterator it) {
return new IllegalStateException("[" + it.getIndex() + "] " + message); //$NON-NLS-1$//$NON-NLS-2$
}
private static RuntimeException error(String message) {
return new IllegalStateException(message);
}
private static Object parse(CharacterIterator it) {
parseWhitespace(it);
Object result = parseValue(it);
parseWhitespace(it);
if (it.current() != CharacterIterator.DONE)
throw error("should be done", it); //$NON-NLS-1$
return result;
}
private static void parseWhitespace(CharacterIterator it) {
char c = it.current();
while (Character.isWhitespace(c))
c = it.next();
}
private static Object parseValue(CharacterIterator it) {
switch (it.current()) {
case '{':
return parseObject(it);
case '[':
return parseArray(it);
case '"':
return parseString(it);
case '-':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
return parseNumber(it);
case 't':
parseText(Boolean.TRUE.toString(), it);
return Boolean.TRUE;
case 'f':
parseText(Boolean.FALSE.toString(), it);
return Boolean.FALSE;
case 'n':
parseText(NULL, it);
return null;
}
throw error("Bad JSON starting character '" + it.current() + "'", it); //$NON-NLS-1$ //$NON-NLS-2$;
}
private static Map parseObject(CharacterIterator it) {
it.next();
parseWhitespace(it);
if (it.current() == '}') {
it.next();
return Collections.EMPTY_MAP;
}
Map map = new HashMap();
while (true) {
if (it.current() != '"')
throw error(
"expected a string start '\"' but was '" + it.current() + "'", it); //$NON-NLS-1$ //$NON-NLS-2$
String key = parseString(it);
if (map.containsKey(key))
throw error("' already defined" + "key '" + key, it); //$NON-NLS-1$ //$NON-NLS-2$
parseWhitespace(it);
if (it.current() != ':')
throw error(
"expected a pair separator ':' but was '" + it.current() + "'", it); //$NON-NLS-1$ //$NON-NLS-2$
it.next();
parseWhitespace(it);
Object value = parseValue(it);
map.put(key, value);
parseWhitespace(it);
if (it.current() == ',') {
it.next();
parseWhitespace(it);
continue;
}
if (it.current() != '}')
throw error(
"expected an object close '}' but was '" + it.current() + "'", it); //$NON-NLS-1$ //$NON-NLS-2$
break;
}
it.next();
return map;
}
private static List parseArray(CharacterIterator it) {
it.next();
parseWhitespace(it);
if (it.current() == ']') {
it.next();
return Collections.EMPTY_LIST;
}
List list = new ArrayList();
while (true) {
Object value = parseValue(it);
list.add(value);
parseWhitespace(it);
if (it.current() == ',') {
it.next();
parseWhitespace(it);
continue;
}
if (it.current() != ']')
throw error(
"expected an array close ']' but was '" + it.current() + "'", it); //$NON-NLS-1$ //$NON-NLS-2$
break;
}
it.next();
return list;
}
private static void parseText(String string, CharacterIterator it) {
int length = string.length();
char c = it.current();
for (int i = 0; i < length; i++) {
if (c != string.charAt(i))
throw error(
"expected to parse '" + string + "' but character " + (i + 1) + " was '" + c + "'", it); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$;
c = it.next();
}
}
private static Object parseNumber(CharacterIterator it) {
StringBuffer buffer = new StringBuffer();
char c = it.current();
while (Character.isDigit(c) || c == '-' || c == '+' || c == '.' || c == 'e'
|| c == 'E') {
buffer.append(c);
c = it.next();
}
try {
return new BigDecimal(buffer.toString());
} catch (NumberFormatException e) {
throw error("expected a number but was '" + buffer.toString() + "'", it); //$NON-NLS-1$ //$NON-NLS-2$;
}
}
private static String parseString(CharacterIterator it) {
char c = it.next();
if (c == '"') {
it.next();
return EMPTY_STRING;
}
StringBuffer buffer = new StringBuffer();
while (c != '"') {
if (Character.isISOControl(c))
throw error(
"illegal iso control character: '" + Integer.toHexString(c) + "'", it); //$NON-NLS-1$ //$NON-NLS-2$);
if (c == '\\') {
c = it.next();
switch (c) {
case '"':
case '\\':
case '/':
buffer.append(c);
break;
case 'b':
buffer.append('\b');
break;
case 'f':
buffer.append('\f');
break;
case 'n':
buffer.append('\n');
break;
case 'r':
buffer.append('\r');
break;
case 't':
buffer.append('\t');
break;
case 'u':
StringBuffer unicode = new StringBuffer(4);
for (int i = 0; i < 4; i++) {
unicode.append(it.next());
}
try {
buffer.append((char) Integer.parseInt(unicode.toString(), 16));
} catch (NumberFormatException e) {
throw error(
"expected a unicode hex number but was '" + unicode.toString() + "'", it); //$NON-NLS-1$ //$NON-NLS-2$););
}
break;
default:
throw error("illegal escape character '" + c + "'", it); //$NON-NLS-1$ //$NON-NLS-2$););
}
} else
buffer.append(c);
c = it.next();
}
c = it.next();
return buffer.toString();
}
private static void writeValue(Object value, StringBuffer buffer) {
if (value == null)
buffer.append(NULL);
else if (value instanceof Boolean || value instanceof Number)
buffer.append(value.toString());
else if (value instanceof String)
writeString((String) value, buffer);
else if (value instanceof Collection)
writeArray((Collection) value, buffer);
else if (value instanceof Map)
writeObject((Map) value, buffer);
else
throw error("Unexpected object instance type was '" + value.getClass().getName() + "'"); //$NON-NLS-1$ //$NON-NLS-2$););
}
private static void writeObject(Map map, StringBuffer buffer) {
buffer.append('{');
for (Iterator iterator = map.keySet().iterator(); iterator.hasNext();) {
Object key = iterator.next();
if (!(key instanceof String))
throw error("Map keys must be an instance of String but was '" + key.getClass().getName() + "'"); //$NON-NLS-1$ //$NON-NLS-2$););
writeString((String) key, buffer);
buffer.append(':');
writeValue(map.get(key), buffer);
buffer.append(',');
}
if (buffer.charAt(buffer.length() - 1) == ',')
buffer.setCharAt(buffer.length() - 1, '}');
else
buffer.append('}');
}
private static void writeArray(Collection collection, StringBuffer buffer) {
buffer.append('[');
for (Iterator iterator = collection.iterator(); iterator.hasNext();) {
writeValue(iterator.next(), buffer);
buffer.append(',');
}
if (buffer.charAt(buffer.length() - 1) == ',')
buffer.setCharAt(buffer.length() - 1, ']');
else
buffer.append(']');
}
private static void writeString(String string, StringBuffer buffer) {
buffer.append('"');
int length = string.length();
for (int i = 0; i < length; i++) {
char c = string.charAt(i);
switch (c) {
case '"':
case '\\':
case '/':
buffer.append('\\');
buffer.append(c);
break;
case '\b':
buffer.append("\\b"); //$NON-NLS-1$
break;
case '\f':
buffer.append("\\f"); //$NON-NLS-1$
break;
case '\n':
buffer.append("\\n"); //$NON-NLS-1$
break;
case '\r':
buffer.append("\\r"); //$NON-NLS-1$
break;
case '\t':
buffer.append("\\t"); //$NON-NLS-1$
break;
default:
if (Character.isISOControl(c)) {
buffer.append("\\u"); //$NON-NLS-1$
String hexString = Integer.toHexString(c);
for (int j = hexString.length(); j < 4; j++)
buffer.append('0');
buffer.append(hexString);
} else
buffer.append(c);
}
}
buffer.append('"');
}
}