diff options
-rw-r--r-- | bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/JSONObject.java | 386 |
1 files changed, 386 insertions, 0 deletions
diff --git a/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/JSONObject.java b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/JSONObject.java new file mode 100644 index 000000000..3ac36215e --- /dev/null +++ b/bundles/org.eclipse.e4.core.services/src/org/eclipse/e4/core/services/JSONObject.java @@ -0,0 +1,386 @@ +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('"'); + } + +} |