Merge branch 'develop' into feature/JAL-3551Pymol
[jalview.git] / srcjar_unused / org / json / simple / parser / JSONParser.java
diff --git a/srcjar_unused/org/json/simple/parser/JSONParser.java b/srcjar_unused/org/json/simple/parser/JSONParser.java
new file mode 100644 (file)
index 0000000..70e04cc
--- /dev/null
@@ -0,0 +1,611 @@
+/*
+ * $Id: JSONParser.java,v 1.1 2006/04/15 14:10:48 platform Exp $
+ * Created on 2006-4-15
+ */
+package org.json.simple.parser;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+
+/**
+ * Parser for JSON text. Please note that JSONParser is NOT thread-safe.
+ * 
+ * @author FangYidong<fangyidong@yahoo.com.cn>
+ */
+public class JSONParser
+{
+  public static final int S_INIT = 0;
+
+  public static final int S_IN_FINISHED_VALUE = 1;// string,number,boolean,null,object,array
+
+  public static final int S_IN_OBJECT = 2;
+
+  public static final int S_IN_ARRAY = 3;
+
+  public static final int S_PASSED_PAIR_KEY = 4;
+
+  public static final int S_IN_PAIR_VALUE = 5;
+
+  public static final int S_END = 6;
+
+  public static final int S_IN_ERROR = -1;
+
+  private LinkedList handlerStatusStack;
+
+  private Yylex lexer = new Yylex((Reader) null);
+
+  private Yytoken token = null;
+
+  private int status = S_INIT;
+
+  private int peekStatus(LinkedList statusStack)
+  {
+    if (statusStack.size() == 0)
+      return -1;
+    Integer status = (Integer) statusStack.getFirst();
+    return status.intValue();
+  }
+
+  /**
+   * Reset the parser to the initial state without resetting the underlying
+   * reader.
+   *
+   */
+  public void reset()
+  {
+    token = null;
+    status = S_INIT;
+    handlerStatusStack = null;
+  }
+
+  /**
+   * Reset the parser to the initial state with a new character reader.
+   * 
+   * @param in
+   *          - The new character reader.
+   * @throws IOException
+   * @throws ParseException
+   */
+  public void reset(Reader in)
+  {
+    lexer.yyreset(in);
+    reset();
+  }
+
+  /**
+   * @return The position of the beginning of the current token.
+   */
+  public int getPosition()
+  {
+    return lexer.getPosition();
+  }
+
+  public Object parse(String s) throws ParseException
+  {
+    return parse(s, (ContainerFactory) null);
+  }
+
+  public Object parse(String s, ContainerFactory containerFactory)
+          throws ParseException
+  {
+    StringReader in = new StringReader(s);
+    try
+    {
+      return parse(in, containerFactory);
+    } catch (IOException ie)
+    {
+      /*
+       * Actually it will never happen.
+       */
+      throw new ParseException(-1,
+              ParseException.ERROR_UNEXPECTED_EXCEPTION, ie);
+    }
+  }
+
+  public Object parse(Reader in) throws IOException, ParseException
+  {
+    return parse(in, (ContainerFactory) null);
+  }
+
+  /**
+   * Parse JSON text into java object from the input source.
+   * 
+   * @param in
+   * @param containerFactory
+   *          - Use this factory to createyour own JSON object and JSON array
+   *          containers.
+   * @return Instance of the following: org.json.simple.JSONObject,
+   *         org.json.simple.JSONArray, java.lang.String, java.lang.Number,
+   *         java.lang.Boolean, null
+   * 
+   * @throws IOException
+   * @throws ParseException
+   */
+  public Object parse(Reader in, ContainerFactory containerFactory)
+          throws IOException, ParseException
+  {
+    reset(in);
+    LinkedList statusStack = new LinkedList();
+    LinkedList valueStack = new LinkedList();
+
+    try
+    {
+      do
+      {
+        nextToken();
+        switch (status)
+        {
+        case S_INIT:
+          switch (token.type)
+          {
+          case Yytoken.TYPE_VALUE:
+            status = S_IN_FINISHED_VALUE;
+            statusStack.addFirst(new Integer(status));
+            valueStack.addFirst(token.value);
+            break;
+          case Yytoken.TYPE_LEFT_BRACE:
+            status = S_IN_OBJECT;
+            statusStack.addFirst(new Integer(status));
+            valueStack.addFirst(createObjectContainer(containerFactory));
+            break;
+          case Yytoken.TYPE_LEFT_SQUARE:
+            status = S_IN_ARRAY;
+            statusStack.addFirst(new Integer(status));
+            valueStack.addFirst(createArrayContainer(containerFactory));
+            break;
+          default:
+            status = S_IN_ERROR;
+          }// inner switch
+          break;
+
+        case S_IN_FINISHED_VALUE:
+          if (token.type == Yytoken.TYPE_EOF)
+            return valueStack.removeFirst();
+          else
+            throw new ParseException(getPosition(),
+                    ParseException.ERROR_UNEXPECTED_TOKEN, token);
+
+        case S_IN_OBJECT:
+          switch (token.type)
+          {
+          case Yytoken.TYPE_COMMA:
+            break;
+          case Yytoken.TYPE_VALUE:
+            if (token.value instanceof String)
+            {
+              String key = (String) token.value;
+              valueStack.addFirst(key);
+              status = S_PASSED_PAIR_KEY;
+              statusStack.addFirst(new Integer(status));
+            }
+            else
+            {
+              status = S_IN_ERROR;
+            }
+            break;
+          case Yytoken.TYPE_RIGHT_BRACE:
+            if (valueStack.size() > 1)
+            {
+              statusStack.removeFirst();
+              valueStack.removeFirst();
+              status = peekStatus(statusStack);
+            }
+            else
+            {
+              status = S_IN_FINISHED_VALUE;
+            }
+            break;
+          default:
+            status = S_IN_ERROR;
+            break;
+          }// inner switch
+          break;
+
+        case S_PASSED_PAIR_KEY:
+          switch (token.type)
+          {
+          case Yytoken.TYPE_COLON:
+            break;
+          case Yytoken.TYPE_VALUE:
+            statusStack.removeFirst();
+            String key = (String) valueStack.removeFirst();
+            Map parent = (Map) valueStack.getFirst();
+            parent.put(key, token.value);
+            status = peekStatus(statusStack);
+            break;
+          case Yytoken.TYPE_LEFT_SQUARE:
+            statusStack.removeFirst();
+            key = (String) valueStack.removeFirst();
+            parent = (Map) valueStack.getFirst();
+            List newArray = createArrayContainer(containerFactory);
+            parent.put(key, newArray);
+            status = S_IN_ARRAY;
+            statusStack.addFirst(new Integer(status));
+            valueStack.addFirst(newArray);
+            break;
+          case Yytoken.TYPE_LEFT_BRACE:
+            statusStack.removeFirst();
+            key = (String) valueStack.removeFirst();
+            parent = (Map) valueStack.getFirst();
+            Map newObject = createObjectContainer(containerFactory);
+            parent.put(key, newObject);
+            status = S_IN_OBJECT;
+            statusStack.addFirst(new Integer(status));
+            valueStack.addFirst(newObject);
+            break;
+          default:
+            status = S_IN_ERROR;
+          }
+          break;
+
+        case S_IN_ARRAY:
+          switch (token.type)
+          {
+          case Yytoken.TYPE_COMMA:
+            break;
+          case Yytoken.TYPE_VALUE:
+            List val = (List) valueStack.getFirst();
+            val.add(token.value);
+            break;
+          case Yytoken.TYPE_RIGHT_SQUARE:
+            if (valueStack.size() > 1)
+            {
+              statusStack.removeFirst();
+              valueStack.removeFirst();
+              status = peekStatus(statusStack);
+            }
+            else
+            {
+              status = S_IN_FINISHED_VALUE;
+            }
+            break;
+          case Yytoken.TYPE_LEFT_BRACE:
+            val = (List) valueStack.getFirst();
+            Map newObject = createObjectContainer(containerFactory);
+            val.add(newObject);
+            status = S_IN_OBJECT;
+            statusStack.addFirst(new Integer(status));
+            valueStack.addFirst(newObject);
+            break;
+          case Yytoken.TYPE_LEFT_SQUARE:
+            val = (List) valueStack.getFirst();
+            List newArray = createArrayContainer(containerFactory);
+            val.add(newArray);
+            status = S_IN_ARRAY;
+            statusStack.addFirst(new Integer(status));
+            valueStack.addFirst(newArray);
+            break;
+          default:
+            status = S_IN_ERROR;
+          }// inner switch
+          break;
+        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)
+    {
+      throw ie;
+    }
+
+    throw new ParseException(getPosition(),
+            ParseException.ERROR_UNEXPECTED_TOKEN, token);
+  }
+
+  private void nextToken() throws ParseException, IOException
+  {
+    token = lexer.yylex();
+    if (token == null)
+      token = new Yytoken(Yytoken.TYPE_EOF, null);
+  }
+
+  private Map createObjectContainer(ContainerFactory containerFactory)
+  {
+    if (containerFactory == null)
+      return new JSONObject();
+    Map m = containerFactory.createObjectContainer();
+
+    if (m == null)
+      return new JSONObject();
+    return m;
+  }
+
+  private List createArrayContainer(ContainerFactory containerFactory)
+  {
+    if (containerFactory == null)
+      return new JSONArray();
+    List l = containerFactory.creatArrayContainer();
+
+    if (l == null)
+      return new JSONArray();
+    return l;
+  }
+
+  public void parse(String s, ContentHandler contentHandler)
+          throws ParseException
+  {
+    parse(s, contentHandler, false);
+  }
+
+  public void parse(String s, ContentHandler contentHandler,
+          boolean isResume) throws ParseException
+  {
+    StringReader in = new StringReader(s);
+    try
+    {
+      parse(in, contentHandler, isResume);
+    } catch (IOException ie)
+    {
+      /*
+       * Actually it will never happen.
+       */
+      throw new ParseException(-1,
+              ParseException.ERROR_UNEXPECTED_EXCEPTION, ie);
+    }
+  }
+
+  public void parse(Reader in, ContentHandler contentHandler)
+          throws IOException, ParseException
+  {
+    parse(in, contentHandler, false);
+  }
+
+  /**
+   * 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:
+          /*
+           * 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.
+           */
+          statusStack.removeFirst();
+          status = peekStatus(statusStack);
+          if (!contentHandler.endObjectEntry())
+            return;
+          break;
+
+        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);
+  }
+}