package com.boombuler.piraten.utils; import java.util.ArrayList; import java.util.HashMap; import java.util.List; public class JsonParser { public class ParseException extends Exception { } private String mInput; private int mPos; private JsonParser(String input) { mInput = input; mPos = 0; } private String readString() throws ParseException{ char cur = next(true); if (cur != '"') throw new ParseException(); StringBuilder result = new StringBuilder(); boolean inEscape = false; while (!EOF()) { cur = next(false); if (inEscape) { if (cur == '"') result.append('"'); else if (cur == '\\') result.append('\\'); else if (cur == '/') result.append('/'); else if (cur == 'b') result.append('\b'); else if (cur == 'f') result.append('\f'); else if (cur == 'n') result.append('\n'); else if (cur == 'r') result.append('\r'); else if (cur == 't') result.append('\t'); else if (cur == 'u') result.append((char) Integer.parseInt(String.valueOf(next(false) + next(false) + next(false) + next(false)), 16)); else throw new ParseException(); inEscape = false; } else { if (cur == '\\') { inEscape = true; continue; } if (cur == '"') return result.toString(); result.append(cur); } } throw new ParseException(); } private Object readObject() throws ParseException { char cur = next(true); if (cur != '{') throw new ParseException(); JsonObject result = new JsonObject(); if (peek(true) == '}') { next(true); return result; } while (!EOF()) { String key = readString(); char c = next(true); if (c != ':') throw new ParseException(); Object value = read(); result.put(key, value); c = next(true); if (c == ',') continue; else if (c == '}') return result; } throw new ParseException(); } private Object readArray() throws ParseException { char cur = next(true); if (cur != '[') throw new ParseException(); JsonArray result = new JsonArray(); if (peek(true) == ']') { next(true); return result; } while (!EOF()) { result.add(read()); char c = next(true); if (c == ',') continue; else if (c == ']') return result; } throw new ParseException(); } private Object readConst() throws ParseException { StringBuilder result = new StringBuilder(); char c = peek(true); while (!EOF() && Character.isLetter(c)) { next(result.length() == 0); result.append(c); c = peek(false); } String s = result.toString(); if ("null".equals(s)) return null; else if ("true".equals(s)) return Boolean.valueOf(true); else if ("false".equals(s)) return Boolean.valueOf(false); else throw new ParseException(); } private Object readNumber() throws ParseException { StringBuilder result = new StringBuilder(); char c = next(true); if (c == '-' || Character.isDigit(c)) { result.append(c); } boolean isFloat = false; boolean isExp = false; while (!EOF()) { c = peek(false); if (Character.isDigit(c)) { next(false); result.append(c); } else if (c == '.' && !isFloat && !isExp) { isFloat = true; next(false); result.append(c); } else if ((c == 'e' || c == 'E') && !isExp) { isExp = true; next(false); result.append(c); c = next(false); if (Character.isDigit(c) || c == '+' || c == '-') { result.append(c); } } else break; } if (isFloat || isExp) return Double.valueOf(result.toString()); else return Integer.valueOf(result.toString()); } private Object read() throws ParseException { char c = peek(true); if (c == '{') return readObject(); else if (c == '"') return readString(); else if (c == '[') return readArray(); else if (Character.isLetter(c)) return readConst(); else if (Character.isDigit(c) || c == '-') return readNumber(); throw new ParseException(); } private boolean EOF() { return mPos >= mInput.length(); } private char next(boolean onlyRelevant) throws ParseException{ try { char result = mInput.charAt(mPos++); if (onlyRelevant) { while (!EOF() && Character.isWhitespace(result)) result = mInput.charAt(mPos++); } return result; } catch (Exception ex) { throw new ParseException(); } } private char peek(boolean onlyRelevant) throws ParseException { int pos = mPos; try { return next(onlyRelevant); } finally { mPos = pos; } } public static Object Parse(String input) throws ParseException { return new JsonParser(input).read(); } }