/** * Reads a Hjson value from the given reader. * <p> * Characters are read in chunks and buffered internally, therefore wrapping an existing reader in * an additional <code>BufferedReader</code> does <strong>not</strong> improve reading * performance. * </p> * * @param reader the reader to read the Hjson value from * @return the Hjson value that has been read * @throws IOException if an I/O error occurs in the reader * @throws ParseException if the input is not valid Hjson */ public static JsonValue readHjson(Reader reader) throws IOException { return new HjsonParser(reader, null).parse(); }
JsonValue parse() throws IOException { // Braces for the root object are optional read(); skipWhiteSpace(); if (legacyRoot) { switch (current) { case '[': case '{': return checkTrailing(readValue()); default: try { // assume we have a root object without braces return checkTrailing(readObject(true)); } catch (Exception exception) { // test if we are dealing with a single JSON value instead (true/false/null/num/"") reset(); read(); skipWhiteSpace(); try { return checkTrailing(readValue()); } catch (Exception exception2) { } throw exception; // throw original error } } } else { return checkTrailing(readValue()); } }
private String readStringInternal(boolean allowML) throws IOException { // callees make sure that (current=='"' || current=='\'') int exitCh = current; read(); startCapture(); while (current!=exitCh) { if (current=='\\') readEscape(); else if (current<0x20) throw expected("valid string character"); else read(); } String string=endCapture(); read(); if (allowML && exitCh=='\'' && current=='\'' && string.length()==0) { // ''' indicates a multiline string read(); return readMlString(); } else return string; }
JsonValue checkTrailing(JsonValue v) throws ParseException, IOException { skipWhiteSpace(); if (!isEndOfText()) throw error("Extra characters in input: "+current); return v; }
private ParseException expected(String expected) { if (isEndOfText()) { return error("Unexpected end of input"); } return error("Expected "+expected); }
private void skipIndent(int indent) throws IOException { while (indent-->0) { if (isWhiteSpace(current) && current!='\n') read(); else break; } }
private JsonObject readObject(boolean objectWithoutBraces) throws IOException { if (!objectWithoutBraces) read(); JsonObject object=new JsonObject(); skipWhiteSpace(); while (true) { if (objectWithoutBraces) { if (isEndOfText()) break; } else { if (isEndOfText()) throw error("End of input while parsing an object (did you forget a closing '}'?)"); if (readIf('}')) break; } String name=readName(); skipWhiteSpace(); if (!readIf(':')) { throw expected("':'"); } skipWhiteSpace(); object.add(name, readValue()); skipWhiteSpace(); if (readIf(',')) skipWhiteSpace(); // , is optional } return object; }
private JsonArray readArray() throws IOException { read(); JsonArray array=new JsonArray(); skipWhiteSpace(); if (readIf(']')) { return array; } while (true) { skipWhiteSpace(); array.add(readValue()); skipWhiteSpace(); if (readIf(',')) skipWhiteSpace(); // , is optional if (readIf(']')) break; else if (isEndOfText()) throw error("End of input while parsing an array (did you forget a closing ']'?)"); } return array; }
private void skipWhiteSpace() throws IOException { while (!isEndOfText()) { while (isWhiteSpace()) read(); if (current=='#' || current=='/' && peek()=='/') { do { read(); } while (current>=0 && current!='\n'); } else if (current=='/' && peek()=='*') { read(); do { read(); } while (current>=0 && !(current=='*' && peek()=='/')); read(); read(); } else break; } }
private String readName() throws IOException { if (current=='"' || current=='\'') return readStringInternal(false); StringBuilder name=new StringBuilder(); int space=-1, start=index; while (true) { if (current==':') { if (name.length()==0) throw error("Found ':' but no key name (for an empty key name use quotes)"); else if (space>=0 && space!=name.length()) { index=start+space; throw error("Found whitespace in your key name (use quotes to include)"); } return name.toString(); } else if (isWhiteSpace(current)) { if (space<0) space=name.length(); } else if (current<' ') { throw error("Name is not closed"); } else if (JsonValue.isPunctuatorChar(current)) { throw error("Found '" + (char)current + "' where a key name was expected (check your syntax or use quotes if the key name includes {}[],: or whitespace)"); } else name.append((char)current); read(); } }
int first=current; if (JsonValue.isPunctuatorChar(first)) throw error("Found a punctuator character '" + (char)first + "' when expecting a quoteless string (check your syntax)"); value.append((char)current); for (;;) { read(); boolean isEol=current<0 || current=='\r' || current=='\n'; if (isEol || current==',' || current=='}' || current==']' || current=='#' || current=='/' && (peek()=='/' || peek()=='*') ) { switch (first) { default: if (first=='-' || first>='0' && first<='9') { JsonValue n=tryParseNumber(value, false); if (n!=null) return n;
if (isWhiteSpace(current) && current!='\n') read(); else break; if (current=='\n') { read(); skipIndent(indent); } if (current<0) throw error("Bad multiline string"); else if (current=='\'') { triple++; read(); if (triple==3) { if (sb.charAt(sb.length()-1)=='\n') sb.deleteCharAt(sb.length()-1); read(); skipIndent(indent); read();
private void readEscape() throws IOException { pauseCapture(); read(); switch(current) { case '"': char[] hexChars=new char[4]; for (int i=0; i<4; i++) { read(); if (!isHexDigit()) { throw expected("hexadecimal digit"); break; default: throw expected("valid escape sequence"); read();
if (!isDigit(first)) return null; if (first=='0' && idx<len && isDigit(value.charAt(idx))) return null; // leading zero is not allowed while (idx<len && isDigit(value.charAt(idx))) idx++; if (idx>=len || !isDigit(value.charAt(idx++))) return null; while (idx<len && isDigit(value.charAt(idx))) idx++; if (idx<len && (value.charAt(idx)=='+' || value.charAt(idx)=='-')) idx++; if (idx>=len || !isDigit(value.charAt(idx++))) return null; while (idx<len && isDigit(value.charAt(idx))) idx++; while (idx<len && isWhiteSpace(value.charAt(idx))) idx++;
HjsonParser.isWhiteSpace(left) || HjsonParser.isWhiteSpace(right) || left=='"' || left=='\'' || left=='/' && (left1=='*' || left1=='/') || JsonValue.isPunctuatorChar(left) || HjsonParser.tryParseNumber(value, true)!=null || startsWithKeyword(value)) { for(char ch : valuec) { if (needsEscapeML(ch)) { noEscapeML=false; break; } else if (!HjsonParser.isWhiteSpace(ch)) allWhite=false;
private boolean isWhiteSpace() { return isWhiteSpace((char)current); }
private ParseException error(String message) { int column=index-lineOffset; int offset=isEndOfText()?index:index-1; return new ParseException(message, offset, line, column-1); }
private JsonObject readObject(boolean objectWithoutBraces) throws IOException { if (!objectWithoutBraces) read(); JsonObject object=new JsonObject(); skipWhiteSpace(); while (true) { if (objectWithoutBraces) { if (isEndOfText()) break; } else { if (isEndOfText()) throw error("End of input while parsing an object (did you forget a closing '}'?)"); if (readIf('}')) break; } String name=readName(); skipWhiteSpace(); if (!readIf(':')) { throw expected("':'"); } skipWhiteSpace(); object.add(name, readValue()); skipWhiteSpace(); if (readIf(',')) skipWhiteSpace(); // , is optional } return object; }
private JsonArray readArray() throws IOException { read(); JsonArray array=new JsonArray(); skipWhiteSpace(); if (readIf(']')) { return array; } while (true) { skipWhiteSpace(); array.add(readValue()); skipWhiteSpace(); if (readIf(',')) skipWhiteSpace(); // , is optional if (readIf(']')) break; else if (isEndOfText()) throw error("End of input while parsing an array (did you forget a closing ']'?)"); } return array; }
private void skipWhiteSpace() throws IOException { while (!isEndOfText()) { while (isWhiteSpace()) read(); if (current=='#' || current=='/' && peek()=='/') { do { read(); } while (current>=0 && current!='\n'); } else if (current=='/' && peek()=='*') { read(); do { read(); } while (current>=0 && !(current=='*' && peek()=='/')); read(); read(); } else break; } }