On 14/09/2026 22:24, [email protected] wrote:
This is an automated email from the ASF dual-hosted git repository.

rmaucher pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tomcat.git


The following commit(s) were added to refs/heads/main by this push:
      new 5578eb98c1 Unescape quoted strings
5578eb98c1 is described below

commit 5578eb98c185d38f76b03af1994cc515892e2813
Author: remm <[email protected]>
AuthorDate: Mon Sep 14 23:24:29 2026 +0200

     Unescape quoted strings

Which version of JavaCC are you using to generate the parser? I am trying to fix an issue around double-decoding with unicode escaped '\' and can't seem to recreate the same output given the current jjt file.

Mark


---
  java/org/apache/tomcat/util/json/JSONParser.java | 32 ++++++++++++++++++++++--
  java/org/apache/tomcat/util/json/JSONParser.jjt  | 32 ++++++++++++++++++++++--
  2 files changed, 60 insertions(+), 4 deletions(-)

diff --git a/java/org/apache/tomcat/util/json/JSONParser.java 
b/java/org/apache/tomcat/util/json/JSONParser.java
index c21b0f67f9..88c880e6ee 100644
--- a/java/org/apache/tomcat/util/json/JSONParser.java
+++ b/java/org/apache/tomcat/util/json/JSONParser.java
@@ -75,6 +75,34 @@ public class JSONParser implements JSONParserConstants {
          return str.substring(0, pos);
      }
+ /**
+     * Resolve the JSON escape sequences of a string token body (the
+     * surrounding quotes are already removed). The token grammar only
+     * admits the short escapes: {@code \b}, {@code \f}, {@code \n},
+     * {@code \r}, {@code \t}, {@code \/}, {@code \\} and the
+     * self-escaped quote character.
+     */
+    private static String unescape(String value) {
+        StringBuilder result = new StringBuilder(value.length());
+        for (int i = 0; i < value.length(); i++) {
+            char c = value.charAt(i);
+            if (c != '\\' || i + 1 >= value.length()) {
+                result.append(c);
+                continue;
+            }
+            char next = value.charAt(++i);
+            switch (next) {
+                case 'b' -> result.append('\b');
+                case 'f' -> result.append('\f');
+                case 'n' -> result.append('\n');
+                case 'r' -> result.append('\r');
+                case 't' -> result.append('\t');
+                default -> result.append(next);
+            }
+        }
+        return result.toString();
+    }
+
      public void setNativeNumbers(boolean value) {
          this.nativeNumbers = value;
      }
@@ -452,7 +480,7 @@ public class JSONParser implements JSONParserConstants {
                  String image = token.image;
                  {
                      if ("" != null) {
-                        return image.substring(1, image.length() - 1);
+                        return unescape(image.substring(1, image.length() - 
1));
                      }
                  }
                  break;
@@ -481,7 +509,7 @@ public class JSONParser implements JSONParserConstants {
                  String image = token.image;
                  {
                      if ("" != null) {
-                        return image.substring(1, image.length() - 1);
+                        return unescape(image.substring(1, image.length() - 
1));
                      }
                  }
                  break;
diff --git a/java/org/apache/tomcat/util/json/JSONParser.jjt 
b/java/org/apache/tomcat/util/json/JSONParser.jjt
index 08996d10ab..1726c4cab4 100644
--- a/java/org/apache/tomcat/util/json/JSONParser.jjt
+++ b/java/org/apache/tomcat/util/json/JSONParser.jjt
@@ -106,6 +106,34 @@ public class JSONParser {
          return str.substring(0, pos);
      }
+ /**
+     * Resolve the JSON escape sequences of a string token body (the
+     * surrounding quotes are already removed). The token grammar only
+     * admits the short escapes: {@code \b}, {@code \f}, {@code \n},
+     * {@code \r}, {@code \t}, {@code \/}, {@code \\} and the
+     * self-escaped quote character.
+     */
+    private static String unescape(String value) {
+        StringBuilder result = new StringBuilder(value.length());
+        for (int i = 0; i < value.length(); i++) {
+            char c = value.charAt(i);
+            if (c != '\\' || i + 1 >= value.length()) {
+                result.append(c);
+                continue;
+            }
+            char next = value.charAt(++i);
+            switch (next) {
+                case 'b' -> result.append('\b');
+                case 'f' -> result.append('\f');
+                case 'n' -> result.append('\n');
+                case 'r' -> result.append('\r');
+                case 't' -> result.append('\t');
+                default -> result.append(next);
+            }
+        }
+        return result.toString();
+    }
+
      public void setNativeNumbers(boolean value) {
          this.nativeNumbers = value;
      }
@@ -358,7 +386,7 @@ String doubleQuoteString() : {
          <STRING_DOUBLE_NONEMPTY>
          {
              String image = token.image;
-            return image.substring(1, image.length() - 1);
+            return unescape(image.substring(1, image.length() - 1));
          }
      )
  }
@@ -372,7 +400,7 @@ String singleQuoteString() : {
          <STRING_SINGLE_NONEMPTY>
          {
              String image = token.image;
-            return image.substring(1, image.length() - 1);
+            return unescape(image.substring(1, image.length() - 1));
          }
      )
  }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to