This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch 8.5.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git


The following commit(s) were added to refs/heads/8.5.x by this push:
     new 43ca6e08bc Back port JSON parser to 8.5.x (required by HTTP/2 priority 
back port)
43ca6e08bc is described below

commit 43ca6e08bc09f2caa46988c6335939344b208c45
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Wed May 10 11:59:47 2023 +0100

    Back port JSON parser to 8.5.x (required by HTTP/2 priority back port)
---
 build.xml                                          |  13 +-
 java/org/apache/tomcat/util/json/JSONParser.java   | 655 ++++++++++++++++
 java/org/apache/tomcat/util/json/JSONParser.jjt    | 384 +++++++++
 .../tomcat/util/json/JSONParserConstants.java      | 122 +++
 .../tomcat/util/json/JSONParserTokenManager.java   | 869 +++++++++++++++++++++
 .../apache/tomcat/util/json/JavaCharStream.java    | 641 +++++++++++++++
 .../tomcat/util/json/LocalStrings.properties       |  16 +
 .../tomcat/util/json/LocalStrings_de.properties    |  16 +
 .../tomcat/util/json/LocalStrings_fr.properties    |  16 +
 .../tomcat/util/json/LocalStrings_ja.properties    |  16 +
 .../tomcat/util/json/LocalStrings_ko.properties    |  16 +
 .../tomcat/util/json/LocalStrings_zh_CN.properties |  16 +
 .../apache/tomcat/util/json/ParseException.java    | 212 +++++
 java/org/apache/tomcat/util/json/Token.java        | 147 ++++
 .../org/apache/tomcat/util/json/TokenMgrError.java | 163 ++++
 15 files changed, 3297 insertions(+), 5 deletions(-)

diff --git a/build.xml b/build.xml
index d407be0407..c2232942af 100644
--- a/build.xml
+++ b/build.xml
@@ -629,13 +629,16 @@
         <exclude name="**/*_2.xml"/>
         <exclude name="res/checkstyle/header-al2.txt"/>
         <!-- Exclude auto-generated files -->
-        <exclude name="java/org/apache/el/parser/ELParser.jj" />
         <exclude name="java/org/apache/el/parser/ELParser*.java" />
         <exclude name="java/org/apache/el/parser/Node.java" />
-        <exclude name="java/org/apache/**/parser/JJT*ParserState.java" />
-        <exclude name="java/org/apache/**/parser/ParseException.java" />
-        <exclude name="java/org/apache/**/parser/SimpleCharStream.java" />
-        <exclude name="java/org/apache/**/parser/Token*.java" />
+        <exclude name="java/org/apache/tomcat/util/json/JSONParser*.java" />
+        <exclude name="**/*.jj" />
+        <exclude name="java/org/apache/**/JJT*ParserState.java" />
+        <exclude name="java/org/apache/**/ParseException.java" />
+        <exclude name="java/org/apache/**/JavaCharStream.java" />
+        <exclude name="java/org/apache/**/SimpleCharStream.java" />
+        <exclude name="java/org/apache/**/Token.java" />
+        <exclude name="java/org/apache/**/TokenMgrError.java" />
         <!-- Exclude developer specific local files -->
         <exclude name="build.properties" />
         <exclude name="res/maven/mvn.properties" />
