Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions release-notes/CREDITS-2.x
Original file line number Diff line number Diff line change
Expand Up @@ -461,3 +461,9 @@ Justin Gosselin (@jgosselin-accesso)
* Reported #1359: Non-surrogate characters being incorrectly combined when
`JsonWriteFeature.COMBINE_UNICODE_SURROGATES_IN_UTF8` is enabled
(2.18.2)

Haruki (@stackunderflow111)
* Reported #1398: feature COMBINE_UNICODE_SURROGATES_IN_UTF8 doesn't work
when custom characterEscape is used
(2.18.2)

4 changes: 4 additions & 0 deletions release-notes/VERSION-2.x
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ a pure JSON library.
parsing later numbers
(fix contributed by @pjfanning)

#1398: Fix issue that feature COMBINE_UNICODE_SURROGATES_IN_UTF8 doesn't work
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for updating release notes too! :)

when custom characterEscape is used
(reported and fixed by @stackunderflow111)

2.18.2 (27-Nov-2024)

#1359: Non-surrogate characters being incorrectly combined when
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1732,6 +1732,16 @@ private final void _writeCustomStringSegment2(final char[] cbuf, int offset, fin
outputBuffer[outputPtr++] = (byte) (0xc0 | (ch >> 6));
outputBuffer[outputPtr++] = (byte) (0x80 | (ch & 0x3f));
} else {
// 3- or 4-byte character
if (_isStartOfSurrogatePair(ch)) {
final boolean combineSurrogates = Feature.COMBINE_UNICODE_SURROGATES_IN_UTF8.enabledIn(_features);
if (combineSurrogates && offset < end) {
char highSurrogate = (char) ch;
char lowSurrogate = cbuf[offset++];
outputPtr = _outputSurrogatePair(highSurrogate, lowSurrogate, outputPtr);
continue;
}
}
outputPtr = _outputMultiByteChar(ch, outputPtr);
}
}
Expand Down Expand Up @@ -1789,6 +1799,16 @@ private final void _writeCustomStringSegment2(final String text, int offset, fin
outputBuffer[outputPtr++] = (byte) (0xc0 | (ch >> 6));
outputBuffer[outputPtr++] = (byte) (0x80 | (ch & 0x3f));
} else {
// 3- or 4-byte character
if (_isStartOfSurrogatePair(ch)) {
final boolean combineSurrogates = Feature.COMBINE_UNICODE_SURROGATES_IN_UTF8.enabledIn(_features);
if (combineSurrogates && offset < end) {
char highSurrogate = (char) ch;
char lowSurrogate = text.charAt(offset++);
outputPtr = _outputSurrogatePair(highSurrogate, lowSurrogate, outputPtr);
continue;
}
}
outputPtr = _outputMultiByteChar(ch, outputPtr);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,4 +123,21 @@ void checkNonSurrogates() throws Exception {
assertTrue(json.contains("foo\u3042bar"));
assertTrue(json.contains("\"test_emoji\":\"\uD83D\uDE0A\""));
}

@Test
void checkSurrogateWithCharacterEscapes() throws Exception {
JsonFactory f = JsonFactory.builder()
.enable(JsonWriteFeature.COMBINE_UNICODE_SURROGATES_IN_UTF8)
.build();
f.setCharacterEscapes(JsonpCharacterEscapes.instance());
ByteArrayOutputStream out = new ByteArrayOutputStream();
try (JsonGenerator gen = f.createGenerator(out)) {
gen.writeStartObject();
// Outside the BMP; 0x1F60A - emoji
gen.writeStringField("test_emoji", new String(Character.toChars(0x1F60A)));
gen.writeEndObject();
}
String json = out.toString("UTF-8");
assertEquals("{\"test_emoji\":\"\uD83D\uDE0A\"}", json);
}
}