diff options
Diffstat (limited to 'plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/JSON.java')
-rw-r--r-- | plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/JSON.java | 516 |
1 files changed, 516 insertions, 0 deletions
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/JSON.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/JSON.java new file mode 100644 index 000000000..16fdcb5e8 --- /dev/null +++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/JSON.java @@ -0,0 +1,516 @@ +/******************************************************************************* + * Copyright (c) 2007 Wind River Systems, Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package com.windriver.tcf.api.protocol; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.StringReader; +import java.io.UnsupportedEncodingException; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import com.windriver.tcf.api.internal.core.ReadOnlyCollection; +import com.windriver.tcf.api.internal.core.ReadOnlyMap; + +/** + * JSON is TCF preferred marshaling. This class implements generation and parsing of JSON strings. + * The code is optimized for speed since it is a time-critical part of the framework. + */ +public class JSON { + + private static char[] tmp_buf = new char[0x1000]; + private static byte[] tmp_bbf = new byte[0x1000]; + private static int tmp_buf_pos; + + private static Reader reader; + private static final char[] cur_buf = new char[0x1000]; + private static int cur_buf_pos; + private static int cur_buf_len; + private static int cur_ch; + + // This buffer is used to create nice error reports + private static final char[] err_buf = new char[100]; + private static int err_buf_pos; + private static int err_buf_cnt; + + private static void write(char ch) { + if (tmp_buf_pos >= tmp_buf.length) { + char[] tmp = new char[tmp_buf.length * 2]; + System.arraycopy(tmp_buf, 0, tmp, 0, tmp_buf_pos); + tmp_buf = tmp; + } + tmp_buf[tmp_buf_pos++] = ch; + } + + private static void write(String s) { + int l = s.length(); + for (int i = 0; i < l; i++) { + char ch = s.charAt(i); + if (tmp_buf_pos >= tmp_buf.length) write(ch); + else tmp_buf[tmp_buf_pos++] = ch; + } + } + + private static void writeUInt(int n) { + assert n >= 0; + if (n >= 10) writeUInt(n / 10); + write((char)('0' + n % 10)); + } + + private static void read() throws IOException { + if (cur_buf_pos >= cur_buf_len) { + cur_buf_len = reader.read(cur_buf); + cur_buf_pos = 0; + if (cur_buf_len < 0) { + cur_buf_len = 0; + cur_ch = -1; + return; + } + } + cur_ch = cur_buf[cur_buf_pos++]; + err_buf[err_buf_pos++] = (char)cur_ch; + if (err_buf_pos >= err_buf.length) { + err_buf_pos = 0; + err_buf_cnt++; + } + } + + private static void error() throws IOException { + error("syntax error"); + } + + private static void error(String msg) throws IOException { + StringBuffer bf = new StringBuffer(); + bf.append("JSON " + msg + ":"); + int cnt = 0; + boolean nl = true; + for (int i = 0;; i++) { + char ch = 0; + if (err_buf_cnt == 0 && i < err_buf_pos) { + ch = err_buf[i]; + } + else if (err_buf_cnt > 0 && i < err_buf.length) { + ch = err_buf[(err_buf_pos + i) % err_buf.length]; + } + else { + int n = reader.read(); + if (n < 0) break; + ch = (char)n; + } + if (nl) { + bf.append("\n "); + if (err_buf_cnt == 0) bf.append(cnt); + else bf.append('*'); + bf.append(": "); + if (cnt == 0 && err_buf_cnt > 0) bf.append("..."); + nl = false; + } + if (ch == 0) { + cnt++; + nl = true; + continue; + } + bf.append(ch); + } + throw new IOException(bf.toString()); + } + + private static int readHexDigit() throws IOException { + int n = 0; + if (cur_ch >= '0' && cur_ch <= '9') n = cur_ch - '0'; + else if (cur_ch >= 'A' && cur_ch <= 'F') n = cur_ch - 'A' + 10; + else if (cur_ch >= 'a' && cur_ch <= 'f') n = cur_ch - 'a' + 10; + else error(); + read(); + return n; + } + + private static Object readNestedObject() throws IOException { + switch (cur_ch) { + case '"': + read(); + tmp_buf_pos = 0; + for (;;) { + if (cur_ch <= 0) error(); + if (cur_ch == '"') break; + if (cur_ch == '\\') { + read(); + if (cur_ch <= 0) error(); + switch (cur_ch) { + case '"': + case '\\': + case '/': + break; + case 'b': + cur_ch = '\b'; + break; + case 'f': + cur_ch = '\f'; + break; + case 'n': + cur_ch = '\n'; + break; + case 'r': + cur_ch = '\r'; + break; + case 't': + cur_ch = '\t'; + break; + case 'u': + read(); + int n = 0; + n |= readHexDigit() << 12; + n |= readHexDigit() << 8; + n |= readHexDigit() << 4; + n |= readHexDigit(); + write((char)n); + continue; + default: + error(); + break; + } + } + if (tmp_buf_pos >= tmp_buf.length) { + write((char)cur_ch); + } + else { + tmp_buf[tmp_buf_pos++] = (char)cur_ch; + } + if (cur_buf_pos >= cur_buf_len) { + read(); + } + else { + cur_ch = cur_buf[cur_buf_pos++]; + err_buf[err_buf_pos++] = (char)cur_ch; + if (err_buf_pos >= err_buf.length) { + err_buf_pos = 0; + err_buf_cnt++; + } + } + } + read(); + return new String(tmp_buf, 0, tmp_buf_pos); + case '[': + Collection<Object> l = new ArrayList<Object>(); + read(); + if (cur_ch <= 0) error(); + if (cur_ch != ']') { + for (;;) { + l.add(readNestedObject()); + if (cur_ch == ']') break; + if (cur_ch != ',') error(); + read(); + } + } + read(); + return new ReadOnlyCollection<Object>(l); + case '{': + Map<String,Object> m = new HashMap<String,Object>(); + read(); + if (cur_ch <= 0) error(); + if (cur_ch != '}') { + for (;;) { + String key = (String)readNestedObject(); + if (cur_ch != ':') error(); + read(); + Object val = readNestedObject(); + m.put(key, val); + if (cur_ch == '}') break; + if (cur_ch != ',') error(); + read(); + } + } + read(); + return new ReadOnlyMap<String,Object>(m); + case 'n': + read(); + if (cur_ch != 'u') error(); + read(); + if (cur_ch != 'l') error(); + read(); + if (cur_ch != 'l') error(); + read(); + return null; + case 'f': + read(); + if (cur_ch != 'a') error(); + read(); + if (cur_ch != 'l') error(); + read(); + if (cur_ch != 's') error(); + read(); + if (cur_ch != 'e') error(); + read(); + return Boolean.FALSE; + case 't': + read(); + if (cur_ch != 'r') error(); + read(); + if (cur_ch != 'u') error(); + read(); + if (cur_ch != 'e') error(); + read(); + return Boolean.TRUE; + default: + boolean neg = cur_ch == '-'; + if (neg) read(); + if (cur_ch >= '0' && cur_ch <= '9') { + // TODO: float number + int v = 0; + while (v <= 0x7fffffff / 10 - 1) { + v = v * 10 + (cur_ch - '0'); + read(); + if (cur_ch < '0' || cur_ch > '9') { + return new Integer(neg ? -v : v); + } + } + long vl = v; + while (vl < 0x7fffffffffffffffl / 10 - 1) { + vl = vl * 10 + (cur_ch - '0'); + read(); + if (cur_ch < '0' || cur_ch > '9') { + return new Long(neg ? -vl : vl); + } + } + StringBuffer sb = new StringBuffer(); + if (neg) sb.append('-'); + sb.append(vl); + while (true) { + sb.append(cur_ch); + read(); + if (cur_ch < '0' || cur_ch > '9') { + return new BigInteger(sb.toString()); + } + } + } + error(); + return null; + } + } + + private static Object readObject() throws IOException { + Object o = readNestedObject(); + if (cur_ch >= 0) error(); + return o; + } + + private static Object[] readSequence() throws IOException { + List<Object> l = new ArrayList<Object>(); + while (cur_ch >= 0) { + l.add(readNestedObject()); + if (cur_ch != 0) error("missing \\0 terminator"); + read(); + } + return l.toArray(); + } + + @SuppressWarnings("unchecked") + private static void writeObject(Object o) throws IOException { + if (o == null) { + write("null"); + } + else if (o instanceof Boolean) { + write(o.toString()); + } + else if (o instanceof Number) { + write(o.toString()); + } + else if (o instanceof String) { + String s = (String)o; + char[] arr = new char[s.length()]; + s.getChars(0, arr.length, arr, 0); + writeObject(arr); + } + else if (o instanceof char[]) { + char[] s = (char[])o; + write('"'); + int l = s.length; + for (int i = 0; i < l; i++) { + char ch = s[i]; + switch (ch) { + case 0: + write("\\u0000"); + break; + case '\r': + write("\\r"); + break; + case '\n': + write("\\n"); + break; + case '\t': + write("\\t"); + break; + case '\b': + write("\\b"); + break; + case '\f': + write("\\f"); + break; + case '"': + case '\\': + write('\\'); + default: + if (tmp_buf_pos >= tmp_buf.length) write(ch); + else tmp_buf[tmp_buf_pos++] = ch; + } + } + write('"'); + } + else if (o instanceof byte[]) { + write('['); + byte[] arr = (byte[])o; + boolean comma = false; + for (int i = 0; i < arr.length; i++) { + if (comma) write(','); + writeUInt(arr[i] & 0xff); + comma = true; + } + write(']'); + } + else if (o instanceof Object[]) { + write('['); + Object[] arr = (Object[])o; + boolean comma = false; + for (int i = 0; i < arr.length; i++) { + if (comma) write(','); + writeObject(arr[i]); + comma = true; + } + write(']'); + } + else if (o instanceof Collection) { + write('['); + boolean comma = false; + for (Iterator<Object> i = ((Collection<Object>)o).iterator(); i.hasNext();) { + if (comma) write(','); + writeObject(i.next()); + comma = true; + } + write(']'); + } + else if (o instanceof Map) { + Map<String,Object> map = (Map<String,Object>)o; + write('{'); + boolean comma = false; + for (Iterator<Map.Entry<String,Object>> i = map.entrySet().iterator(); i.hasNext();) { + if (comma) write(','); + Map.Entry<String,Object> e = i.next(); + writeObject(e.getKey()); + write(':'); + writeObject(e.getValue()); + comma = true; + } + write('}'); + } + else { + throw new IOException("JSON: unsupported object type"); + } + } + + private static byte[] toBytes() throws UnsupportedEncodingException { + int inp_pos = 0; + int out_pos = 0; + while (inp_pos < tmp_buf_pos) { + if (out_pos >= tmp_bbf.length - 4) { + byte[] tmp = new byte[tmp_bbf.length * 2]; + System.arraycopy(tmp_bbf, 0, tmp, 0, out_pos); + tmp_bbf = tmp; + } + int ch = tmp_buf[inp_pos++]; + if (ch < 0x80) { + tmp_bbf[out_pos++] = (byte)ch; + } + else if (ch < 0x800) { + tmp_bbf[out_pos++] = (byte)((ch >> 6) | 0xc0); + tmp_bbf[out_pos++] = (byte)(ch & 0x3f | 0x80); + } + else if (ch < 0x10000) { + tmp_bbf[out_pos++] = (byte)((ch >> 12) | 0xe0); + tmp_bbf[out_pos++] = (byte)((ch >> 6) & 0x3f | 0x80); + tmp_bbf[out_pos++] = (byte)(ch & 0x3f | 0x80); + } + else { + tmp_bbf[out_pos++] = (byte)((ch >> 18) | 0xf0); + tmp_bbf[out_pos++] = (byte)((ch >> 12) & 0x3f | 0x80); + tmp_bbf[out_pos++] = (byte)((ch >> 6) & 0x3f | 0x80); + tmp_bbf[out_pos++] = (byte)(ch & 0x3f | 0x80); + } + } + byte[] res = new byte[out_pos]; + System.arraycopy(tmp_bbf, 0, res, 0, out_pos); + return res; + } + + public static String toJSON(Object o) throws IOException { + assert Protocol.isDispatchThread(); + tmp_buf_pos = 0; + writeObject(o); + return new String(tmp_buf, 0, tmp_buf_pos); + } + + public static byte[] toJASONBytes(Object o) throws IOException { + assert Protocol.isDispatchThread(); + tmp_buf_pos = 0; + writeObject(o); + return toBytes(); + } + + public static byte[] toJSONSequence(Object[] o) throws IOException { + assert Protocol.isDispatchThread(); + if (o == null || o.length == 0) return null; + tmp_buf_pos = 0; + for (int i = 0; i < o.length; i++) { + writeObject(o[i]); + write((char)0); + } + return toBytes(); + } + + public static Object parseOne(String s) throws IOException { + assert Protocol.isDispatchThread(); + reader = new StringReader(s); + err_buf_pos = 0; + err_buf_cnt = 0; + cur_buf_pos = 0; + cur_buf_len = 0; + read(); + return readObject(); + } + + public static Object parseOne(byte[] b) throws IOException { + assert Protocol.isDispatchThread(); + reader = new InputStreamReader(new ByteArrayInputStream(b), "UTF8"); + err_buf_pos = 0; + err_buf_cnt = 0; + cur_buf_pos = 0; + cur_buf_len = 0; + read(); + return readObject(); + } + + public static Object[] parseSequence(byte[] b) throws IOException { + assert Protocol.isDispatchThread(); + reader = new InputStreamReader(new ByteArrayInputStream(b), "UTF8"); + err_buf_pos = 0; + err_buf_cnt = 0; + cur_buf_pos = 0; + cur_buf_len = 0; + read(); + return readSequence(); + } +} |