diff --git a/java/org/apache/tomcat/util/json/JSONParser.java 
b/java/org/apache/tomcat/util/json/JSONParser.java
new file mode 100644
index 0000000000..0842017739
--- /dev/null
+++ b/java/org/apache/tomcat/util/json/JSONParser.java
@@ -0,0 +1,655 @@
+/* JSONParser.java */
+/* Generated By:JavaCC: Do not edit this line. JSONParser.java */
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.tomcat.util.json;
+
+/**
+ * Basic JSON parser generated by JavaCC. It consumes the input provided 
through the constructor when
+ * {@code parseObject()}, {@code parseList()}, or {@code parse()} are called, 
and there is no way to directly
+ * reset the state.
+ */
+@SuppressWarnings("all") // Ignore warnings in generated code
+public class JSONParser implements JSONParserConstants {
+
+    private boolean nativeNumbers = false;
+
+    public JSONParser(String input) {
+        this(new java.io.StringReader(input));
+    }
+
+    /**
+     * Parses a JSON object into a Java {@code Map}.
+     */
+    public java.util.LinkedHashMap<String, Object> parseObject() throws 
ParseException {
+        java.util.LinkedHashMap<String, Object> toReturn = object();
+        if (!ensureEOF()) {
+            throw new IllegalStateException("Expected EOF, but still had 
content to parse");
+        }
+        return toReturn;
+    }
+
+    /**
+     * Parses a JSON array into a Java {@code List}.
+     */
+    public java.util.ArrayList<Object> parseArray() throws ParseException {
+        java.util.ArrayList<Object> toReturn = list();
+        if (!ensureEOF()) {
+            throw new IllegalStateException("Expected EOF, but still had 
content to parse");
+        }
+        return toReturn;
+    }
+
+    /**
+     * Parses any JSON-parseable object, returning the value.
+     */
+    public Object parse() throws ParseException {
+        Object toReturn = anything();
+        if (!ensureEOF()) {
+            throw new IllegalStateException("Expected EOF, but still had 
content to parse");
+        }
+        return toReturn;
+    }
+
+    private static String substringBefore(String str, char delim) {
+        int pos = str.indexOf(delim);
+        if (pos == -1) {
+            return str;
+        }
+        return str.substring(0, pos);
+    }
+
+    public void setNativeNumbers(boolean value) {
+        this.nativeNumbers = value;
+    }
+
+    public boolean getNativeNumbers() {
+        return this.nativeNumbers;
+    }
+
+  final public boolean ensureEOF() throws ParseException {
+    jj_consume_token(0);
+{if ("" != null) {
+  return true;
+}}
+    throw new Error("Missing return statement in function");
+}
+
+  final public Object anything() throws ParseException {Object x;
+    switch (jj_nt.kind) {
+    case BRACE_OPEN:{
+      x = object();
+      break;
+      }
+    case BRACKET_OPEN:{
+      x = list();
+      break;
+      }
+    case NUMBER_INTEGER:
+    case NUMBER_DECIMAL:
+    case TRUE:
+    case FALSE:
+    case NULL:
+    case STRING_SINGLE_EMPTY:
+    case STRING_DOUBLE_EMPTY:
+    case STRING_SINGLE_NONEMPTY:
+    case STRING_DOUBLE_NONEMPTY:{
+      x = value();
+      break;
+      }
+    default:
+      jj_la1[0] = jj_gen;
+      jj_consume_token(-1);
+      throw new ParseException();
+    }
+{if ("" != null) {
+  return x;
+}}
+    throw new Error("Missing return statement in function");
+}
+
+  final public String objectKey() throws ParseException {Object o;
+    String key;
+    switch (jj_nt.kind) {
+    case STRING_SINGLE_EMPTY:
+    case STRING_DOUBLE_EMPTY:
+    case STRING_SINGLE_NONEMPTY:
+    case STRING_DOUBLE_NONEMPTY:{
+      key = string();
+      break;
+      }
+    case SYMBOL:{
+      key = symbol();
+      break;
+      }
+    case NULL:{
+      nullValue();
+key = null;
+      break;
+      }
+    case NUMBER_INTEGER:
+    case NUMBER_DECIMAL:
+    case TRUE:
+    case FALSE:{
+      switch (jj_nt.kind) {
+      case TRUE:
+      case FALSE:{
+        o = booleanValue();
+        break;
+        }
+      case NUMBER_INTEGER:
+      case NUMBER_DECIMAL:{
+        o = number();
+        break;
+        }
+      default:
+        jj_la1[1] = jj_gen;
+        jj_consume_token(-1);
+        throw new ParseException();
+      }
+key = o.toString();
+      break;
+      }
+    default:
+      jj_la1[2] = jj_gen;
+      jj_consume_token(-1);
+      throw new ParseException();
+    }
+{if ("" != null) {
+  return key;
+}}
+    throw new Error("Missing return statement in function");
+}
+
+  final public java.util.LinkedHashMap<String, Object> object() throws 
ParseException {final java.util.LinkedHashMap<String, Object> map = new 
java.util.LinkedHashMap<String, Object>();
+    String key;
+    Object value;
+    jj_consume_token(BRACE_OPEN);
+    switch (jj_nt.kind) {
+    case NUMBER_INTEGER:
+    case NUMBER_DECIMAL:
+    case TRUE:
+    case FALSE:
+    case NULL:
+    case STRING_SINGLE_EMPTY:
+    case STRING_DOUBLE_EMPTY:
+    case STRING_SINGLE_NONEMPTY:
+    case STRING_DOUBLE_NONEMPTY:
+    case SYMBOL:{
+      key = objectKey();
+      jj_consume_token(COLON);
+      value = anything();
+map.put(key, value);
+key = null; value = null;
+      label_1:
+      while (true) {
+        switch (jj_nt.kind) {
+        case COMMA:{
+          ;
+          break;
+          }
+        default:
+          jj_la1[3] = jj_gen;
+          break label_1;
+        }
+        jj_consume_token(COMMA);
+        key = objectKey();
+        jj_consume_token(COLON);
+        value = anything();
+map.put(key, value);
+key = null; value = null;
+      }
+      break;
+      }
+    default:
+      jj_la1[4] = jj_gen;
+      ;
+    }
+    jj_consume_token(BRACE_CLOSE);
+{if ("" != null) {
+  return map;
+}}
+    throw new Error("Missing return statement in function");
+}
+
+  final public java.util.ArrayList<Object> list() throws ParseException {final 
java.util.ArrayList<Object> list = new java.util.ArrayList<Object>();
+    Object value;
+    jj_consume_token(BRACKET_OPEN);
+    switch (jj_nt.kind) {
+    case BRACE_OPEN:
+    case BRACKET_OPEN:
+    case NUMBER_INTEGER:
+    case NUMBER_DECIMAL:
+    case TRUE:
+    case FALSE:
+    case NULL:
+    case STRING_SINGLE_EMPTY:
+    case STRING_DOUBLE_EMPTY:
+    case STRING_SINGLE_NONEMPTY:
+    case STRING_DOUBLE_NONEMPTY:{
+      value = anything();
+list.add(value);
+value = null;
+      label_2:
+      while (true) {
+        switch (jj_nt.kind) {
+        case COMMA:{
+          ;
+          break;
+          }
+        default:
+          jj_la1[5] = jj_gen;
+          break label_2;
+        }
+        jj_consume_token(COMMA);
+        value = anything();
+list.add(value);
+value = null;
+      }
+      break;
+      }
+    default:
+      jj_la1[6] = jj_gen;
+      ;
+    }
+    jj_consume_token(BRACKET_CLOSE);
+list.trimToSize();
+        {if ("" != null) {
+          return list;
+        }}
+    throw new Error("Missing return statement in function");
+}
+
+  final public Object value() throws ParseException {Object x;
+    switch (jj_nt.kind) {
+    case STRING_SINGLE_EMPTY:
+    case STRING_DOUBLE_EMPTY:
+    case STRING_SINGLE_NONEMPTY:
+    case STRING_DOUBLE_NONEMPTY:{
+      x = string();
+      break;
+      }
+    case NUMBER_INTEGER:
+    case NUMBER_DECIMAL:{
+      x = number();
+      break;
+      }
+    case TRUE:
+    case FALSE:{
+      x = booleanValue();
+      break;
+      }
+    case NULL:{
+      x = nullValue();
+      break;
+      }
+    default:
+      jj_la1[7] = jj_gen;
+      jj_consume_token(-1);
+      throw new ParseException();
+    }
+{if ("" != null) {
+  return x;
+}}
+    throw new Error("Missing return statement in function");
+}
+
+  final public Object nullValue() throws ParseException {
+    jj_consume_token(NULL);
+{if ("" != null) {
+  return null;
+}}
+    throw new Error("Missing return statement in function");
+}
+
+  final public Boolean booleanValue() throws ParseException {Boolean b;
+    switch (jj_nt.kind) {
+    case TRUE:{
+      jj_consume_token(TRUE);
+b = Boolean.TRUE;
+      break;
+      }
+    case FALSE:{
+      jj_consume_token(FALSE);
+b = Boolean.FALSE;
+      break;
+      }
+    default:
+      jj_la1[8] = jj_gen;
+      jj_consume_token(-1);
+      throw new ParseException();
+    }
+{if ("" != null) {
+  return b;
+}}
+    throw new Error("Missing return statement in function");
+}
+
+  final public Number number() throws ParseException {Token t;
+    switch (jj_nt.kind) {
+    case NUMBER_DECIMAL:{
+      t = jj_consume_token(NUMBER_DECIMAL);
+if (nativeNumbers) {
+                {if ("" != null) {
+                  return Long.valueOf(t.image);
+                }}
+            } else {
+                {if ("" != null) {
+                  return new java.math.BigDecimal(t.image);
+                }}
+            }
+      break;
+      }
+    case NUMBER_INTEGER:{
+      t = jj_consume_token(NUMBER_INTEGER);
+if (nativeNumbers) {
+                {if ("" != null) {
+                  return Double.valueOf(t.image);
+                }}
+            } else {
+                {if ("" != null) {
+                  return new java.math.BigInteger(substringBefore(t.image, 
'.'));
+                }}
+            }
+      break;
+      }
+    default:
+      jj_la1[9] = jj_gen;
+      jj_consume_token(-1);
+      throw new ParseException();
+    }
+    throw new Error("Missing return statement in function");
+}
+
+  final public String string() throws ParseException {String s;
+    switch (jj_nt.kind) {
+    case STRING_DOUBLE_EMPTY:
+    case STRING_DOUBLE_NONEMPTY:{
+      s = doubleQuoteString();
+      break;
+      }
+    case STRING_SINGLE_EMPTY:
+    case STRING_SINGLE_NONEMPTY:{
+      s = singleQuoteString();
+      break;
+      }
+    default:
+      jj_la1[10] = jj_gen;
+      jj_consume_token(-1);
+      throw new ParseException();
+    }
+{if ("" != null) {
+  return s;
+}}
+    throw new Error("Missing return statement in function");
+}
+
+  final public String doubleQuoteString() throws ParseException {
+    switch (jj_nt.kind) {
+    case STRING_DOUBLE_EMPTY:{
+      jj_consume_token(STRING_DOUBLE_EMPTY);
+{if ("" != null) {
+  return "";
+}}
+      break;
+      }
+    case STRING_DOUBLE_NONEMPTY:{
+      jj_consume_token(STRING_DOUBLE_NONEMPTY);
+String image = token.image;
+            {if ("" != null) {
+              return image.substring(1, image.length() - 1);
+            }}
+      break;
+      }
+    default:
+      jj_la1[11] = jj_gen;
+      jj_consume_token(-1);
+      throw new ParseException();
+    }
+    throw new Error("Missing return statement in function");
+}
+
+  final public String singleQuoteString() throws ParseException {
+    switch (jj_nt.kind) {
+    case STRING_SINGLE_EMPTY:{
+      jj_consume_token(STRING_SINGLE_EMPTY);
+{if ("" != null) {
+  return "";
+}}
+      break;
+      }
+    case STRING_SINGLE_NONEMPTY:{
+      jj_consume_token(STRING_SINGLE_NONEMPTY);
+String image = token.image;
+            {if ("" != null) {
+              return image.substring(1, image.length() - 1);
+            }}
+      break;
+      }
+    default:
+      jj_la1[12] = jj_gen;
+      jj_consume_token(-1);
+      throw new ParseException();
+    }
+    throw new Error("Missing return statement in function");
+}
+
+  final public String symbol() throws ParseException {
+    jj_consume_token(SYMBOL);
+{if ("" != null) {
+  return token.image;
+}}
+    throw new Error("Missing return statement in function");
+}
+
+  /** Generated Token Manager. */
+  public JSONParserTokenManager token_source;
+  JavaCharStream jj_input_stream;
+  /** Current token. */
+  public Token token;
+  /** Next token. */
+  public Token jj_nt;
+  private int jj_gen;
+  final private int[] jj_la1 = new int[13];
+  static private int[] jj_la1_0;
+  static {
+          jj_la1_init_0();
+       }
+       private static void jj_la1_init_0() {
+          jj_la1_0 = new int[] 
{0xccf8480,0x78000,0x1ccf8000,0x40,0x1ccf8000,0x40,0xccf8480,0xccf8000,0x60000,0x18000,0xcc00000,0x8800000,0x4400000,};
+       }
+
+  /** Constructor with InputStream. */
+  public JSONParser(java.io.InputStream stream) {
+         this(stream, null);
+  }
+  /** Constructor with InputStream and supplied encoding */
+  public JSONParser(java.io.InputStream stream, String encoding) {
+        try { jj_input_stream = new JavaCharStream(stream, encoding, 1, 1); } 
catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); }
+        token_source = new JSONParserTokenManager(jj_input_stream);
+        token = new Token();
+        token.next = jj_nt = token_source.getNextToken();
+        jj_gen = 0;
+        for (int i = 0; i < 13; i++) {
+    jj_la1[i] = -1;
+  }
+  }
+
+  /** Reinitialise. */
+  public void ReInit(java.io.InputStream stream) {
+         ReInit(stream, null);
+  }
+  /** Reinitialise. */
+  public void ReInit(java.io.InputStream stream, String encoding) {
+        try { jj_input_stream.ReInit(stream, encoding, 1, 1); } 
catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); }
+        token_source.ReInit(jj_input_stream);
+        token = new Token();
+        token.next = jj_nt = token_source.getNextToken();
+        jj_gen = 0;
+        for (int i = 0; i < 13; i++) {
+    jj_la1[i] = -1;
+  }
+  }
+
+  /** Constructor. */
+  public JSONParser(java.io.Reader stream) {
+        jj_input_stream = new JavaCharStream(stream, 1, 1);
+        token_source = new JSONParserTokenManager(jj_input_stream);
+        token = new Token();
+        token.next = jj_nt = token_source.getNextToken();
+        jj_gen = 0;
+        for (int i = 0; i < 13; i++) {
+    jj_la1[i] = -1;
+  }
+  }
+
+  /** Reinitialise. */
+  public void ReInit(java.io.Reader stream) {
+       if (jj_input_stream == null) {
+          jj_input_stream = new JavaCharStream(stream, 1, 1);
+       } else {
+          jj_input_stream.ReInit(stream, 1, 1);
+       }
+       if (token_source == null) {
+ token_source = new JSONParserTokenManager(jj_input_stream);
+       }
+
+        token_source.ReInit(jj_input_stream);
+        token = new Token();
+        token.next = jj_nt = token_source.getNextToken();
+        jj_gen = 0;
+        for (int i = 0; i < 13; i++) {
+    jj_la1[i] = -1;
+  }
+  }
+
+  /** Constructor with generated Token Manager. */
+  public JSONParser(JSONParserTokenManager tm) {
+        token_source = tm;
+        token = new Token();
+        token.next = jj_nt = token_source.getNextToken();
+        jj_gen = 0;
+        for (int i = 0; i < 13; i++) {
+    jj_la1[i] = -1;
+  }
+  }
+
+  /** Reinitialise. */
+  public void ReInit(JSONParserTokenManager tm) {
+        token_source = tm;
+        token = new Token();
+        token.next = jj_nt = token_source.getNextToken();
+        jj_gen = 0;
+        for (int i = 0; i < 13; i++) {
+    jj_la1[i] = -1;
+  }
+  }
+
+  private Token jj_consume_token(int kind) throws ParseException {
+        Token oldToken = token;
+        if ((token = jj_nt).next != null) {
+    jj_nt = jj_nt.next;
+  } else {
+    jj_nt = jj_nt.next = token_source.getNextToken();
+  }
+        if (token.kind == kind) {
+          jj_gen++;
+          return token;
+        }
+        jj_nt = token;
+        token = oldToken;
+        jj_kind = kind;
+        throw generateParseException();
+  }
+
+
+/** Get the next Token. */
+  final public Token getNextToken() {
+        if ((token = jj_nt).next != null) {
+    jj_nt = jj_nt.next;
+  } else {
+    jj_nt = jj_nt.next = token_source.getNextToken();
+  }
+        jj_gen++;
+        return token;
+  }
+
+/** Get the specific Token. */
+  final public Token getToken(int index) {
+        Token t = token;
+        for (int i = 0; i < index; i++) {
+          if (t.next != null) {
+      t = t.next;
+    } else {
+      t = t.next = token_source.getNextToken();
+    }
+        }
+        return t;
+  }
+
+  private java.util.List<int[]> jj_expentries = new 
java.util.ArrayList<int[]>();
+  private int[] jj_expentry;
+  private int jj_kind = -1;
+
+  /** Generate ParseException. */
+  public ParseException generateParseException() {
+        jj_expentries.clear();
+        boolean[] la1tokens = new boolean[29];
+        if (jj_kind >= 0) {
+          la1tokens[jj_kind] = true;
+          jj_kind = -1;
+        }
+        for (int i = 0; i < 13; i++) {
+          if (jj_la1[i] == jj_gen) {
+                for (int j = 0; j < 32; j++) {
+                  if ((jj_la1_0[i] & (1<<j)) != 0) {
+                        la1tokens[j] = true;
+                  }
+                }
+          }
+        }
+        for (int i = 0; i < 29; i++) {
+          if (la1tokens[i]) {
+                jj_expentry = new int[1];
+                jj_expentry[0] = i;
+                jj_expentries.add(jj_expentry);
+          }
+        }
+        int[][] exptokseq = new int[jj_expentries.size()][];
+        for (int i = 0; i < jj_expentries.size(); i++) {
+          exptokseq[i] = jj_expentries.get(i);
+        }
+        return new ParseException(token, exptokseq, tokenImage);
+  }
+
+  private int trace_indent = 0;
+  private boolean trace_enabled;
+
+/** Trace enabled. */
+  final public boolean trace_enabled() {
+        return trace_enabled;
+  }
+
+  /** Enable tracing. */
+  final public void enable_tracing() {
+  }
+
+  /** Disable tracing. */
+  final public void disable_tracing() {
+  }
+
+}
diff --git a/java/org/apache/tomcat/util/json/JSONParser.jjt 
b/java/org/apache/tomcat/util/json/JSONParser.jjt
new file mode 100644
index 0000000000..39a9432862
--- /dev/null
+++ b/java/org/apache/tomcat/util/json/JSONParser.jjt
@@ -0,0 +1,384 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+options {
+    CHOICE_AMBIGUITY_CHECK=3;
+    OTHER_AMBIGUITY_CHECK=2;
+    ERROR_REPORTING=true;
+    JAVA_UNICODE_ESCAPE=true;
+    UNICODE_INPUT=true;
+    IGNORE_CASE=true;
+    SUPPORT_CLASS_VISIBILITY_PUBLIC=true;
+    FORCE_LA_CHECK=true;
+    CACHE_TOKENS=true;
+    SANITY_CHECK=true;
+    STATIC=false;
+}
+
+PARSER_BEGIN(JSONParser)
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.tomcat.util.json;
+
+/**
+* Basic JSON parser generated by JavaCC. It consumes the input provided 
through the constructor when
+* {@code parseObject()}, {@code parseList()}, or {@code parse()} are called, 
and there is no way to directly
+* reset the state.
+*/
+@SuppressWarnings("all") // Ignore warnings in generated code
+public class JSONParser {
+
+    protected static final org.apache.tomcat.util.res.StringManager sm = 
org.apache.tomcat.util.res.StringManager.getManager(JSONParser.class);
+
+    private boolean nativeNumbers = false;
+
+    public JSONParser(String input) {
+        this(new java.io.StringReader(input));
+    }
+
+    /**
+     * Parses a JSON object into a Java {@code Map}.
+     */
+    public java.util.LinkedHashMap<String, Object> parseObject() throws 
ParseException {
+        java.util.LinkedHashMap<String, Object> toReturn = object();
+        if (!ensureEOF()) {
+            throw new 
IllegalStateException(sm.getString("parser.expectedEOF"));
+        }
+        return toReturn;
+    }
+
+    /**
+     * Parses a JSON array into a Java {@code List}.
+     */
+    public java.util.ArrayList<Object> parseArray() throws ParseException {
+        java.util.ArrayList<Object> toReturn = list();
+        if (!ensureEOF()) {
+            throw new 
IllegalStateException(sm.getString("parser.expectedEOF"));
+        }
+        return toReturn;
+    }
+
+    /**
+     * Parses any JSON-parsable object, returning the value.
+     */
+    public Object parse() throws ParseException {
+        Object toReturn = anything();
+        if (!ensureEOF()) {
+            throw new 
IllegalStateException(sm.getString("parser.expectedEOF"));
+        }
+        return toReturn;
+    }
+
+    private static String substringBefore(String str, char delim) {
+        int pos = str.indexOf(delim);
+        if (pos == -1) {
+            return str;
+        }
+        return str.substring(0, pos);
+    }
+
+    public void setNativeNumbers(boolean value) {
+        this.nativeNumbers = value;
+    }
+
+    public boolean getNativeNumbers() {
+        return this.nativeNumbers;
+    }
+
+}
+
+PARSER_END(JSONParser)
+
+// Ignore comments
+SKIP: {
+    <C_SINGLE_COMMENT: "//" (~["\n","\r","\f"])* <EOL>>
+| <C_MULTILINE_COMMENT: "/*" (~[])* "*/">
+| <SH_SINGLE_COMMENT: "#" (~["\n","\r","\f"])* <EOL>>
+| <WHITESPACE: " " | "\t">
+| <EOL: "\n" | "\r" | "\f">
+}
+
+// Common tokens
+TOKEN: {
+    <COMMA: ",">
+}
+
+// Object tokens
+TOKEN:{
+    <BRACE_OPEN: "{">
+| <BRACE_CLOSE: "}">
+| <COLON: ":">
+}
+
+// Array tokens
+TOKEN:{
+    <BRACKET_OPEN: "[">
+| <BRACKET_CLOSE: "]">
+}
+
+// Number token
+TOKEN:{
+    <#ZERO: "0">
+| <#DIGIT_NONZERO: ["1"-"9"]>
+| <#DIGIT: (<DIGIT_NONZERO> | <ZERO>) >
+| <NUMBER_INTEGER:
+        ("-")?
+        ( (<ZERO>)+ | ( <DIGIT_NONZERO> (<DIGIT>)* ) )
+    >
+| <NUMBER_DECIMAL:
+        ("-")?
+        ( (<ZERO>)+ | ( <DIGIT_NONZERO> (<DIGIT>)* ) )
+        ("."
+            (<DIGIT>)+
+            (
+                ["e","E"]
+                ("+" | "-")?
+                (<DIGIT>)+
+            )?
+        )
+    >
+}
+
+// Boolean tokens
+TOKEN:{
+    <TRUE: "true">
+| <FALSE: "false">
+}
+
+// Null token
+TOKEN:{
+    <NULL: "null">
+}
+
+// String tokens
+TOKEN:{
+    <#QUOTE_DOUBLE: "\"">
+| <#QUOTE_SINGLE: "'">
+| <STRING_SINGLE_EMPTY: "''">
+| <STRING_DOUBLE_EMPTY: "\"\"">
+| <#STRING_SINGLE_BODY: (
+        (~["'","\\","\r","\n","\f","\t"]) |
+        ( "\\" ( "r" | "n" | "f" | "\\" | "/" | "'" | "b" | "t" ) )
+    )+>
+| <#STRING_DOUBLE_BODY: (
+        (~["\"","\\","\r","\n","\f","\t"]) |
+        ( "\\" ( "r" | "n" | "f" | "\\" | "/" | "\"" | "b" | "t" ) )
+    )+>
+| <STRING_SINGLE_NONEMPTY: <QUOTE_SINGLE> <STRING_SINGLE_BODY> <QUOTE_SINGLE>>
+| <STRING_DOUBLE_NONEMPTY: <QUOTE_DOUBLE> <STRING_DOUBLE_BODY> <QUOTE_DOUBLE>>
+}
+
+// Raw symbol tokens
+TOKEN:{
+    <SYMBOL: (["a"-"z", "A"-"Z", "0", "1"-"9"])+ >
+}
+
+
+boolean ensureEOF() : {}{
+    <EOF>
+    { return true; }
+}
+
+Object anything() : {
+    Object x;
+}{
+    ( x = object()
+    | x = list()
+    | x = value()
+    )
+    { return x; }
+}
+
+String objectKey() : {
+    Object o;
+    String key;
+} {
+    (
+        key = string()
+    | key = symbol()
+    | (
+        nullValue()
+        { key = null; }
+        )
+    | (
+            ( o = booleanValue() | o = number() )
+            { key = o.toString(); }
+        )
+    )
+    { return key; }
+}
+
+java.util.LinkedHashMap<String, Object> object() : {
+    final java.util.LinkedHashMap<String, Object> map = new 
java.util.LinkedHashMap<String, Object>();
+    String key;
+    Object value;
+}{
+    <BRACE_OPEN>
+    [
+        key = objectKey()
+        <COLON>
+        value = anything()
+        { map.put(key, value); }
+        { key = null; value = null; }
+        (
+            <COMMA>
+            key = objectKey()
+            <COLON>
+            value = anything()
+            { map.put(key, value); }
+            { key = null; value = null; }
+        )*
+    ]
+    <BRACE_CLOSE>
+    { return map; }
+}
+
+java.util.ArrayList<Object> list() : {
+    final java.util.ArrayList<Object> list = new java.util.ArrayList<Object>();
+    Object value;
+}{
+    <BRACKET_OPEN>
+    [
+        value = anything()
+        { list.add(value); }
+        { value = null; }
+        (
+            <COMMA>
+            value = anything()
+            { list.add(value); }
+            { value = null; }
+        )*
+    ]
+    <BRACKET_CLOSE>
+    {
+        list.trimToSize();
+        return list;
+    }
+}
+
+Object value() : {
+    Object x;
+}{
+    ( x = string()
+    | x = number()
+    | x = booleanValue()
+    | x = nullValue()
+    )
+    { return x; }
+}
+
+Object nullValue(): {}{
+    <NULL>
+    { return null; }
+}
+
+Boolean booleanValue(): {
+    Boolean b;
+}{
+    (
+        (
+            <TRUE>
+            { b = Boolean.TRUE; }
+        ) | (
+            <FALSE>
+            { b = Boolean.FALSE; }
+        )
+    )
+    { return b; }
+}
+
+Number number(): {
+    Token t;
+}{
+    (
+        t = <NUMBER_DECIMAL>
+        {
+            if (nativeNumbers) {
+                return Long.valueOf(t.image);
+            } else {
+                return new java.math.BigDecimal(t.image);
+            }
+        }
+    ) | (
+        t = <NUMBER_INTEGER>
+        {
+            if (nativeNumbers) {
+                return Double.valueOf(t.image);
+            } else {
+                return new java.math.BigInteger(substringBefore(t.image, '.'));
+            }
+        }
+    )
+}
+
+String string() : {
+    String s;
+}{
+    ( s = doubleQuoteString()
+    | s = singleQuoteString()
+    )
+    { return s; }
+}
+
+String doubleQuoteString() : {
+}{
+    (
+        <STRING_DOUBLE_EMPTY>
+        { return ""; }
+    ) | (
+        <STRING_DOUBLE_NONEMPTY>
+        {
+            String image = token.image;
+            return image.substring(1, image.length() - 1);
+        }
+    )
+}
+
+String singleQuoteString() : {
+}{
+    (
+        <STRING_SINGLE_EMPTY>
+        { return ""; }
+    ) | (
+        <STRING_SINGLE_NONEMPTY>
+        {
+            String image = token.image;
+            return image.substring(1, image.length() - 1);
+        }
+    )
+}
+
+String symbol() : {
+}{
+    <SYMBOL>
+    { return token.image; }
+}
diff --git a/java/org/apache/tomcat/util/json/JSONParserConstants.java 
b/java/org/apache/tomcat/util/json/JSONParserConstants.java
new file mode 100644
index 0000000000..7f1315ddfa
--- /dev/null
+++ b/java/org/apache/tomcat/util/json/JSONParserConstants.java
@@ -0,0 +1,122 @@
+/* Generated By:JavaCC: Do not edit this line. JSONParserConstants.java */
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.tomcat.util.json;
+
+
+/**
+ * Token literal values and constants.
+ * Generated by org.javacc.parser.OtherFilesGen#start()
+ */
+public interface JSONParserConstants {
+
+  /** End of File. */
+  int EOF = 0;
+  /** RegularExpression Id. */
+  int C_SINGLE_COMMENT = 1;
+  /** RegularExpression Id. */
+  int C_MULTILINE_COMMENT = 2;
+  /** RegularExpression Id. */
+  int SH_SINGLE_COMMENT = 3;
+  /** RegularExpression Id. */
+  int WHITESPACE = 4;
+  /** RegularExpression Id. */
+  int EOL = 5;
+  /** RegularExpression Id. */
+  int COMMA = 6;
+  /** RegularExpression Id. */
+  int BRACE_OPEN = 7;
+  /** RegularExpression Id. */
+  int BRACE_CLOSE = 8;
+  /** RegularExpression Id. */
+  int COLON = 9;
+  /** RegularExpression Id. */
+  int BRACKET_OPEN = 10;
+  /** RegularExpression Id. */
+  int BRACKET_CLOSE = 11;
+  /** RegularExpression Id. */
+  int ZERO = 12;
+  /** RegularExpression Id. */
+  int DIGIT_NONZERO = 13;
+  /** RegularExpression Id. */
+  int DIGIT = 14;
+  /** RegularExpression Id. */
+  int NUMBER_INTEGER = 15;
+  /** RegularExpression Id. */
+  int NUMBER_DECIMAL = 16;
+  /** RegularExpression Id. */
+  int TRUE = 17;
+  /** RegularExpression Id. */
+  int FALSE = 18;
+  /** RegularExpression Id. */
+  int NULL = 19;
+  /** RegularExpression Id. */
+  int QUOTE_DOUBLE = 20;
+  /** RegularExpression Id. */
+  int QUOTE_SINGLE = 21;
+  /** RegularExpression Id. */
+  int STRING_SINGLE_EMPTY = 22;
+  /** RegularExpression Id. */
+  int STRING_DOUBLE_EMPTY = 23;
+  /** RegularExpression Id. */
+  int STRING_SINGLE_BODY = 24;
+  /** RegularExpression Id. */
+  int STRING_DOUBLE_BODY = 25;
+  /** RegularExpression Id. */
+  int STRING_SINGLE_NONEMPTY = 26;
+  /** RegularExpression Id. */
+  int STRING_DOUBLE_NONEMPTY = 27;
+  /** RegularExpression Id. */
+  int SYMBOL = 28;
+
+  /** Lexical state. */
+  int DEFAULT = 0;
+
+  /** Literal token values. */
+  String[] tokenImage = {
+    "<EOF>",
+    "<C_SINGLE_COMMENT>",
+    "<C_MULTILINE_COMMENT>",
+    "<SH_SINGLE_COMMENT>",
+    "<WHITESPACE>",
+    "<EOL>",
+    "\",\"",
+    "\"{\"",
+    "\"}\"",
+    "\":\"",
+    "\"[\"",
+    "\"]\"",
+    "\"0\"",
+    "<DIGIT_NONZERO>",
+    "<DIGIT>",
+    "<NUMBER_INTEGER>",
+    "<NUMBER_DECIMAL>",
+    "\"true\"",
+    "\"false\"",
+    "\"null\"",
+    "\"\\\"\"",
+    "\"\\\'\"",
+    "\"\\\'\\\'\"",
+    "\"\\\"\\\"\"",
+    "<STRING_SINGLE_BODY>",
+    "<STRING_DOUBLE_BODY>",
+    "<STRING_SINGLE_NONEMPTY>",
+    "<STRING_DOUBLE_NONEMPTY>",
+    "<SYMBOL>",
+  };
+
+}
diff --git a/java/org/apache/tomcat/util/json/JSONParserTokenManager.java 
b/java/org/apache/tomcat/util/json/JSONParserTokenManager.java
new file mode 100644
index 0000000000..adf29f7e7f
--- /dev/null
+++ b/java/org/apache/tomcat/util/json/JSONParserTokenManager.java
@@ -0,0 +1,869 @@
+/* JSONParserTokenManager.java */
+/* Generated By:JavaCC: Do not edit this line. JSONParserTokenManager.java */
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.tomcat.util.json;
+
+/** Token Manager. */
+@SuppressWarnings("all") // Ignore warnings in generated code
+public class JSONParserTokenManager implements JSONParserConstants {
+
+  /** Debug output. */
+  public  java.io.PrintStream debugStream = System.out;
+  /** Set debug output. */
+  public  void setDebugStream(java.io.PrintStream ds) { debugStream = ds; }
+private final int jjStopStringLiteralDfa_0(int pos, long active0){
+   switch (pos)
+   {
+      case 0:
+         if ((active0 & 0xe0000L) != 0L)
+         {
+            jjmatchedKind = 28;
+            return 15;
+         }
+         if ((active0 & 0x400000L) != 0L) {
+          return 38;
+        }
+         if ((active0 & 0x800000L) != 0L) {
+          return 39;
+        }
+         return -1;
+      case 1:
+         if ((active0 & 0xe0000L) != 0L)
+         {
+            jjmatchedKind = 28;
+            jjmatchedPos = 1;
+            return 15;
+         }
+         return -1;
+      case 2:
+         if ((active0 & 0xe0000L) != 0L)
+         {
+            jjmatchedKind = 28;
+            jjmatchedPos = 2;
+            return 15;
+         }
+         return -1;
+      case 3:
+         if ((active0 & 0xa0000L) != 0L) {
+          return 15;
+        }
+         if ((active0 & 0x40000L) != 0L)
+         {
+            jjmatchedKind = 28;
+            jjmatchedPos = 3;
+            return 15;
+         }
+         return -1;
+      default :
+         return -1;
+   }
+}
+private final int jjStartNfa_0(int pos, long active0){
+   return jjMoveNfa_0(jjStopStringLiteralDfa_0(pos, active0), pos + 1);
+}
+private int jjStopAtPos(int pos, int kind)
+{
+   jjmatchedKind = kind;
+   jjmatchedPos = pos;
+   return pos + 1;
+}
+private int jjMoveStringLiteralDfa0_0(){
+   switch(curChar)
+   {
+      case 34:
+         return jjMoveStringLiteralDfa1_0(0x800000L);
+      case 39:
+         return jjMoveStringLiteralDfa1_0(0x400000L);
+      case 44:
+         return jjStopAtPos(0, 6);
+      case 58:
+         return jjStopAtPos(0, 9);
+      case 91:
+         return jjStopAtPos(0, 10);
+      case 93:
+         return jjStopAtPos(0, 11);
+      case 70:
+      case 102:
+         return jjMoveStringLiteralDfa1_0(0x40000L);
+      case 78:
+      case 110:
+         return jjMoveStringLiteralDfa1_0(0x80000L);
+      case 84:
+      case 116:
+         return jjMoveStringLiteralDfa1_0(0x20000L);
+      case 123:
+         return jjStopAtPos(0, 7);
+      case 125:
+         return jjStopAtPos(0, 8);
+      default :
+         return jjMoveNfa_0(0, 0);
+   }
+}
+private int jjMoveStringLiteralDfa1_0(long active0){
+   try { curChar = input_stream.readChar(); }
+   catch(java.io.IOException e) {
+      jjStopStringLiteralDfa_0(0, active0);
+      return 1;
+   }
+   switch(curChar)
+   {
+      case 34:
+         if ((active0 & 0x800000L) != 0L) {
+          return jjStopAtPos(1, 23);
+        }
+         break;
+      case 39:
+         if ((active0 & 0x400000L) != 0L) {
+          return jjStopAtPos(1, 22);
+        }
+         break;
+      case 65:
+      case 97:
+         return jjMoveStringLiteralDfa2_0(active0, 0x40000L);
+      case 82:
+      case 114:
+         return jjMoveStringLiteralDfa2_0(active0, 0x20000L);
+      case 85:
+      case 117:
+         return jjMoveStringLiteralDfa2_0(active0, 0x80000L);
+      default :
+         break;
+   }
+   return jjStartNfa_0(0, active0);
+}
+private int jjMoveStringLiteralDfa2_0(long old0, long active0){
+   if (((active0 &= old0)) == 0L) {
+    return jjStartNfa_0(0, old0);
+  }
+   try { curChar = input_stream.readChar(); }
+   catch(java.io.IOException e) {
+      jjStopStringLiteralDfa_0(1, active0);
+      return 2;
+   }
+   switch(curChar)
+   {
+      case 76:
+      case 108:
+         return jjMoveStringLiteralDfa3_0(active0, 0xc0000L);
+      case 85:
+      case 117:
+         return jjMoveStringLiteralDfa3_0(active0, 0x20000L);
+      default :
+         break;
+   }
+   return jjStartNfa_0(1, active0);
+}
+private int jjMoveStringLiteralDfa3_0(long old0, long active0){
+   if (((active0 &= old0)) == 0L) {
+    return jjStartNfa_0(1, old0);
+  }
+   try { curChar = input_stream.readChar(); }
+   catch(java.io.IOException e) {
+      jjStopStringLiteralDfa_0(2, active0);
+      return 3;
+   }
+   switch(curChar)
+   {
+      case 69:
+      case 101:
+         if ((active0 & 0x20000L) != 0L) {
+          return jjStartNfaWithStates_0(3, 17, 15);
+        }
+         break;
+      case 76:
+      case 108:
+         if ((active0 & 0x80000L) != 0L) {
+          return jjStartNfaWithStates_0(3, 19, 15);
+        }
+         break;
+      case 83:
+      case 115:
+         return jjMoveStringLiteralDfa4_0(active0, 0x40000L);
+      default :
+         break;
+   }
+   return jjStartNfa_0(2, active0);
+}
+private int jjMoveStringLiteralDfa4_0(long old0, long active0){
+   if (((active0 &= old0)) == 0L) {
+    return jjStartNfa_0(2, old0);
+  }
+   try { curChar = input_stream.readChar(); }
+   catch(java.io.IOException e) {
+      jjStopStringLiteralDfa_0(3, active0);
+      return 4;
+   }
+   switch(curChar)
+   {
+      case 69:
+      case 101:
+         if ((active0 & 0x40000L) != 0L) {
+          return jjStartNfaWithStates_0(4, 18, 15);
+        }
+         break;
+      default :
+         break;
+   }
+   return jjStartNfa_0(3, active0);
+}
+private int jjStartNfaWithStates_0(int pos, int kind, int state)
+{
+   jjmatchedKind = kind;
+   jjmatchedPos = pos;
+   try { curChar = input_stream.readChar(); }
+   catch(java.io.IOException e) { return pos + 1; }
+   return jjMoveNfa_0(state, pos + 1);
+}
+static final long[] jjbitVec0 = {
+   0xfffffffffffffffeL, 0xffffffffffffffffL, 0xffffffffffffffffL, 
0xffffffffffffffffL
+};
+static final long[] jjbitVec2 = {
+   0x0L, 0x0L, 0xffffffffffffffffL, 0xffffffffffffffffL
+};
+private int jjMoveNfa_0(int startState, int curPos)
+{
+   int startsAt = 0;
+   jjnewStateCnt = 38;
+   int i = 1;
+   jjstateSet[0] = startState;
+   int kind = 0x7fffffff;
+   for (;;)
+   {
+      if (++jjround == 0x7fffffff) {
+        ReInitRounds();
+      }
+      if (curChar < 64)
+      {
+         long l = 1L << curChar;
+         do
+         {
+            switch(jjstateSet[--i])
+            {
+               case 0:
+                  if ((0x3ff000000000000L & l) != 0L)
+                  {
+                     if (kind > 28) {
+                      kind = 28;
+                    }
+                     { jjCheckNAdd(15); }
+                  }
+                  else if ((0x3400L & l) != 0L)
+                  {
+                     if (kind > 5) {
+                      kind = 5;
+                    }
+                  }
+                  else if ((0x100000200L & l) != 0L)
+                  {
+                     if (kind > 4) {
+                      kind = 4;
+                    }
+                  }
+                  else if (curChar == 45)
+                     { jjCheckNAddStates(0, 3); }
+                  else if (curChar == 47)
+                     { jjAddStates(4, 5); }
+                  else if (curChar == 34)
+                     { jjCheckNAddTwoStates(11, 12); }
+                  else if (curChar == 39)
+                     { jjCheckNAddTwoStates(6, 7); }
+                  else if (curChar == 35)
+                     { jjCheckNAddTwoStates(1, 2); }
+                  if ((0x3fe000000000000L & l) != 0L)
+                  {
+                     if (kind > 15) {
+                      kind = 15;
+                    }
+                     { jjCheckNAddStates(6, 8); }
+                  }
+                  else if (curChar == 48)
+                  {
+                     if (kind > 15) {
+                      kind = 15;
+                    }
+                     { jjCheckNAddStates(9, 11); }
+                  }
+                  break;
+               case 38:
+               case 6:
+                  if ((0xffffff7fffffc9ffL & l) != 0L)
+                     { jjCheckNAddStates(12, 14); }
+                  break;
+               case 39:
+               case 11:
+                  if ((0xfffffffbffffc9ffL & l) != 0L)
+                     { jjCheckNAddStates(15, 17); }
+                  break;
+               case 1:
+                  if ((0xffffffffffffcbffL & l) != 0L)
+                     { jjCheckNAddTwoStates(1, 2); }
+                  break;
+               case 2:
+                  if ((0x3400L & l) != 0L && kind > 3) {
+                    kind = 3;
+                  }
+                  break;
+               case 3:
+                  if ((0x100000200L & l) != 0L && kind > 4) {
+                    kind = 4;
+                  }
+                  break;
+               case 4:
+                  if ((0x3400L & l) != 0L && kind > 5) {
+                    kind = 5;
+                  }
+                  break;
+               case 5:
+                  if (curChar == 39)
+                     { jjCheckNAddTwoStates(6, 7); }
+                  break;
+               case 8:
+                  if ((0x808000000000L & l) != 0L)
+                     { jjCheckNAddStates(12, 14); }
+                  break;
+               case 9:
+                  if (curChar == 39 && kind > 26) {
+                    kind = 26;
+                  }
+                  break;
+               case 10:
+                  if (curChar == 34)
+                     { jjCheckNAddTwoStates(11, 12); }
+                  break;
+               case 13:
+                  if ((0x800400000000L & l) != 0L)
+                     { jjCheckNAddStates(15, 17); }
+                  break;
+               case 14:
+                  if (curChar == 34 && kind > 27) {
+                    kind = 27;
+                  }
+                  break;
+               case 15:
+                  if ((0x3ff000000000000L & l) == 0L) {
+                    break;
+                  }
+                  if (kind > 28) {
+                    kind = 28;
+                  }
+                  { jjCheckNAdd(15); }
+                  break;
+               case 16:
+                  if (curChar == 47)
+                     { jjAddStates(4, 5); }
+                  break;
+               case 17:
+                  if (curChar == 47)
+                     { jjCheckNAddTwoStates(18, 19); }
+                  break;
+               case 18:
+                  if ((0xffffffffffffcbffL & l) != 0L)
+                     { jjCheckNAddTwoStates(18, 19); }
+                  break;
+               case 19:
+                  if ((0x3400L & l) != 0L && kind > 1) {
+                    kind = 1;
+                  }
+                  break;
+               case 20:
+                  if (curChar == 42)
+                     { jjCheckNAddTwoStates(21, 23); }
+                  break;
+               case 21:
+                  { jjCheckNAddTwoStates(21, 23); }
+                  break;
+               case 22:
+                  if (curChar == 47 && kind > 2) {
+                    kind = 2;
+                  }
+                  break;
+               case 23:
+                  if (curChar == 42) {
+                    jjstateSet[jjnewStateCnt++] = 22;
+                  }
+                  break;
+               case 24:
+                  if (curChar == 45)
+                     { jjCheckNAddStates(0, 3); }
+                  break;
+               case 25:
+                  if (curChar != 48) {
+                    break;
+                  }
+                  if (kind > 15) {
+                    kind = 15;
+                  }
+                  { jjCheckNAdd(25); }
+                  break;
+               case 26:
+                  if ((0x3fe000000000000L & l) == 0L) {
+                    break;
+                  }
+                  if (kind > 15) {
+                    kind = 15;
+                  }
+                  { jjCheckNAdd(27); }
+                  break;
+               case 27:
+                  if ((0x3ff000000000000L & l) == 0L) {
+                    break;
+                  }
+                  if (kind > 15) {
+                    kind = 15;
+                  }
+                  { jjCheckNAdd(27); }
+                  break;
+               case 28:
+                  if (curChar == 48)
+                     { jjCheckNAddTwoStates(28, 29); }
+                  break;
+               case 29:
+                  if (curChar == 46)
+                     { jjCheckNAdd(30); }
+                  break;
+               case 30:
+                  if ((0x3ff000000000000L & l) == 0L) {
+                    break;
+                  }
+                  if (kind > 16) {
+                    kind = 16;
+                  }
+                  { jjCheckNAddTwoStates(30, 31); }
+                  break;
+               case 32:
+                  if ((0x280000000000L & l) != 0L)
+                     { jjCheckNAdd(33); }
+                  break;
+               case 33:
+                  if ((0x3ff000000000000L & l) == 0L) {
+                    break;
+                  }
+                  if (kind > 16) {
+                    kind = 16;
+                  }
+                  { jjCheckNAdd(33); }
+                  break;
+               case 34:
+                  if ((0x3fe000000000000L & l) != 0L)
+                     { jjCheckNAddTwoStates(35, 29); }
+                  break;
+               case 35:
+                  if ((0x3ff000000000000L & l) != 0L)
+                     { jjCheckNAddTwoStates(35, 29); }
+                  break;
+               case 36:
+                  if (curChar != 48) {
+                    break;
+                  }
+                  if (kind > 15) {
+                    kind = 15;
+                  }
+                  { jjCheckNAddStates(9, 11); }
+                  break;
+               case 37:
+                  if ((0x3fe000000000000L & l) == 0L) {
+                    break;
+                  }
+                  if (kind > 15) {
+                    kind = 15;
+                  }
+                  { jjCheckNAddStates(6, 8); }
+                  break;
+               default : break;
+            }
+         } while(i != startsAt);
+      }
+      else if (curChar < 128)
+      {
+         long l = 1L << (curChar & 077);
+         do
+         {
+            switch(jjstateSet[--i])
+            {
+               case 0:
+               case 15:
+                  if ((0x7fffffe07fffffeL & l) == 0L) {
+                    break;
+                  }
+                  if (kind > 28) {
+                    kind = 28;
+                  }
+                  { jjCheckNAdd(15); }
+                  break;
+               case 38:
+                  if ((0xffffffffefffffffL & l) != 0L)
+                     { jjCheckNAddStates(12, 14); }
+                  else if (curChar == 92) {
+                    jjstateSet[jjnewStateCnt++] = 8;
+                  }
+                  break;
+               case 39:
+                  if ((0xffffffffefffffffL & l) != 0L)
+                     { jjCheckNAddStates(15, 17); }
+                  else if (curChar == 92) {
+                    jjstateSet[jjnewStateCnt++] = 13;
+                  }
+                  break;
+               case 1:
+                  { jjAddStates(18, 19); }
+                  break;
+               case 6:
+                  if ((0xffffffffefffffffL & l) != 0L)
+                     { jjCheckNAddStates(12, 14); }
+                  break;
+               case 7:
+                  if (curChar == 92) {
+                    jjstateSet[jjnewStateCnt++] = 8;
+                  }
+                  break;
+               case 8:
+                  if ((0x14404410144044L & l) != 0L)
+                     { jjCheckNAddStates(12, 14); }
+                  break;
+               case 11:
+                  if ((0xffffffffefffffffL & l) != 0L)
+                     { jjCheckNAddStates(15, 17); }
+                  break;
+               case 12:
+                  if (curChar == 92) {
+                    jjstateSet[jjnewStateCnt++] = 13;
+                  }
+                  break;
+               case 13:
+                  if ((0x14404410144044L & l) != 0L)
+                     { jjCheckNAddStates(15, 17); }
+                  break;
+               case 18:
+                  { jjAddStates(20, 21); }
+                  break;
+               case 21:
+                  { jjAddStates(22, 23); }
+                  break;
+               case 31:
+                  if ((0x2000000020L & l) != 0L)
+                     { jjAddStates(24, 25); }
+                  break;
+               default : break;
+            }
+         } while(i != startsAt);
+      } else {
+         int hiByte = (curChar >> 8);
+         int i1 = hiByte >> 6;
+         long l1 = 1L << (hiByte & 077);
+         int i2 = (curChar & 0xff) >> 6;
+         long l2 = 1L << (curChar & 077);
+         do
+         {
+            switch(jjstateSet[--i])
+            {
+               case 38:
+               case 6:
+                  if (jjCanMove_0(hiByte, i1, i2, l1, l2))
+                     { jjCheckNAddStates(12, 14); }
+                  break;
+               case 39:
+               case 11:
+                  if (jjCanMove_0(hiByte, i1, i2, l1, l2))
+                     { jjCheckNAddStates(15, 17); }
+                  break;
+               case 1:
+                  if (jjCanMove_0(hiByte, i1, i2, l1, l2))
+                     { jjAddStates(18, 19); }
+                  break;
+               case 18:
+                  if (jjCanMove_0(hiByte, i1, i2, l1, l2))
+                     { jjAddStates(20, 21); }
+                  break;
+               case 21:
+                  if (jjCanMove_0(hiByte, i1, i2, l1, l2))
+                     { jjAddStates(22, 23); }
+                  break;
+               default : if (i1 == 0 || l1 == 0 || i2 == 0 ||  l2 == 0) {
+                break;
+              } else {
+                break;
+              }
+            }
+         } while(i != startsAt);
+      }
+      if (kind != 0x7fffffff)
+      {
+         jjmatchedKind = kind;
+         jjmatchedPos = curPos;
+         kind = 0x7fffffff;
+      }
+      ++curPos;
+      if ((i = jjnewStateCnt) == (startsAt = 38 - (jjnewStateCnt = startsAt))) 
{
+        return curPos;
+      }
+      try { curChar = input_stream.readChar(); }
+      catch(java.io.IOException e) { return curPos; }
+   }
+}
+
+/** Token literal values. */
+public static final String[] jjstrLiteralImages = {
+"", null, null, null, null, null, "\54", "\173", "\175", "\72", "\133",
+"\135", null, null, null, null, null, null, null, null, null, null, "\47\47",
+"\42\42", null, null, null, null, null, };
+protected Token jjFillToken()
+{
+   final Token t;
+   final String curTokenImage;
+   final int beginLine;
+   final int endLine;
+   final int beginColumn;
+   final int endColumn;
+   String im = jjstrLiteralImages[jjmatchedKind];
+   curTokenImage = (im == null) ? input_stream.GetImage() : im;
+   beginLine = input_stream.getBeginLine();
+   beginColumn = input_stream.getBeginColumn();
+   endLine = input_stream.getEndLine();
+   endColumn = input_stream.getEndColumn();
+   t = Token.newToken(jjmatchedKind, curTokenImage);
+
+   t.beginLine = beginLine;
+   t.endLine = endLine;
+   t.beginColumn = beginColumn;
+   t.endColumn = endColumn;
+
+   return t;
+}
+static final int[] jjnextStates = {
+   25, 26, 28, 34, 17, 20, 27, 35, 29, 25, 28, 29, 6, 7, 9, 11,
+   12, 14, 1, 2, 18, 19, 21, 23, 32, 33,
+};
+private static final boolean jjCanMove_0(int hiByte, int i1, int i2, long l1, 
long l2)
+{
+   switch(hiByte)
+   {
+      case 0:
+         return ((jjbitVec2[i2] & l2) != 0L);
+      default :
+         if ((jjbitVec0[i1] & l1) != 0L) {
+          return true;
+        }
+         return false;
+   }
+}
+
+int curLexState = 0;
+int defaultLexState = 0;
+int jjnewStateCnt;
+int jjround;
+int jjmatchedPos;
+int jjmatchedKind;
+
+/** Get the next Token. */
+public Token getNextToken()
+{
+  Token matchedToken;
+  int curPos = 0;
+
+  EOFLoop :
+  for (;;)
+  {
+   try
+   {
+      curChar = input_stream.BeginToken();
+   }
+   catch(Exception e)
+   {
+      jjmatchedKind = 0;
+      jjmatchedPos = -1;
+      matchedToken = jjFillToken();
+      return matchedToken;
+   }
+
+   jjmatchedKind = 0x7fffffff;
+   jjmatchedPos = 0;
+   curPos = jjMoveStringLiteralDfa0_0();
+   if (jjmatchedKind != 0x7fffffff)
+   {
+      if (jjmatchedPos + 1 < curPos) {
+        input_stream.backup(curPos - jjmatchedPos - 1);
+      }
+      if ((jjtoToken[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 
0L)
+      {
+         matchedToken = jjFillToken();
+         return matchedToken;
+      } else {
+         continue EOFLoop;
+      }
+   }
+   int error_line = input_stream.getEndLine();
+   int error_column = input_stream.getEndColumn();
+   String error_after = null;
+   boolean EOFSeen = false;
+   try { input_stream.readChar(); input_stream.backup(1); }
+   catch (java.io.IOException e1) {
+      EOFSeen = true;
+      error_after = curPos <= 1 ? "" : input_stream.GetImage();
+      if (curChar == '\n' || curChar == '\r') {
+         error_line++;
+         error_column = 0;
+      } else {
+        error_column++;
+      }
+   }
+   if (!EOFSeen) {
+      input_stream.backup(1);
+      error_after = curPos <= 1 ? "" : input_stream.GetImage();
+   }
+   throw new TokenMgrError(EOFSeen, curLexState, error_line, error_column, 
error_after, curChar, TokenMgrError.LEXICAL_ERROR);
+  }
+}
+
+void SkipLexicalActions(Token matchedToken)
+{
+   switch(jjmatchedKind)
+   {
+      default :
+         break;
+   }
+}
+void MoreLexicalActions()
+{
+   jjimageLen += (lengthOfMatch = jjmatchedPos + 1);
+   switch(jjmatchedKind)
+   {
+      default :
+         break;
+   }
+}
+void TokenLexicalActions(Token matchedToken)
+{
+   switch(jjmatchedKind)
+   {
+      default :
+         break;
+   }
+}
+private void jjCheckNAdd(int state)
+{
+   if (jjrounds[state] != jjround)
+   {
+      jjstateSet[jjnewStateCnt++] = state;
+      jjrounds[state] = jjround;
+   }
+}
+private void jjAddStates(int start, int end)
+{
+   do {
+      jjstateSet[jjnewStateCnt++] = jjnextStates[start];
+   } while (start++ != end);
+}
+private void jjCheckNAddTwoStates(int state1, int state2)
+{
+   jjCheckNAdd(state1);
+   jjCheckNAdd(state2);
+}
+
+private void jjCheckNAddStates(int start, int end)
+{
+   do {
+      jjCheckNAdd(jjnextStates[start]);
+   } while (start++ != end);
+}
+
+    /** Constructor. */
+    public JSONParserTokenManager(JavaCharStream stream){
+
+      if (JavaCharStream.staticFlag) {
+        throw new Error("ERROR: Cannot use a static CharStream class with a 
non-static lexical analyzer.");
+      }
+
+    input_stream = stream;
+  }
+
+  /** Constructor. */
+  public JSONParserTokenManager (JavaCharStream stream, int lexState){
+    ReInit(stream);
+    SwitchTo(lexState);
+  }
+
+  /** Reinitialise parser. */
+  public void ReInit(JavaCharStream stream)
+  {
+    jjmatchedPos =
+    jjnewStateCnt =
+    0;
+    curLexState = defaultLexState;
+    input_stream = stream;
+    ReInitRounds();
+  }
+
+  private void ReInitRounds()
+  {
+    int i;
+    jjround = 0x80000001;
+    for (i = 38; i-- > 0;) {
+      jjrounds[i] = 0x80000000;
+    }
+  }
+
+  /** Reinitialise parser. */
+  public void ReInit(JavaCharStream stream, int lexState)
+  {
+    ReInit(stream);
+    SwitchTo(lexState);
+  }
+
+  /** Switch to specified lex state. */
+  public void SwitchTo(int lexState)
+  {
+    if (lexState >= 1 || lexState < 0) {
+      throw new TokenMgrError("Error: Ignoring invalid lexical state : " + 
lexState + ". State unchanged.", TokenMgrError.INVALID_LEXICAL_STATE);
+    } else {
+      curLexState = lexState;
+    }
+  }
+
+
+/** Lexer state names. */
+public static final String[] lexStateNames = {
+   "DEFAULT",
+};
+
+/** Lex State array. */
+public static final int[] jjnewLexState = {
+   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-1, -1, -1, -1, -1, -1,
+   -1, -1, -1, -1,
+};
+static final long[] jjtoToken = {
+   0x1ccf8fc1L,
+};
+static final long[] jjtoSkip = {
+   0x3eL,
+};
+static final long[] jjtoSpecial = {
+   0x0L,
+};
+static final long[] jjtoMore = {
+   0x0L,
+};
+    protected JavaCharStream  input_stream;
+
+    private final int[] jjrounds = new int[38];
+    private final int[] jjstateSet = new int[2 * 38];
+    private final StringBuilder jjimage = new StringBuilder();
+    private StringBuilder image = jjimage;
+    private int jjimageLen;
+    private int lengthOfMatch;
+    protected int curChar;
+}
diff --git a/java/org/apache/tomcat/util/json/JavaCharStream.java 
b/java/org/apache/tomcat/util/json/JavaCharStream.java
new file mode 100644
index 0000000000..65cf498b78
--- /dev/null
+++ b/java/org/apache/tomcat/util/json/JavaCharStream.java
@@ -0,0 +1,641 @@
+/* Generated By:JavaCC: Do not edit this line. JavaCharStream.java Version 7.0 
*/
+/* JavaCCOptions:STATIC=false,SUPPORT_CLASS_VISIBILITY_PUBLIC=true */
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.tomcat.util.json;
+
+/**
+ * An implementation of interface CharStream, where the stream is assumed to
+ * contain only ASCII characters (with java-like unicode escape processing).
+ */
+@SuppressWarnings("all") // Ignore warnings in generated code
+public
+class JavaCharStream
+{
+  /** Whether parser is static. */
+  public static final boolean staticFlag = false;
+
+  static final int hexval(char c) throws java.io.IOException {
+    switch(c)
+    {
+       case '0' :
+          return 0;
+       case '1' :
+          return 1;
+       case '2' :
+          return 2;
+       case '3' :
+          return 3;
+       case '4' :
+          return 4;
+       case '5' :
+          return 5;
+       case '6' :
+          return 6;
+       case '7' :
+          return 7;
+       case '8' :
+          return 8;
+       case '9' :
+          return 9;
+
+       case 'a' :
+       case 'A' :
+          return 10;
+       case 'b' :
+       case 'B' :
+          return 11;
+       case 'c' :
+       case 'C' :
+          return 12;
+       case 'd' :
+       case 'D' :
+          return 13;
+       case 'e' :
+       case 'E' :
+          return 14;
+       case 'f' :
+       case 'F' :
+          return 15;
+    }
+
+    throw new java.io.IOException(); // Should never come here
+  }
+
+/** Position in buffer. */
+  public int bufpos = -1;
+  int bufsize;
+  int available;
+  int tokenBegin;
+  protected int bufline[];
+  protected int bufcolumn[];
+
+  protected int column = 0;
+  protected int line = 1;
+
+  protected boolean prevCharIsCR = false;
+  protected boolean prevCharIsLF = false;
+
+  protected java.io.Reader inputStream;
+
+  protected char[] nextCharBuf;
+  protected char[] buffer;
+  protected int maxNextCharInd = 0;
+  protected int nextCharInd = -1;
+  protected int inBuf = 0;
+  protected int tabSize = 1;
+  protected boolean trackLineColumn = true;
+
+  public void setTabSize(int i) { tabSize = i; }
+  public int getTabSize() { return tabSize; }
+
+  protected void ExpandBuff(boolean wrapAround)
+  {
+    char[] newbuffer = new char[bufsize + 2048];
+    int newbufline[] = new int[bufsize + 2048];
+    int newbufcolumn[] = new int[bufsize + 2048];
+
+    try
+    {
+      if (wrapAround)
+      {
+        System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - 
tokenBegin);
+        System.arraycopy(buffer, 0, newbuffer, bufsize - tokenBegin, bufpos);
+        buffer = newbuffer;
+
+        System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - 
tokenBegin);
+        System.arraycopy(bufline, 0, newbufline, bufsize - tokenBegin, bufpos);
+        bufline = newbufline;
+
+        System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - 
tokenBegin);
+        System.arraycopy(bufcolumn, 0, newbufcolumn, bufsize - tokenBegin, 
bufpos);
+        bufcolumn = newbufcolumn;
+
+        bufpos += (bufsize - tokenBegin);
+    } else {
+        System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - 
tokenBegin);
+        buffer = newbuffer;
+
+        System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - 
tokenBegin);
+        bufline = newbufline;
+
+        System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - 
tokenBegin);
+        bufcolumn = newbufcolumn;
+
+        bufpos -= tokenBegin;
+      }
+    }
+    catch (Throwable t)
+    {
+      throw new Error(t.getMessage());
+    }
+
+    available = (bufsize += 2048);
+    tokenBegin = 0;
+  }
+
+  protected void FillBuff() throws java.io.IOException
+  {
+    int i;
+    if (maxNextCharInd == 4096) {
+      maxNextCharInd = nextCharInd = 0;
+    }
+
+    try {
+      if ((i = inputStream.read(nextCharBuf, maxNextCharInd,
+                                          4096 - maxNextCharInd)) == -1)
+      {
+        inputStream.close();
+        throw new java.io.IOException();
+      } else {
+        maxNextCharInd += i;
+      }
+      return;
+    }
+    catch(java.io.IOException e) {
+      if (bufpos != 0)
+      {
+        --bufpos;
+        backup(0);
+      } else {
+        bufline[bufpos] = line;
+        bufcolumn[bufpos] = column;
+      }
+      throw e;
+    }
+  }
+
+  protected char ReadByte() throws java.io.IOException
+  {
+    if (++nextCharInd >= maxNextCharInd) {
+      FillBuff();
+    }
+
+    return nextCharBuf[nextCharInd];
+  }
+
+/** @return starting character for token. */
+  public char BeginToken() throws java.io.IOException
+  {
+    if (inBuf > 0)
+    {
+      --inBuf;
+
+      if (++bufpos == bufsize) {
+        bufpos = 0;
+      }
+
+      tokenBegin = bufpos;
+      return buffer[bufpos];
+    }
+
+    tokenBegin = 0;
+    bufpos = -1;
+
+    return readChar();
+  }
+
+  protected void AdjustBuffSize()
+  {
+    if (available == bufsize)
+    {
+      if (tokenBegin > 2048)
+      {
+        bufpos = 0;
+        available = tokenBegin;
+      } else {
+        ExpandBuff(false);
+      }
+    }
+    else if (available > tokenBegin) {
+      available = bufsize;
+    } else if ((tokenBegin - available) < 2048) {
+      ExpandBuff(true);
+    } else {
+      available = tokenBegin;
+    }
+  }
+
+  protected void UpdateLineColumn(char c)
+  {
+    column++;
+
+    if (prevCharIsLF)
+    {
+      prevCharIsLF = false;
+      line += (column = 1);
+    }
+    else if (prevCharIsCR)
+    {
+      prevCharIsCR = false;
+      if (c == '\n')
+      {
+        prevCharIsLF = true;
+      } else {
+        line += (column = 1);
+      }
+    }
+
+    switch (c)
+    {
+      case '\r' :
+        prevCharIsCR = true;
+        break;
+      case '\n' :
+        prevCharIsLF = true;
+        break;
+      case '\t' :
+        column--;
+        column += (tabSize - (column % tabSize));
+        break;
+      default :
+        break;
+    }
+
+    bufline[bufpos] = line;
+    bufcolumn[bufpos] = column;
+  }
+
+/** Read a character. */
+  public char readChar() throws java.io.IOException
+  {
+    if (inBuf > 0)
+    {
+      --inBuf;
+
+      if (++bufpos == bufsize) {
+        bufpos = 0;
+      }
+
+      return buffer[bufpos];
+    }
+
+    char c;
+
+    if (++bufpos == available) {
+      AdjustBuffSize();
+    }
+
+    if ((buffer[bufpos] = c = ReadByte()) == '\\')
+    {
+      if (trackLineColumn) { UpdateLineColumn(c); }
+
+      int backSlashCnt = 1;
+
+      for (;;) // Read all the backslashes
+      {
+        if (++bufpos == available) {
+          AdjustBuffSize();
+        }
+
+        try
+        {
+          if ((buffer[bufpos] = c = ReadByte()) != '\\')
+          {
+            if (trackLineColumn) { UpdateLineColumn(c); }
+            // found a non-backslash char.
+            if ((c == 'u') && ((backSlashCnt & 1) == 1))
+            {
+              if (--bufpos < 0) {
+                bufpos = bufsize - 1;
+              }
+
+              break;
+            }
+
+            backup(backSlashCnt);
+            return '\\';
+          }
+        }
+        catch(java.io.IOException e)
+        {
+         // We are returning one backslash so we should only backup (count-1)
+          if (backSlashCnt > 1) {
+            backup(backSlashCnt-1);
+          }
+
+          return '\\';
+        }
+
+        if (trackLineColumn) { UpdateLineColumn(c); }
+        backSlashCnt++;
+      }
+
+      // Here, we have seen an odd number of backslash's followed by a 'u'
+      try
+      {
+        while ((c = ReadByte()) == 'u') {
+          ++column;
+        }
+
+        buffer[bufpos] = c = (char)(hexval(c) << 12 |
+                                    hexval(ReadByte()) << 8 |
+                                    hexval(ReadByte()) << 4 |
+                                    hexval(ReadByte()));
+
+        column += 4;
+      }
+      catch(java.io.IOException e)
+      {
+        throw new Error("Invalid escape character at line " + line +
+                                         " column " + column + ".");
+      }
+
+      if (backSlashCnt == 1) {
+        return c;
+      } else
+      {
+        backup(backSlashCnt - 1);
+        return '\\';
+      }
+    } else {
+      UpdateLineColumn(c);
+      return c;
+    }
+  }
+
+  @Deprecated
+  /**
+   * @deprecated
+   * @see #getEndColumn
+   */
+  public int getColumn() {
+    return bufcolumn[bufpos];
+  }
+
+  @Deprecated
+  /**
+   * @deprecated
+   * @see #getEndLine
+   */
+  public int getLine() {
+    return bufline[bufpos];
+  }
+
+/** Get end column. */
+  public int getEndColumn() {
+    return bufcolumn[bufpos];
+  }
+
+/** Get end line. */
+  public int getEndLine() {
+    return bufline[bufpos];
+  }
+
+/** @return column of token start */
+  public int getBeginColumn() {
+    return bufcolumn[tokenBegin];
+  }
+
+/** @return line number of token start */
+  public int getBeginLine() {
+    return bufline[tokenBegin];
+  }
+
+/** Retreat. */
+  public void backup(int amount) {
+
+    inBuf += amount;
+    if ((bufpos -= amount) < 0) {
+      bufpos += bufsize;
+    }
+  }
+
+/** Constructor. */
+  public JavaCharStream(java.io.Reader dstream,
+                 int startline, int startcolumn, int buffersize)
+  {
+    inputStream = dstream;
+    line = startline;
+    column = startcolumn - 1;
+
+    available = bufsize = buffersize;
+    buffer = new char[buffersize];
+    bufline = new int[buffersize];
+    bufcolumn = new int[buffersize];
+    nextCharBuf = new char[4096];
+  }
+
+/** Constructor. */
+  public JavaCharStream(java.io.Reader dstream,
+                                        int startline, int startcolumn)
+  {
+    this(dstream, startline, startcolumn, 4096);
+  }
+
+/** Constructor. */
+  public JavaCharStream(java.io.Reader dstream)
+  {
+    this(dstream, 1, 1, 4096);
+  }
+/** Reinitialise. */
+  public void ReInit(java.io.Reader dstream,
+                 int startline, int startcolumn, int buffersize)
+  {
+    inputStream = dstream;
+    line = startline;
+    column = startcolumn - 1;
+
+    if (buffer == null || buffersize != buffer.length)
+    {
+      available = bufsize = buffersize;
+      buffer = new char[buffersize];
+      bufline = new int[buffersize];
+      bufcolumn = new int[buffersize];
+      nextCharBuf = new char[4096];
+    }
+    prevCharIsLF = prevCharIsCR = false;
+    tokenBegin = inBuf = maxNextCharInd = 0;
+    nextCharInd = bufpos = -1;
+  }
+
+/** Reinitialise. */
+  public void ReInit(java.io.Reader dstream,
+                                        int startline, int startcolumn)
+  {
+    ReInit(dstream, startline, startcolumn, 4096);
+  }
+
+/** Reinitialise. */
+  public void ReInit(java.io.Reader dstream)
+  {
+    ReInit(dstream, 1, 1, 4096);
+  }
+/** Constructor. */
+  public JavaCharStream(java.io.InputStream dstream, String encoding, int 
startline,
+  int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException
+  {
+    this(encoding == null ? new java.io.InputStreamReader(dstream) : new 
java.io.InputStreamReader(dstream, encoding), startline, startcolumn, 
buffersize);
+  }
+
+/** Constructor. */
+  public JavaCharStream(java.io.InputStream dstream, int startline,
+  int startcolumn, int buffersize)
+  {
+    this(new java.io.InputStreamReader(dstream), startline, startcolumn, 4096);
+  }
+
+/** Constructor. */
+  public JavaCharStream(java.io.InputStream dstream, String encoding, int 
startline,
+                        int startcolumn) throws 
java.io.UnsupportedEncodingException
+  {
+    this(dstream, encoding, startline, startcolumn, 4096);
+  }
+
+/** Constructor. */
+  public JavaCharStream(java.io.InputStream dstream, int startline,
+                        int startcolumn)
+  {
+    this(dstream, startline, startcolumn, 4096);
+  }
+
+/** Constructor. */
+  public JavaCharStream(java.io.InputStream dstream, String encoding) throws 
java.io.UnsupportedEncodingException
+  {
+    this(dstream, encoding, 1, 1, 4096);
+  }
+
+/** Constructor. */
+  public JavaCharStream(java.io.InputStream dstream)
+  {
+    this(dstream, 1, 1, 4096);
+  }
+
+/** Reinitialise. */
+  public void ReInit(java.io.InputStream dstream, String encoding, int 
startline,
+  int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException
+  {
+    ReInit(encoding == null ? new java.io.InputStreamReader(dstream) : new 
java.io.InputStreamReader(dstream, encoding), startline, startcolumn, 
buffersize);
+  }
+
+/** Reinitialise. */
+  public void ReInit(java.io.InputStream dstream, int startline,
+  int startcolumn, int buffersize)
+  {
+    ReInit(new java.io.InputStreamReader(dstream), startline, startcolumn, 
buffersize);
+  }
+/** Reinitialise. */
+  public void ReInit(java.io.InputStream dstream, String encoding, int 
startline,
+                     int startcolumn) throws 
java.io.UnsupportedEncodingException
+  {
+    ReInit(dstream, encoding, startline, startcolumn, 4096);
+  }
+/** Reinitialise. */
+  public void ReInit(java.io.InputStream dstream, int startline,
+                     int startcolumn)
+  {
+    ReInit(dstream, startline, startcolumn, 4096);
+  }
+/** Reinitialise. */
+  public void ReInit(java.io.InputStream dstream, String encoding) throws 
java.io.UnsupportedEncodingException
+  {
+    ReInit(dstream, encoding, 1, 1, 4096);
+  }
+
+/** Reinitialise. */
+  public void ReInit(java.io.InputStream dstream)
+  {
+    ReInit(dstream, 1, 1, 4096);
+  }
+
+  /** @return token image as String */
+  public String GetImage()
+  {
+    if (bufpos >= tokenBegin) {
+      return new String(buffer, tokenBegin, bufpos - tokenBegin + 1);
+    } else {
+      return new String(buffer, tokenBegin, bufsize - tokenBegin) +
+                              new String(buffer, 0, bufpos + 1);
+    }
+  }
+
+  /** @return suffix */
+  public char[] GetSuffix(int len)
+  {
+    char[] ret = new char[len];
+
+    if ((bufpos + 1) >= len) {
+      System.arraycopy(buffer, bufpos - len + 1, ret, 0, len);
+    } else
+    {
+      System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0,
+                                                        len - bufpos - 1);
+      System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1);
+    }
+
+    return ret;
+  }
+
+  /** Set buffers back to null when finished. */
+  public void Done()
+  {
+    nextCharBuf = null;
+    buffer = null;
+    bufline = null;
+    bufcolumn = null;
+  }
+
+  /**
+   * Method to adjust line and column numbers for the start of a token.
+   */
+  public void adjustBeginLineColumn(int newLine, int newCol)
+  {
+    int start = tokenBegin;
+    int len;
+
+    if (bufpos >= tokenBegin)
+    {
+      len = bufpos - tokenBegin + inBuf + 1;
+    } else {
+      len = bufsize - tokenBegin + bufpos + 1 + inBuf;
+    }
+
+    int i = 0, j = 0, k = 0;
+    int nextColDiff = 0, columnDiff = 0;
+
+    while (i < len && bufline[j = start % bufsize] == bufline[k = ++start % 
bufsize])
+    {
+      bufline[j] = newLine;
+      nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j];
+      bufcolumn[j] = newCol + columnDiff;
+      columnDiff = nextColDiff;
+      i++;
+    }
+
+    if (i < len)
+    {
+      bufline[j] = newLine++;
+      bufcolumn[j] = newCol + columnDiff;
+
+      while (i++ < len)
+      {
+        if (bufline[j = start % bufsize] != bufline[++start % bufsize]) {
+          bufline[j] = newLine++;
+        } else {
+          bufline[j] = newLine;
+        }
+      }
+    }
+
+    line = bufline[j];
+    column = bufcolumn[j];
+  }
+  boolean getTrackLineColumn() { return trackLineColumn; }
+  void setTrackLineColumn(boolean tlc) { trackLineColumn = tlc; }
+
+}
+/* JavaCC - OriginalChecksum=58f718af3466d6064ba0132bca4fbce2 (do not edit 
this line) */
diff --git a/java/org/apache/tomcat/util/json/LocalStrings.properties 
b/java/org/apache/tomcat/util/json/LocalStrings.properties
new file mode 100644
index 0000000000..4a8717dd3f
--- /dev/null
+++ b/java/org/apache/tomcat/util/json/LocalStrings.properties
@@ -0,0 +1,16 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+
+parser.expectedEOF=Expected EOF, but still had content to parse
diff --git a/java/org/apache/tomcat/util/json/LocalStrings_de.properties 
b/java/org/apache/tomcat/util/json/LocalStrings_de.properties
new file mode 100644
index 0000000000..534d9a7770
--- /dev/null
+++ b/java/org/apache/tomcat/util/json/LocalStrings_de.properties
@@ -0,0 +1,16 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+
+parser.expectedEOF=Habe EOF erwartet, aber es gab noch weiteren Inhalt zum 
Parsen
diff --git a/java/org/apache/tomcat/util/json/LocalStrings_fr.properties 
b/java/org/apache/tomcat/util/json/LocalStrings_fr.properties
new file mode 100644
index 0000000000..4804c7e149
--- /dev/null
+++ b/java/org/apache/tomcat/util/json/LocalStrings_fr.properties
@@ -0,0 +1,16 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+
+parser.expectedEOF=L'EOF était attendue mais il y avait toujours du contenu à 
nalyser
diff --git a/java/org/apache/tomcat/util/json/LocalStrings_ja.properties 
b/java/org/apache/tomcat/util/json/LocalStrings_ja.properties
new file mode 100644
index 0000000000..a2addc0f9d
--- /dev/null
+++ b/java/org/apache/tomcat/util/json/LocalStrings_ja.properties
@@ -0,0 +1,16 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+
+parser.expectedEOF=EOFを期待しますが、解析する内容をまだ持っていました。
diff --git a/java/org/apache/tomcat/util/json/LocalStrings_ko.properties 
b/java/org/apache/tomcat/util/json/LocalStrings_ko.properties
new file mode 100644
index 0000000000..eb30a12cbc
--- /dev/null
+++ b/java/org/apache/tomcat/util/json/LocalStrings_ko.properties
@@ -0,0 +1,16 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+
+parser.expectedEOF=예상된 EOF이긴 하나, 여전히 파싱할 컨텐트들이 남아 있습니다.
diff --git a/java/org/apache/tomcat/util/json/LocalStrings_zh_CN.properties 
b/java/org/apache/tomcat/util/json/LocalStrings_zh_CN.properties
new file mode 100644
index 0000000000..f39f3c6130
--- /dev/null
+++ b/java/org/apache/tomcat/util/json/LocalStrings_zh_CN.properties
@@ -0,0 +1,16 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+
+parser.expectedEOF=期望EOF,但仍有内容需要解析
diff --git a/java/org/apache/tomcat/util/json/ParseException.java 
b/java/org/apache/tomcat/util/json/ParseException.java
new file mode 100644
index 0000000000..d569eea154
--- /dev/null
+++ b/java/org/apache/tomcat/util/json/ParseException.java
@@ -0,0 +1,212 @@
+/* Generated By:JavaCC: Do not edit this line. ParseException.java Version 7.0 
*/
+/* JavaCCOptions:KEEP_LINE_COLUMN=true */
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.tomcat.util.json;
+
+/**
+ * This exception is thrown when parse errors are encountered.
+ * You can explicitly create objects of this exception type by
+ * calling the method generateParseException in the generated
+ * parser.
+ *
+ * You can modify this class to customize your error reporting
+ * mechanisms so long as you retain the public fields.
+ */
+@SuppressWarnings("all") // Ignore warnings in generated code
+public class ParseException extends Exception {
+
+  /**
+   * The version identifier for this Serializable class.
+   * Increment only if the <i>serialized</i> form of the
+   * class changes.
+   */
+  private static final long serialVersionUID = 1L;
+
+  /**
+   * The end of line string for this machine.
+   */
+  protected static String EOL = System.getProperty("line.separator", "\n");
+
+  /**
+   * This constructor is used by the method "generateParseException"
+   * in the generated parser.  Calling this constructor generates
+   * a new object of this type with the fields "currentToken",
+   * "expectedTokenSequences", and "tokenImage" set.
+   */
+  public ParseException(Token currentTokenVal,
+                        int[][] expectedTokenSequencesVal,
+                        String[] tokenImageVal
+                       )
+  {
+    super(initialise(currentTokenVal, expectedTokenSequencesVal, 
tokenImageVal));
+    currentToken = currentTokenVal;
+    expectedTokenSequences = expectedTokenSequencesVal;
+    tokenImage = tokenImageVal;
+  }
+
+  /**
+   * The following constructors are for use by you for whatever
+   * purpose you can think of.  Constructing the exception in this
+   * manner makes the exception behave in the normal way - i.e., as
+   * documented in the class "Throwable".  The fields "errorToken",
+   * "expectedTokenSequences", and "tokenImage" do not contain
+   * relevant information.  The JavaCC generated code does not use
+   * these constructors.
+   */
+
+  public ParseException() {
+    super();
+  }
+
+  /** Constructor with message. */
+  public ParseException(String message) {
+    super(message);
+  }
+
+
+  /**
+   * This is the last token that has been consumed successfully.  If
+   * this object has been created due to a parse error, the token
+   * following this token will (therefore) be the first error token.
+   */
+  public Token currentToken;
+
+  /**
+   * Each entry in this array is an array of integers.  Each array
+   * of integers represents a sequence of tokens (by their ordinal
+   * values) that is expected at this point of the parse.
+   */
+  public int[][] expectedTokenSequences;
+
+  /**
+   * This is a reference to the "tokenImage" array of the generated
+   * parser within which the parse error occurred.  This array is
+   * defined in the generated ...Constants interface.
+   */
+  public String[] tokenImage;
+
+  /**
+   * It uses "currentToken" and "expectedTokenSequences" to generate a parse
+   * error message and returns it.  If this object has been created
+   * due to a parse error, and you do not catch it (it gets thrown
+   * from the parser) the correct error message
+   * gets displayed.
+   */
+  private static String initialise(Token currentToken,
+                           int[][] expectedTokenSequences,
+                           String[] tokenImage) {
+
+    StringBuffer expected = new StringBuffer();
+    int maxSize = 0;
+    for (int i = 0; i < expectedTokenSequences.length; i++) {
+      if (maxSize < expectedTokenSequences[i].length) {
+        maxSize = expectedTokenSequences[i].length;
+      }
+      for (int j = 0; j < expectedTokenSequences[i].length; j++) {
+        expected.append(tokenImage[expectedTokenSequences[i][j]]).append(' ');
+      }
+      if (expectedTokenSequences[i][expectedTokenSequences[i].length - 1] != 
0) {
+        expected.append("...");
+      }
+      expected.append(EOL).append("    ");
+    }
+    String retval = "Encountered \"";
+    Token tok = currentToken.next;
+    for (int i = 0; i < maxSize; i++) {
+      if (i != 0) {
+        retval += " ";
+      }
+      if (tok.kind == 0) {
+        retval += tokenImage[0];
+        break;
+      }
+      retval += " " + tokenImage[tok.kind];
+      retval += " \"";
+      retval += add_escapes(tok.image);
+      retval += " \"";
+      tok = tok.next;
+    }
+    retval += "\" at line " + currentToken.next.beginLine + ", column " + 
currentToken.next.beginColumn;
+    retval += "." + EOL;
+
+
+    if (expectedTokenSequences.length == 0) {
+        // Nothing to add here
+    } else {
+           if (expectedTokenSequences.length == 1) {
+             retval += "Was expecting:" + EOL + "    ";
+           } else {
+             retval += "Was expecting one of:" + EOL + "    ";
+           }
+           retval += expected.toString();
+    }
+
+    return retval;
+  }
+
+
+  /**
+   * Used to convert raw characters to their escaped version
+   * when these raw version cannot be used as part of an ASCII
+   * string literal.
+   */
+  static String add_escapes(String str) {
+      StringBuffer retval = new StringBuffer();
+      char ch;
+      for (int i = 0; i < str.length(); i++) {
+        switch (str.charAt(i))
+        {
+           case '\b':
+              retval.append("\\b");
+              continue;
+           case '\t':
+              retval.append("\\t");
+              continue;
+           case '\n':
+              retval.append("\\n");
+              continue;
+           case '\f':
+              retval.append("\\f");
+              continue;
+           case '\r':
+              retval.append("\\r");
+              continue;
+           case '\"':
+              retval.append("\\\"");
+              continue;
+           case '\'':
+              retval.append("\\\'");
+              continue;
+           case '\\':
+              retval.append("\\\\");
+              continue;
+           default:
+              if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
+                 String s = "0000" + Integer.toString(ch, 16);
+                 retval.append("\\u" + s.substring(s.length() - 4, 
s.length()));
+              } else {
+                 retval.append(ch);
+              }
+              continue;
+        }
+      }
+      return retval.toString();
+   }
+
+}
+/* JavaCC - OriginalChecksum=1ccce09e6dc04d17e33b6d15b9c1f0c3 (do not edit 
this line) */
diff --git a/java/org/apache/tomcat/util/json/Token.java 
b/java/org/apache/tomcat/util/json/Token.java
new file mode 100644
index 0000000000..479e14e279
--- /dev/null
+++ b/java/org/apache/tomcat/util/json/Token.java
@@ -0,0 +1,147 @@
+/* Generated By:JavaCC: Do not edit this line. Token.java Version 7.0 */
+/* 
JavaCCOptions:TOKEN_EXTENDS=,KEEP_LINE_COLUMN=true,SUPPORT_CLASS_VISIBILITY_PUBLIC=true
 */
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.tomcat.util.json;
+
+/**
+ * Describes the input token stream.
+ */
+@SuppressWarnings("all") // Ignore warnings in generated code
+public class Token implements java.io.Serializable {
+
+  /**
+   * The version identifier for this Serializable class.
+   * Increment only if the <i>serialized</i> form of the
+   * class changes.
+   */
+  private static final long serialVersionUID = 1L;
+
+  /**
+   * An integer that describes the kind of this token.  This numbering
+   * system is determined by JavaCCParser, and a table of these numbers is
+   * stored in the file ...Constants.java.
+   */
+  public int kind;
+
+  /** The line number of the first character of this Token. */
+  public int beginLine;
+  /** The column number of the first character of this Token. */
+  public int beginColumn;
+  /** The line number of the last character of this Token. */
+  public int endLine;
+  /** The column number of the last character of this Token. */
+  public int endColumn;
+
+  /**
+   * The string image of the token.
+   */
+  public String image;
+
+  /**
+   * A reference to the next regular (non-special) token from the input
+   * stream.  If this is the last token from the input stream, or if the
+   * token manager has not read tokens beyond this one, this field is
+   * set to null.  This is true only if this token is also a regular
+   * token.  Otherwise, see below for a description of the contents of
+   * this field.
+   */
+  public Token next;
+
+  /**
+   * This field is used to access special tokens that occur prior to this
+   * token, but after the immediately preceding regular (non-special) token.
+   * If there are no such special tokens, this field is set to null.
+   * When there are more than one such special token, this field refers
+   * to the last of these special tokens, which in turn refers to the next
+   * previous special token through its specialToken field, and so on
+   * until the first special token (whose specialToken field is null).
+   * The next fields of special tokens refer to other special tokens that
+   * immediately follow it (without an intervening regular token).  If there
+   * is no such token, this field is null.
+   */
+  public Token specialToken;
+
+  /**
+   * An optional attribute value of the Token.
+   * Tokens which are not used as syntactic sugar will often contain
+   * meaningful values that will be used later on by the compiler or
+   * interpreter. This attribute value is often different from the image.
+   * Any subclass of Token that actually wants to return a non-null value can
+   * override this method as appropriate.
+   */
+  public Object getValue() {
+    return null;
+  }
+
+  /**
+   * No-argument constructor
+   */
+  public Token() {}
+
+  /**
+   * Constructs a new token for the specified Image.
+   */
+  public Token(int kind)
+  {
+    this(kind, null);
+  }
+
+  /**
+   * Constructs a new token for the specified Image and Kind.
+   */
+  public Token(int kind, String image)
+  {
+    this.kind = kind;
+    this.image = image;
+  }
+
+  /**
+   * Returns the image.
+   */
+  public String toString()
+  {
+    return image;
+  }
+
+  /**
+   * Returns a new Token object, by default. However, if you want, you
+   * can create and return subclass objects based on the value of ofKind.
+   * Simply add the cases to the switch for all those special cases.
+   * For example, if you have a subclass of Token called IDToken that
+   * you want to create if ofKind is ID, simply add something like :
+   *
+   *    case MyParserConstants.ID : return new IDToken(ofKind, image);
+   *
+   * to the following switch statement. Then you can cast matchedToken
+   * variable to the appropriate type and use sit in your lexical actions.
+   */
+  public static Token newToken(int ofKind, String image)
+  {
+    switch(ofKind)
+    {
+      default : return new Token(ofKind, image);
+    }
+  }
+
+  public static Token newToken(int ofKind)
+  {
+    return newToken(ofKind, null);
+  }
+
+}
+/* JavaCC - OriginalChecksum=3fa555852689f4df3b05452671ed7031 (do not edit 
this line) */
diff --git a/java/org/apache/tomcat/util/json/TokenMgrError.java 
b/java/org/apache/tomcat/util/json/TokenMgrError.java
new file mode 100644
index 0000000000..d6f3e2b71a
--- /dev/null
+++ b/java/org/apache/tomcat/util/json/TokenMgrError.java
@@ -0,0 +1,163 @@
+/* Generated By:JavaCC: Do not edit this line. TokenMgrError.java Version 7.0 
*/
+/* JavaCCOptions: */
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.tomcat.util.json;
+
+/** Token Manager Error. */
+@SuppressWarnings("all") // Ignore warnings in generated code
+public class TokenMgrError extends Error
+{
+
+  /**
+   * The version identifier for this Serializable class.
+   * Increment only if the <i>serialized</i> form of the
+   * class changes.
+   */
+  private static final long serialVersionUID = 1L;
+
+  /*
+   * Ordinals for various reasons why an Error of this type can be thrown.
+   */
+
+  /**
+   * Lexical error occurred.
+   */
+  public static final int LEXICAL_ERROR = 0;
+
+  /**
+   * An attempt was made to create a second instance of a static token manager.
+   */
+  public static final int STATIC_LEXER_ERROR = 1;
+
+  /**
+   * Tried to change to an invalid lexical state.
+   */
+  public static final int INVALID_LEXICAL_STATE = 2;
+
+  /**
+   * Detected (and bailed out of) an infinite loop in the token manager.
+   */
+  public static final int LOOP_DETECTED = 3;
+
+  /**
+   * Indicates the reason why the exception is thrown. It will have
+   * one of the above 4 values.
+   */
+  int errorCode;
+
+  /**
+   * Replaces unprintable characters by their escaped (or unicode escaped)
+   * equivalents in the given string
+   */
+  protected static final String addEscapes(String str) {
+    StringBuffer retval = new StringBuffer();
+    char ch;
+    for (int i = 0; i < str.length(); i++) {
+      switch (str.charAt(i))
+      {
+        case '\b':
+          retval.append("\\b");
+          continue;
+        case '\t':
+          retval.append("\\t");
+          continue;
+        case '\n':
+          retval.append("\\n");
+          continue;
+        case '\f':
+          retval.append("\\f");
+          continue;
+        case '\r':
+          retval.append("\\r");
+          continue;
+        case '\"':
+          retval.append("\\\"");
+          continue;
+        case '\'':
+          retval.append("\\\'");
+          continue;
+        case '\\':
+          retval.append("\\\\");
+          continue;
+        default:
+          if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
+            String s = "0000" + Integer.toString(ch, 16);
+            retval.append("\\u" + s.substring(s.length() - 4, s.length()));
+          } else {
+            retval.append(ch);
+          }
+          continue;
+      }
+    }
+    return retval.toString();
+  }
+
+  /**
+   * Returns a detailed message for the Error when it is thrown by the
+   * token manager to indicate a lexical error.
+   * Parameters :
+   *    EOFSeen     : indicates if EOF caused the lexical error
+   *    curLexState : lexical state in which this error occurred
+   *    errorLine   : line number when the error occurred
+   *    errorColumn : column number when the error occurred
+   *    errorAfter  : prefix that was seen before this error occurred
+   *    curchar     : the offending character
+   * Note: You can customize the lexical error message by modifying this 
method.
+   */
+  protected static String LexicalErr(boolean EOFSeen, int lexState, int 
errorLine, int errorColumn, String errorAfter, int curChar) {
+    char curChar1 = (char)curChar;
+    return("Lexical error at line " +
+          errorLine + ", column " +
+          errorColumn + ".  Encountered: " +
+          (EOFSeen ? "<EOF> " : ("\"" + addEscapes(String.valueOf(curChar1)) + 
"\"") + " (" + (int)curChar + "), ") +
+          "after : \"" + addEscapes(errorAfter) + "\"");
+  }
+
+  /**
+   * You can also modify the body of this method to customize your error 
messages.
+   * For example, cases like LOOP_DETECTED and INVALID_LEXICAL_STATE are not
+   * of end-users concern, so you can return something like :
+   *
+   *     "Internal Error : Please file a bug report .... "
+   *
+   * from this method for such cases in the release version of your parser.
+   */
+  public String getMessage() {
+    return super.getMessage();
+  }
+
+  /*
+   * Constructors of various flavors follow.
+   */
+
+  /** No arg constructor. */
+  public TokenMgrError() {
+  }
+
+  /** Constructor with message and reason. */
+  public TokenMgrError(String message, int reason) {
+    super(message);
+    errorCode = reason;
+  }
+
+  /** Full Constructor. */
+  public TokenMgrError(boolean EOFSeen, int lexState, int errorLine, int 
errorColumn, String errorAfter, int curChar, int reason) {
+    this(LexicalErr(EOFSeen, lexState, errorLine, errorColumn, errorAfter, 
curChar), reason);
+  }
+}
+/* JavaCC - OriginalChecksum=7da4e668c47dee63e10c9b008699a2ca (do not edit 
this line) */


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to