package peergos.shared.io.ipfs.api;
import java.util.*;
import java.lang.reflect.*;
public class JSONParser
{
private static char skipSpaces(String json, int[] pos)
{
while (true)
{
if (pos[0] >= json.length())
return 0;
char ch = json.charAt(pos[0]);
if (Character.isWhitespace(ch))
pos[0]++;
else
return ch;
}
}
private static Boolean parseBoolean(String json, int[] pos)
{
if (json.regionMatches(pos[0], "true", 0, 4))
{
pos[0] += 4;
return Boolean.TRUE;
}
if (json.regionMatches(pos[0], "false", 0, 5))
{
pos[0] += 5;
return Boolean.FALSE;
}
return null;
}
private static Number parseNumber(String json, int[] pos)
{
int endPos = json.length();
int startPos = pos[0];
boolean foundExp = false;
boolean foundDot = false;
boolean allowPM = true;
for (int i=startPos; i<endPos; i++)
{
char ch = json.charAt(i);
if ((ch == 'e') || (ch == 'E'))
{
if (foundExp)
return null;
allowPM = true;
foundExp = true;
continue;
}
if ((ch == '+') || (ch == '-'))
{
if (allowPM)
{
allowPM = false;
ch = skipSpaces(json, pos);
if (ch == 0)
return null;
else
continue;
}
else
return null;
}
allowPM = false;
if (ch == '.')
{
if (foundDot)
return null;
foundDot = true;
continue;
}
if (!Character.isDigit(json.charAt(i)))
{
pos[0] = endPos = i;
break;
}
}
if (startPos == endPos)
return null;
String numericString = json.substring(startPos, endPos);
try
{
return Integer.parseInt(numericString);
}
catch (Exception e) {}
try
{
return Long.parseLong(numericString);
}
catch (Exception e) {}
try
{
return Double.parseDouble(numericString);
}
catch (Exception e) {}
throw new IllegalStateException("Failed to parse JSON number at "+startPos+" '"+numericString+"'");
}
private static List parseArray(String json, int[] pos)
{
int start = pos[0];
if (json.charAt(start) != '[')
return null;
pos[0]++;
ArrayList result = new ArrayList();
while (true)
{
char ch = skipSpaces(json, pos);
if (ch == 0)
break;
else if (ch == ']')
{
pos[0]++;
return result;
}
else if (ch == ',')
{
pos[0]++;
if (skipSpaces(json, pos) == 0)
break;
}
Object val = parse(json, pos);
result.add(val);
}
throw new IllegalStateException("json Array format at "+start+" ["+(pos[0]-start)+"] '"+json.substring(start)+"'");
}
private static Map parseObject(String json, int[] pos)
{
int start = pos[0];
if (json.charAt(start) != '{')
return null;
pos[0]++;
Map result = new LinkedHashMap();
while (true)
{
char ch = skipSpaces(json, pos);
if (ch == 0)
break;
else if (ch == '}')
{
pos[0]++;
return result;
}
else if (ch == ',')
{
pos[0]++;
if (skipSpaces(json, pos) == 0)
break;
}
String key = parseString(json, pos);
ch = skipSpaces(json, pos);
if (ch == 0)
break;
pos[0]++;
if (ch != ':')
break;
Object val = parse(json, pos);
result.put(key, val);
}
throw new IllegalStateException("json Object format at "+pos[0]+" ["+start+", "+json.length()+"] '"+json.substring(pos[0])+"'");
}
private static String parseString(String json, int[] pos)
{
int startPos = pos[0];
if (json.charAt(startPos) != '"')
return null;
pos[0]++;
boolean isEscape = false;
for (int i=startPos+1; i<json.length(); i++)
{
char ch = json.charAt(i);
if (ch == '\\')
{
isEscape = !isEscape;
continue;
}
if (ch == '"')
{
if (!isEscape)
{
pos[0] = i+1;
return json.substring(startPos+1, i);
}
}
isEscape = false;
}
throw new IllegalStateException("json string at at "+startPos+" '"+json+"'");
}
private static Object parse(String json, int[] pos)
{
char ch = skipSpaces(json, pos);
if (ch == 0)
return null;
int startPos = pos[0];
if (startPos == json.length())
return null;
Object result = parseArray(json, pos);
if (result != null)
return result;
result = parseObject(json, pos);
if (result != null)
return result;
result = parseBoolean(json, pos);
if (result != null)
return result;
result = parseString(json, pos);
if (result != null)
return result;
result = parseNumber(json, pos);
if (result != null)
return result;
if (json.regionMatches(pos[0], "null", 0, 4))
{
pos[0] += 4;
return null;
}
throw new IllegalStateException("json object at at "+startPos+" '"+json+"'");
}
public static Object parse(Object json)
{
if (json == null)
return null;
return parse(json.toString());
}
public static Object parse(String json)
{
if (json == null)
return null;
return parse(json, new int[1]);
}
public static List<Object> parseStream(String json)
{
if (json == null)
return null;
int[] pos = new int[1];
List<Object> res = new ArrayList<>();
json = json.trim();
while (pos[0] < json.length())
res.add(parse(json, pos));
return res;
}
private static void escapeString(String s, StringBuffer buf)
{
buf.append('"');
for (int i=0; i<s.length(); i++)
{
char ch = s.charAt(i);
if ((ch == '"') || (ch == '\\'))
buf.append('\\');
buf.append(ch);
}
buf.append('"');
}
private static void toString(Object obj, StringBuffer buf)
{
if (obj == null)
buf.append("null");
else if ((obj instanceof Boolean) || (obj instanceof Number))
buf.append(obj.toString());
else if (obj instanceof Map)
{
Map m = (Map) obj;
boolean first = true;
Iterator itt = m.keySet().iterator();
buf.append('{');
while (itt.hasNext())
{
if (!first)
buf.append(',');
String s = (String) itt.next();
Object val = m.get(s);
escapeString(s, buf);
buf.append(":");
toString(val, buf);
first = false;
}
buf.append('}');
}
else if (obj instanceof Object[])
{
Object[] l = (Object[]) obj;
boolean first = true;
buf.append('[');
for (int i=0; i<l.length; i++)
{
if (!first)
buf.append(',');
toString(l[i], buf);
first = false;
}
buf.append(']');
}
else if (obj instanceof List)
{
List l = (List) obj;
boolean first = true;
Iterator itt = l.iterator();
buf.append('[');
while (itt.hasNext())
{
if (!first)
buf.append(',');
Object val = itt.next();
toString(val, buf);
first = false;
}
buf.append(']');
}
else if (obj instanceof String)
escapeString(obj.toString(), buf);
else
{
/* todo-fix
try
{
Class cls = obj.getClass();
Method m = cls.getDeclaredMethod("toJSON", new Class[0]);
Object jsonObj = m.invoke(obj, new Object[0]);
buf.append(toString(jsonObj));
}
catch (Exception e)
{
escapeString(obj.toString(), buf);
}*/
}
}
public static String toString(Object obj)
{
StringBuffer buf = new StringBuffer();
toString(obj, buf);
return buf.toString();
}
public static String stripWhitespace(String src)
{
boolean inQuote = false, isEscaped = false;
StringBuffer buf = new StringBuffer();
for (int i=0; i<src.length(); i++)
{
char ch = src.charAt(i);
if (!inQuote)
{
if (ch == '"')
{
inQuote = true;
isEscaped = false;
}
else if (Character.isWhitespace(ch))
continue;
}
else if (inQuote)
{
if (ch == '\\')
isEscaped = !isEscaped;
else if ((ch == '"') && !isEscaped)
inQuote = false;
}
buf.append(ch);
}
return buf.toString();
}
public static Object getValue(Object json, String path)
{
String[] parts = path.split("\\.");
for (int i=0; i<parts.length; i++)
{
int index = -1;
String key = parts[i];
if (key.endsWith("]"))
{
int b = key.indexOf("[");
try
{
index = Integer.parseInt(key.substring(b+1, key.length()-1));
key = key.substring(0, b);
}
catch (Exception e)
{
throw new IllegalStateException("Path syntax error - invalid index");
}
}
if ((json != null) && (json instanceof Map))
json = ((Map) json).get(key);
else
return null;
if (index >= 0)
{
if ((json != null) && (json instanceof List))
json = ((List) json).get(index);
else
return null;
}
}
return json;
}
}