/** * Stream processing of JSON text. * * @see ContentHandler * @param in * @param contentHandler * @param isResume - Indicates if it continues previous parsing operation. If set to true, resume * parsing the old stream, and parameter 'in' will be ignored. If this method is called for * the first time in this instance, isResume will be ignored. * @throws IOException * @throws ParseException */ public void parse(Reader in, ContentHandler contentHandler, boolean isResume) throws IOException, ParseException { if (!isResume) { reset(in); handlerStatusStack = new LinkedList(); } else { if (handlerStatusStack == null) { isResume = false; reset(in); handlerStatusStack = new LinkedList(); } } LinkedList statusStack = handlerStatusStack; try { do { switch (status) { case S_INIT: contentHandler.startJSON(); nextToken(); switch (token.type) { case Yytoken.TYPE_VALUE: status = S_IN_FINISHED_VALUE; statusStack.addFirst(new Integer(status)); if (!contentHandler.primitive(token.value)) return; break; case Yytoken.TYPE_LEFT_BRACE: status = S_IN_OBJECT; statusStack.addFirst(new Integer(status)); if (!contentHandler.startObject()) return; break; case Yytoken.TYPE_LEFT_SQUARE: status = S_IN_ARRAY; statusStack.addFirst(new Integer(status)); if (!contentHandler.startArray()) return; break; default: status = S_IN_ERROR; // inner switch } break; case S_IN_FINISHED_VALUE: nextToken(); if (token.type == Yytoken.TYPE_EOF) { contentHandler.endJSON(); status = S_END; return; } else { status = S_IN_ERROR; throw new ParseException(getPosition(), ParseException.ERROR_UNEXPECTED_TOKEN, token); } case S_IN_OBJECT: nextToken(); switch (token.type) { case Yytoken.TYPE_COMMA: break; case Yytoken.TYPE_VALUE: if (token.value instanceof String) { String key = (String) token.value; status = S_PASSED_PAIR_KEY; statusStack.addFirst(new Integer(status)); if (!contentHandler.startObjectEntry(key)) return; } else { status = S_IN_ERROR; } break; case Yytoken.TYPE_RIGHT_BRACE: if (statusStack.size() > 1) { statusStack.removeFirst(); status = peekStatus(statusStack); } else { status = S_IN_FINISHED_VALUE; } if (!contentHandler.endObject()) return; break; default: status = S_IN_ERROR; break; // inner switch } break; case S_PASSED_PAIR_KEY: nextToken(); switch (token.type) { case Yytoken.TYPE_COLON: break; case Yytoken.TYPE_VALUE: statusStack.removeFirst(); status = peekStatus(statusStack); if (!contentHandler.primitive(token.value)) return; if (!contentHandler.endObjectEntry()) return; break; case Yytoken.TYPE_LEFT_SQUARE: statusStack.removeFirst(); statusStack.addFirst(new Integer(S_IN_PAIR_VALUE)); status = S_IN_ARRAY; statusStack.addFirst(new Integer(status)); if (!contentHandler.startArray()) return; break; case Yytoken.TYPE_LEFT_BRACE: statusStack.removeFirst(); statusStack.addFirst(new Integer(S_IN_PAIR_VALUE)); status = S_IN_OBJECT; statusStack.addFirst(new Integer(status)); if (!contentHandler.startObject()) return; break; default: status = S_IN_ERROR; } break; case S_IN_PAIR_VALUE: statusStack.removeFirst(); status = peekStatus(statusStack); if (!contentHandler.endObjectEntry()) return; break; /* * S_IN_PAIR_VALUE is just a marker to indicate the end of an object entry, it doesn't proccess any token, * therefore delay consuming token until next round. */ case S_IN_ARRAY: nextToken(); switch (token.type) { case Yytoken.TYPE_COMMA: break; case Yytoken.TYPE_VALUE: if (!contentHandler.primitive(token.value)) return; break; case Yytoken.TYPE_RIGHT_SQUARE: if (statusStack.size() > 1) { statusStack.removeFirst(); status = peekStatus(statusStack); } else { status = S_IN_FINISHED_VALUE; } if (!contentHandler.endArray()) return; break; case Yytoken.TYPE_LEFT_BRACE: status = S_IN_OBJECT; statusStack.addFirst(new Integer(status)); if (!contentHandler.startObject()) return; break; case Yytoken.TYPE_LEFT_SQUARE: status = S_IN_ARRAY; statusStack.addFirst(new Integer(status)); if (!contentHandler.startArray()) return; break; default: status = S_IN_ERROR; // inner switch } break; case S_END: return; case S_IN_ERROR: throw new ParseException( getPosition(), ParseException.ERROR_UNEXPECTED_TOKEN, token); // switch } if (status == S_IN_ERROR) { throw new ParseException(getPosition(), ParseException.ERROR_UNEXPECTED_TOKEN, token); } } while (token.type != Yytoken.TYPE_EOF); } catch (IOException ie) { status = S_IN_ERROR; throw ie; } catch (ParseException pe) { status = S_IN_ERROR; throw pe; } catch (RuntimeException re) { status = S_IN_ERROR; throw re; } catch (Error e) { status = S_IN_ERROR; throw e; } status = S_IN_ERROR; throw new ParseException(getPosition(), ParseException.ERROR_UNEXPECTED_TOKEN, token); }