Home » apache-tomcat-6.0.26-src » org.apache » tomcat » util » json » [javadoc | source]

    1   package org.apache.tomcat.util.json;
    2   
    3   import java.io.BufferedReader;
    4   import java.io.IOException;
    5   import java.io.Reader;
    6   import java.io.StringReader;
    7   
    8   /*
    9   Copyright (c) 2002 JSON.org
   10   
   11   Permission is hereby granted, free of charge, to any person obtaining a copy
   12   of this software and associated documentation files (the "Software"), to deal
   13   in the Software without restriction, including without limitation the rights
   14   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   15   copies of the Software, and to permit persons to whom the Software is
   16   furnished to do so, subject to the following conditions:
   17   
   18   The above copyright notice and this permission notice shall be included in all
   19   copies or substantial portions of the Software.
   20   
   21   The Software shall be used for Good, not Evil.
   22   
   23   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   24   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   25   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   26   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   27   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   28   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
   29   SOFTWARE.
   30   */
   31   
   32   /**
   33    * A JSONTokener takes a source string and extracts characters and tokens from
   34    * it. It is used by the JSONObject and JSONArray constructors to parse
   35    * JSON source strings.
   36    * @author JSON.org
   37    * @version 2008-09-18
   38    */
   39   public class JSONTokener {
   40   
   41       private int index;
   42       private Reader reader;
   43       private char lastChar;
   44       private boolean useLastChar;
   45   
   46   
   47       /**
   48        * Construct a JSONTokener from a string.
   49        *
   50        * @param reader     A reader.
   51        */
   52       public JSONTokener(Reader reader) {
   53           this.reader = reader.markSupported() ? 
   54           		reader : new BufferedReader(reader);
   55           this.useLastChar = false;
   56           this.index = 0;
   57       }
   58   
   59   
   60       /**
   61        * Construct a JSONTokener from a string.
   62        *
   63        * @param s     A source string.
   64        */
   65       public JSONTokener(String s) {
   66           this(new StringReader(s));
   67       }
   68   
   69   
   70       /**
   71        * Back up one character. This provides a sort of lookahead capability,
   72        * so that you can test for a digit or letter before attempting to parse
   73        * the next number or identifier.
   74        */
   75       public void back() throws JSONException {
   76           if (useLastChar || index <= 0) {
   77               throw new JSONException("Stepping back two steps is not supported");
   78           }
   79           index -= 1;
   80           useLastChar = true;
   81       }
   82   
   83   
   84   
   85       /**
   86        * Get the hex value of a character (base16).
   87        * @param c A character between '0' and '9' or between 'A' and 'F' or
   88        * between 'a' and 'f'.
   89        * @return  An int between 0 and 15, or -1 if c was not a hex digit.
   90        */
   91       public static int dehexchar(char c) {
   92           if (c >= '0' && c <= '9') {
   93               return c - '0';
   94           }
   95           if (c >= 'A' && c <= 'F') {
   96               return c - ('A' - 10);
   97           }
   98           if (c >= 'a' && c <= 'f') {
   99               return c - ('a' - 10);
  100           }
  101           return -1;
  102       }
  103   
  104   
  105       /**
  106        * Determine if the source string still contains characters that next()
  107        * can consume.
  108        * @return true if not yet at the end of the source.
  109        */
  110       public boolean more() throws JSONException {
  111           char nextChar = next();
  112           if (nextChar == 0) {
  113               return false;
  114           } 
  115           back();
  116           return true;
  117       }
  118   
  119   
  120       /**
  121        * Get the next character in the source string.
  122        *
  123        * @return The next character, or 0 if past the end of the source string.
  124        */
  125       public char next() throws JSONException {
  126           if (this.useLastChar) {
  127           	this.useLastChar = false;
  128               if (this.lastChar != 0) {
  129               	this.index += 1;
  130               }
  131               return this.lastChar;
  132           } 
  133           int c;
  134           try {
  135               c = this.reader.read();
  136           } catch (IOException exc) {
  137               throw new JSONException(exc);
  138           }
  139   
  140           if (c <= 0) { // End of stream
  141           	this.lastChar = 0;
  142               return 0;
  143           } 
  144       	this.index += 1;
  145       	this.lastChar = (char) c;
  146           return this.lastChar;
  147       }
  148   
  149   
  150       /**
  151        * Consume the next character, and check that it matches a specified
  152        * character.
  153        * @param c The character to match.
  154        * @return The character.
  155        * @throws JSONException if the character does not match.
  156        */
  157       public char next(char c) throws JSONException {
  158           char n = next();
  159           if (n != c) {
  160               throw syntaxError("Expected '" + c + "' and instead saw '" +
  161                       n + "'");
  162           }
  163           return n;
  164       }
  165   
  166   
  167       /**
  168        * Get the next n characters.
  169        *
  170        * @param n     The number of characters to take.
  171        * @return      A string of n characters.
  172        * @throws JSONException
  173        *   Substring bounds error if there are not
  174        *   n characters remaining in the source string.
  175        */
  176        public String next(int n) throws JSONException {
  177            if (n == 0) {
  178                return "";
  179            }
  180   
  181            char[] buffer = new char[n];
  182            int pos = 0;
  183   
  184            if (this.useLastChar) {
  185           	 this.useLastChar = false;
  186                buffer[0] = this.lastChar;
  187                pos = 1;
  188            }
  189   
  190            try {
  191                int len;
  192                while ((pos < n) && ((len = reader.read(buffer, pos, n - pos)) != -1)) {
  193                    pos += len;
  194                }
  195            } catch (IOException exc) {
  196                throw new JSONException(exc);
  197            }
  198            this.index += pos;
  199   
  200            if (pos < n) {
  201                throw syntaxError("Substring bounds error");
  202            }
  203   
  204            this.lastChar = buffer[n - 1];
  205            return new String(buffer);
  206        }
  207   
  208   
  209       /**
  210        * Get the next char in the string, skipping whitespace.
  211        * @throws JSONException
  212        * @return  A character, or 0 if there are no more characters.
  213        */
  214       public char nextClean() throws JSONException {
  215           for (;;) {
  216               char c = next();
  217               if (c == 0 || c > ' ') {
  218                   return c;
  219               }
  220           }
  221       }
  222   
  223   
  224       /**
  225        * Return the characters up to the next close quote character.
  226        * Backslash processing is done. The formal JSON format does not
  227        * allow strings in single quotes, but an implementation is allowed to
  228        * accept them.
  229        * @param quote The quoting character, either
  230        *      <code>"</code>&nbsp;<small>(double quote)</small> or
  231        *      <code>'</code>&nbsp;<small>(single quote)</small>.
  232        * @return      A String.
  233        * @throws JSONException Unterminated string.
  234        */
  235       public String nextString(char quote) throws JSONException {
  236           char c;
  237           StringBuffer sb = new StringBuffer();
  238           for (;;) {
  239               c = next();
  240               switch (c) {
  241               case 0:
  242               case '\n':
  243               case '\r':
  244                   throw syntaxError("Unterminated string");
  245               case '\\':
  246                   c = next();
  247                   switch (c) {
  248                   case 'b':
  249                       sb.append('\b');
  250                       break;
  251                   case 't':
  252                       sb.append('\t');
  253                       break;
  254                   case 'n':
  255                       sb.append('\n');
  256                       break;
  257                   case 'f':
  258                       sb.append('\f');
  259                       break;
  260                   case 'r':
  261                       sb.append('\r');
  262                       break;
  263                   case 'u':
  264                       sb.append((char)Integer.parseInt(next(4), 16));
  265                       break;
  266                   case 'x' :
  267                       sb.append((char) Integer.parseInt(next(2), 16));
  268                       break;
  269                   default:
  270                       sb.append(c);
  271                   }
  272                   break;
  273               default:
  274                   if (c == quote) {
  275                       return sb.toString();
  276                   }
  277                   sb.append(c);
  278               }
  279           }
  280       }
  281   
  282   
  283       /**
  284        * Get the text up but not including the specified character or the
  285        * end of line, whichever comes first.
  286        * @param  d A delimiter character.
  287        * @return   A string.
  288        */
  289       public String nextTo(char d) throws JSONException {
  290           StringBuffer sb = new StringBuffer();
  291           for (;;) {
  292               char c = next();
  293               if (c == d || c == 0 || c == '\n' || c == '\r') {
  294                   if (c != 0) {
  295                       back();
  296                   }
  297                   return sb.toString().trim();
  298               }
  299               sb.append(c);
  300           }
  301       }
  302   
  303   
  304       /**
  305        * Get the text up but not including one of the specified delimiter
  306        * characters or the end of line, whichever comes first.
  307        * @param delimiters A set of delimiter characters.
  308        * @return A string, trimmed.
  309        */
  310       public String nextTo(String delimiters) throws JSONException {
  311           char c;
  312           StringBuffer sb = new StringBuffer();
  313           for (;;) {
  314               c = next();
  315               if (delimiters.indexOf(c) >= 0 || c == 0 ||
  316                       c == '\n' || c == '\r') {
  317                   if (c != 0) {
  318                       back();
  319                   }
  320                   return sb.toString().trim();
  321               }
  322               sb.append(c);
  323           }
  324       }
  325   
  326   
  327       /**
  328        * Get the next value. The value can be a Boolean, Double, Integer,
  329        * JSONArray, JSONObject, Long, or String, or the JSONObject.NULL object.
  330        * @throws JSONException If syntax error.
  331        *
  332        * @return An object.
  333        */
  334       public Object nextValue() throws JSONException {
  335           char c = nextClean();
  336           String s;
  337   
  338           switch (c) {
  339               case '"':
  340               case '\'':
  341                   return nextString(c);
  342               case '{':
  343                   back();
  344                   return new JSONObject(this);
  345               case '[':
  346               case '(':
  347                   back();
  348                   return new JSONArray(this);
  349           }
  350   
  351           /*
  352            * Handle unquoted text. This could be the values true, false, or
  353            * null, or it can be a number. An implementation (such as this one)
  354            * is allowed to also accept non-standard forms.
  355            *
  356            * Accumulate characters until we reach the end of the text or a
  357            * formatting character.
  358            */
  359   
  360           StringBuffer sb = new StringBuffer();
  361           while (c >= ' ' && ",:]}/\\\"[{;=#".indexOf(c) < 0) {
  362               sb.append(c);
  363               c = next();
  364           }
  365           back();
  366   
  367           s = sb.toString().trim();
  368           if (s.equals("")) {
  369               throw syntaxError("Missing value");
  370           }
  371           return JSONObject.stringToValue(s);
  372       }
  373   
  374   
  375       /**
  376        * Skip characters until the next character is the requested character.
  377        * If the requested character is not found, no characters are skipped.
  378        * @param to A character to skip to.
  379        * @return The requested character, or zero if the requested character
  380        * is not found.
  381        */
  382       public char skipTo(char to) throws JSONException {
  383           char c;
  384           try {
  385               int startIndex = this.index;
  386               reader.mark(Integer.MAX_VALUE);
  387               do {
  388                   c = next();
  389                   if (c == 0) {
  390                       reader.reset();
  391                       this.index = startIndex;
  392                       return c;
  393                   }
  394               } while (c != to);
  395           } catch (IOException exc) {
  396               throw new JSONException(exc);
  397           }
  398   
  399           back();
  400           return c;
  401       }
  402   
  403       /**
  404        * Make a JSONException to signal a syntax error.
  405        *
  406        * @param message The error message.
  407        * @return  A JSONException object, suitable for throwing
  408        */
  409       public JSONException syntaxError(String message) {
  410           return new JSONException(message + toString());
  411       }
  412   
  413   
  414       /**
  415        * Make a printable string of this JSONTokener.
  416        *
  417        * @return " at character [this.index]"
  418        */
  419       public String toString() {
  420           return " at character " + index;
  421       }
  422   }

Home » apache-tomcat-6.0.26-src » org.apache » tomcat » util » json » [javadoc | source]