From 80ca2ef213713f85284fa3c7b8513bf7c69e8c08 Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Mon, 12 Aug 2019 22:06:11 -0700 Subject: [PATCH] Fixed #549 --- .../fasterxml/jackson/core/JsonFactory.java | 4 +- .../fasterxml/jackson/core/io/CharTypes.java | 37 +++++++++++++++++-- .../jackson/core/json/UTF8JsonGenerator.java | 10 ++++- .../core/json/WriterBasedJsonGenerator.java | 3 ++ .../core/json/CustomQuoteCharTest.java | 8 ++-- .../jackson/core/json/TestUtf8Generator.java | 6 +-- 6 files changed, 52 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/core/JsonFactory.java b/src/main/java/com/fasterxml/jackson/core/JsonFactory.java index 6463702360..55695c913a 100644 --- a/src/main/java/com/fasterxml/jackson/core/JsonFactory.java +++ b/src/main/java/com/fasterxml/jackson/core/JsonFactory.java @@ -202,8 +202,8 @@ public static int collectDefaults() { *

* TODO: should clean up this; looks messy having 2 alternatives * with not very clear differences. - * - * @since 2.6.0 + * + * @since 2.6 */ protected final transient ByteQuadsCanonicalizer _byteSymbolCanonicalizer = ByteQuadsCanonicalizer.createRoot(); diff --git a/src/main/java/com/fasterxml/jackson/core/io/CharTypes.java b/src/main/java/com/fasterxml/jackson/core/io/CharTypes.java index 4c616fc13d..b49a13a5bc 100644 --- a/src/main/java/com/fasterxml/jackson/core/io/CharTypes.java +++ b/src/main/java/com/fasterxml/jackson/core/io/CharTypes.java @@ -161,9 +161,7 @@ public final class CharTypes // 04-Mar-2011, tatu: Used to use "-(i + 1)", replaced with constant table[i] = CharacterEscapes.ESCAPE_STANDARD; } - /* Others (and some within that range too) have explicit shorter - * sequences - */ + // Others (and some within that range too) have explicit shorter sequences table['"'] = '"'; table['\\'] = '\\'; // Escaping of slash is optional, so let's not add it @@ -210,6 +208,19 @@ public final class CharTypes */ public static int[] get7BitOutputEscapes() { return sOutputEscapes128; } + /** + * Alternative to {@link #get7BitOutputEscapes()} when a non-standard quote character + * is used. + * + * @since 2.10 + */ + public static int[] get7BitOutputEscapes(int quoteChar) { + if (quoteChar == '"') { + return sOutputEscapes128; + } + return AltEscapes.instance.escapesFor(quoteChar); + } + public static int charToHex(int ch) { return (ch > 127) ? -1 : sHexValues[ch]; @@ -255,5 +266,25 @@ public static char[] copyHexChars() { public static byte[] copyHexBytes() { return (byte[]) HB.clone(); } + + // @since 2.10 + private static class AltEscapes { + public final static AltEscapes instance = new AltEscapes(); + + private int[][] _altEscapes = new int[128][]; + + public int[] escapesFor(int quoteChar) { + int[] esc = _altEscapes[quoteChar]; + if (esc == null) { + esc = Arrays.copyOf(sOutputEscapes128, 128); + // Only add escape setting if character does not already have it + if (esc[quoteChar] == 0) { + esc[quoteChar] = CharacterEscapes.ESCAPE_STANDARD; + } + _altEscapes[quoteChar] = esc; + } + return esc; + } + } } diff --git a/src/main/java/com/fasterxml/jackson/core/json/UTF8JsonGenerator.java b/src/main/java/com/fasterxml/jackson/core/json/UTF8JsonGenerator.java index a66ea33f27..08ca5bf28b 100644 --- a/src/main/java/com/fasterxml/jackson/core/json/UTF8JsonGenerator.java +++ b/src/main/java/com/fasterxml/jackson/core/json/UTF8JsonGenerator.java @@ -122,7 +122,10 @@ public UTF8JsonGenerator(IOContext ctxt, int features, ObjectCodec codec, { super(ctxt, features, codec); _outputStream = out; - _quoteChar = (byte) quoteChar; // TODO: validate/truncate + _quoteChar = (byte) quoteChar; + if (quoteChar != '"') { // since 2.10 + _outputEscapes = CharTypes.get7BitOutputEscapes(quoteChar); + } _bufferRecyclable = true; _outputBuffer = ctxt.allocWriteEncodingBuffer(); @@ -152,7 +155,10 @@ public UTF8JsonGenerator(IOContext ctxt, int features, ObjectCodec codec, super(ctxt, features, codec); _outputStream = out; - _quoteChar = (byte) quoteChar; // TODO: validate/truncate + _quoteChar = (byte) quoteChar; + if (quoteChar != '"') { // since 2.10 + _outputEscapes = CharTypes.get7BitOutputEscapes(quoteChar); + } _bufferRecyclable = bufferRecyclable; _outputTail = outputOffset; diff --git a/src/main/java/com/fasterxml/jackson/core/json/WriterBasedJsonGenerator.java b/src/main/java/com/fasterxml/jackson/core/json/WriterBasedJsonGenerator.java index 8f82843785..a16c5feb5b 100644 --- a/src/main/java/com/fasterxml/jackson/core/json/WriterBasedJsonGenerator.java +++ b/src/main/java/com/fasterxml/jackson/core/json/WriterBasedJsonGenerator.java @@ -109,6 +109,9 @@ public WriterBasedJsonGenerator(IOContext ctxt, int features, _outputBuffer = ctxt.allocConcatBuffer(); _outputEnd = _outputBuffer.length; _quoteChar = quoteChar; + if (quoteChar != '"') { // since 2.10 + _outputEscapes = CharTypes.get7BitOutputEscapes(quoteChar); + } } /* diff --git a/src/test/java/com/fasterxml/jackson/core/json/CustomQuoteCharTest.java b/src/test/java/com/fasterxml/jackson/core/json/CustomQuoteCharTest.java index 66a94fb489..148ef58219 100644 --- a/src/test/java/com/fasterxml/jackson/core/json/CustomQuoteCharTest.java +++ b/src/test/java/com/fasterxml/jackson/core/json/CustomQuoteCharTest.java @@ -75,14 +75,14 @@ public void testAposQuotingWithCharBased() throws Exception _writeObject(g, "key", "It's \"fun\""); g.close(); // should escape apostrophes but not quotes? - assertEquals("{'key':'It\\'s' \"fun\"}", w.toString()); + assertEquals("{'key':'It\\u0027s \\\"fun\\\"'}", w.toString()); // with Array w = new StringWriter(); g = createGenerator(JSON_F, w); _writeArray(g, "It's a sin"); g.close(); - assertEquals("['It\\'s a sin']", w.toString()); + assertEquals("['It\\u0027s a sin']", w.toString()); } public void testAposQuotingWithByteBased() throws Exception @@ -96,14 +96,14 @@ public void testAposQuotingWithByteBased() throws Exception _writeObject(g, "key", "It's \"fun\""); g.close(); // should escape apostrophes but not quotes? - assertEquals("{'key':'It\\'s' \"fun\"}", out.toString("UTF-8")); + assertEquals("{'key':'It\\u0027s \\\"fun\\\"'}", out.toString("UTF-8")); // with Array out = new ByteArrayOutputStream(); g = createGenerator(JSON_F, out); _writeArray(g, "It's a sin"); g.close(); - assertEquals("['It\\'s a sin']", out.toString("UTF-8")); + assertEquals("['It\\u0027s a sin']", out.toString("UTF-8")); } private void _writeObject(JsonGenerator g, String key, String value) throws Exception { diff --git a/src/test/java/com/fasterxml/jackson/core/json/TestUtf8Generator.java b/src/test/java/com/fasterxml/jackson/core/json/TestUtf8Generator.java index 2a53a8e951..828121c76d 100644 --- a/src/test/java/com/fasterxml/jackson/core/json/TestUtf8Generator.java +++ b/src/test/java/com/fasterxml/jackson/core/json/TestUtf8Generator.java @@ -1,10 +1,6 @@ package com.fasterxml.jackson.core.json; -import com.fasterxml.jackson.core.BaseTest; -import com.fasterxml.jackson.core.JsonFactory; -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.core.JsonToken; +import com.fasterxml.jackson.core.*; import com.fasterxml.jackson.core.filter.FilteringGeneratorDelegate; import com.fasterxml.jackson.core.filter.JsonPointerBasedFilter; import com.fasterxml.jackson.core.io.IOContext;