blob: ee6e46b61c8ae0c400788722d4ac62ab04a4560a [file] [log] [blame]
// Do not edit this file! Generated by Ragel.
// Ragel.exe -G2 -J -o JsonReader.java JsonReader.rl
/*******************************************************************************
* Copyright 2011 See AUTHORS file.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package com.badlogic.gdx.utils;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.utils.JsonValue.ValueType;
/** Lightweight JSON parser.<br>
* <br>
* The default behavior is to parse the JSON into a DOM containing {@link JsonValue} objects. Extend this class and override
* methods to perform event driven parsing. When this is done, the parse methods will return null.
* @author Nathan Sweet */
public class JsonReader implements BaseJsonReader {
public JsonValue parse (String json) {
char[] data = json.toCharArray();
return parse(data, 0, data.length);
}
public JsonValue parse (Reader reader) {
try {
char[] data = new char[1024];
int offset = 0;
while (true) {
int length = reader.read(data, offset, data.length - offset);
if (length == -1) break;
if (length == 0) {
char[] newData = new char[data.length * 2];
System.arraycopy(data, 0, newData, 0, data.length);
data = newData;
} else
offset += length;
}
return parse(data, 0, offset);
} catch (IOException ex) {
throw new SerializationException(ex);
} finally {
StreamUtils.closeQuietly(reader);
}
}
public JsonValue parse (InputStream input) {
try {
return parse(new InputStreamReader(input, "UTF-8"));
} catch (IOException ex) {
throw new SerializationException(ex);
} finally {
StreamUtils.closeQuietly(input);
}
}
public JsonValue parse (FileHandle file) {
try {
return parse(file.reader("UTF-8"));
} catch (Exception ex) {
throw new SerializationException("Error parsing file: " + file, ex);
}
}
public JsonValue parse (char[] data, int offset, int length) {
int cs, p = offset, pe = length, eof = pe, top = 0;
int[] stack = new int[4];
int s = 0;
Array<String> names = new Array(8);
boolean needsUnescape = false, stringIsName = false, stringIsUnquoted = false;
RuntimeException parseRuntimeEx = null;
boolean debug = false;
if (debug) System.out.println();
try {
%%{
machine json;
prepush {
if (top == stack.length) {
int[] newStack = new int[stack.length * 2];
System.arraycopy(stack, 0, newStack, 0, stack.length);
stack = newStack;
}
}
action name {
stringIsName = true;
}
action string {
String value = new String(data, s, p - s);
if (needsUnescape) value = unescape(value);
outer:
if (stringIsName) {
stringIsName = false;
if (debug) System.out.println("name: " + value);
names.add(value);
} else {
String name = names.size > 0 ? names.pop() : null;
if (stringIsUnquoted) {
if (value.equals("true")) {
if (debug) System.out.println("boolean: " + name + "=true");
bool(name, true);
break outer;
} else if (value.equals("false")) {
if (debug) System.out.println("boolean: " + name + "=false");
bool(name, false);
break outer;
} else if (value.equals("null")) {
string(name, null);
break outer;
}
boolean couldBeDouble = false, couldBeLong = true;
outer2:
for (int i = s; i < p; i++) {
switch (data[i]) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '-':
case '+':
break;
case '.':
case 'e':
case 'E':
couldBeDouble = true;
couldBeLong = false;
break;
default:
couldBeDouble = false;
couldBeLong = false;
break outer2;
}
}
if (couldBeDouble) {
try {
if (debug) System.out.println("double: " + name + "=" + Double.parseDouble(value));
number(name, Double.parseDouble(value), value);
break outer;
} catch (NumberFormatException ignored) {
}
} else if (couldBeLong) {
if (debug) System.out.println("double: " + name + "=" + Double.parseDouble(value));
try {
number(name, Long.parseLong(value), value);
break outer;
} catch (NumberFormatException ignored) {
}
}
}
if (debug) System.out.println("string: " + name + "=" + value);
string(name, value);
}
stringIsUnquoted = false;
s = p;
}
action startObject {
String name = names.size > 0 ? names.pop() : null;
if (debug) System.out.println("startObject: " + name);
startObject(name);
fcall object;
}
action endObject {
if (debug) System.out.println("endObject");
pop();
fret;
}
action startArray {
String name = names.size > 0 ? names.pop() : null;
if (debug) System.out.println("startArray: " + name);
startArray(name);
fcall array;
}
action endArray {
if (debug) System.out.println("endArray");
pop();
fret;
}
action comment {
int start = p - 1;
if (data[p++] == '/') {
while (p != eof && data[p] != '\n')
p++;
p--;
} else {
while (p + 1 < eof && data[p] != '*' || data[p + 1] != '/')
p++;
p++;
}
if (debug) System.out.println("comment " + new String(data, start, p - start));
}
action unquotedChars {
if (debug) System.out.println("unquotedChars");
s = p;
needsUnescape = false;
stringIsUnquoted = true;
if (stringIsName) {
outer:
while (true) {
switch (data[p]) {
case '\\':
needsUnescape = true;
break;
case '/':
if (p + 1 == eof) break;
char c = data[p + 1];
if (c == '/' || c == '*') break outer;
break;
case ':':
case '\r':
case '\n':
break outer;
}
if (debug) System.out.println("unquotedChar (name): '" + data[p] + "'");
p++;
if (p == eof) break;
}
} else {
outer:
while (true) {
switch (data[p]) {
case '\\':
needsUnescape = true;
break;
case '/':
if (p + 1 == eof) break;
char c = data[p + 1];
if (c == '/' || c == '*') break outer;
break;
case '}':
case ']':
case ',':
case '\r':
case '\n':
break outer;
}
if (debug) System.out.println("unquotedChar (value): '" + data[p] + "'");
p++;
if (p == eof) break;
}
}
p--;
while (Character.isSpace(data[p]))
p--;
}
action quotedChars {
if (debug) System.out.println("quotedChars");
s = ++p;
needsUnescape = false;
outer:
while (true) {
switch (data[p]) {
case '\\':
needsUnescape = true;
p++;
break;
case '"':
break outer;
}
// if (debug) System.out.println("quotedChar: '" + data[p] + "'");
p++;
if (p == eof) break;
}
p--;
}
comment = ('//' | '/*') @comment;
ws = [\r\n\t ] | comment;
ws2 = [\r\t ] | comment;
comma = ',' | ('\n' ws* ','?);
quotedString = '"' @quotedChars %string '"';
nameString = quotedString | ^[":,}/\r\n\t ] >unquotedChars %string;
valueString = quotedString | ^[":,{[\]/\r\n\t ] >unquotedChars %string;
value = '{' @startObject | '[' @startArray | valueString;
nameValue = nameString >name ws* ':' ws* value;
object := ws* nameValue? ws2* <: (comma ws* nameValue ws2*)** :>> (','? ws* '}' @endObject);
array := ws* value? ws2* <: (comma ws* value ws2*)** :>> (','? ws* ']' @endArray);
main := ws* value ws*;
write init;
write exec;
}%%
} catch (RuntimeException ex) {
parseRuntimeEx = ex;
}
JsonValue root = this.root;
this.root = null;
current = null;
lastChild.clear();
if (p < pe) {
int lineNumber = 1;
for (int i = 0; i < p; i++)
if (data[i] == '\n') lineNumber++;
int start = Math.max(0, p - 32);
throw new SerializationException("Error parsing JSON on line " + lineNumber + " near: "
+ new String(data, start, p - start) + "*ERROR*" + new String(data, p, Math.min(64, pe - p)), parseRuntimeEx);
} else if (elements.size != 0) {
JsonValue element = elements.peek();
elements.clear();
if (element != null && element.isObject())
throw new SerializationException("Error parsing JSON, unmatched brace.");
else
throw new SerializationException("Error parsing JSON, unmatched bracket.");
} else if (parseRuntimeEx != null) {
throw new SerializationException("Error parsing JSON: " + new String(data), parseRuntimeEx);
}
return root;
}
%% write data;
private final Array<JsonValue> elements = new Array(8);
private final Array<JsonValue> lastChild = new Array(8);
private JsonValue root, current;
private void addChild (String name, JsonValue child) {
child.setName(name);
if (current == null) {
current = child;
root = child;
} else if (current.isArray() || current.isObject()) {
child.parent = current;
if (current.size == 0)
current.child = child;
else {
JsonValue last = lastChild.pop();
last.next = child;
child.prev = last;
}
lastChild.add(child);
current.size++;
} else
root = current;
}
protected void startObject (String name) {
JsonValue value = new JsonValue(ValueType.object);
if (current != null) addChild(name, value);
elements.add(value);
current = value;
}
protected void startArray (String name) {
JsonValue value = new JsonValue(ValueType.array);
if (current != null) addChild(name, value);
elements.add(value);
current = value;
}
protected void pop () {
root = elements.pop();
if (current.size > 0) lastChild.pop();
current = elements.size > 0 ? elements.peek() : null;
}
protected void string (String name, String value) {
addChild(name, new JsonValue(value));
}
protected void number (String name, double value, String stringValue) {
addChild(name, new JsonValue(value, stringValue));
}
protected void number (String name, long value, String stringValue) {
addChild(name, new JsonValue(value, stringValue));
}
protected void bool (String name, boolean value) {
addChild(name, new JsonValue(value));
}
private String unescape (String value) {
int length = value.length();
StringBuilder buffer = new StringBuilder(length + 16);
for (int i = 0; i < length;) {
char c = value.charAt(i++);
if (c != '\\') {
buffer.append(c);
continue;
}
if (i == length) break;
c = value.charAt(i++);
if (c == 'u') {
buffer.append(Character.toChars(Integer.parseInt(value.substring(i, i + 4), 16)));
i += 4;
continue;
}
switch (c) {
case '"':
case '\\':
case '/':
break;
case 'b':
c = '\b';
break;
case 'f':
c = '\f';
break;
case 'n':
c = '\n';
break;
case 'r':
c = '\r';
break;
case 't':
c = '\t';
break;
default:
throw new SerializationException("Illegal escaped character: \\" + c);
}
buffer.append(c);
}
return buffer.toString();
}
}