Fix #307
diff --git a/release-notes/CREDITS b/release-notes/CREDITS
index f05c389..463d97e 100644
--- a/release-notes/CREDITS
+++ b/release-notes/CREDITS
@@ -79,8 +79,12 @@
* Contributed #209: Make use of `_allowMultipleMatches` in `FilteringParserDelegate`
(2.7.4)
-
Tanguy Leroux (tlrx@github)
* Reported, contributed fix for #280: FilteringGeneratorDelegate.writeUTF8String()
should delegate to writeUTF8String()
(2.7.5)
+
+Mike Naseef (mtnaseef@github)
+ * Reported #307: JsonGenerationException: Split surrogate on writeRaw() input thrown for
+ input of a certain size
+ (2.7.7)
diff --git a/release-notes/VERSION b/release-notes/VERSION
index cdf032d..1d372a3 100644
--- a/release-notes/VERSION
+++ b/release-notes/VERSION
@@ -14,6 +14,12 @@
=== Releases ===
------------------------------------------------------------------------
+2.7.7 (not yet released)
+
+#307: JsonGenerationException: Split surrogate on writeRaw() input thrown for
+ input of a certain size
+ (reported by Mike N)
+
2.7.6 (23-Jul-2016)
- Clean up of FindBugs reported possible issues.
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 8f17ea3..a638519 100644
--- a/src/main/java/com/fasterxml/jackson/core/json/UTF8JsonGenerator.java
+++ b/src/main/java/com/fasterxml/jackson/core/json/UTF8JsonGenerator.java
@@ -515,39 +515,50 @@
*/
@Override
- public void writeRaw(String text)
- throws IOException, JsonGenerationException
- {
- int start = 0;
- int len = text.length();
- while (len > 0) {
- char[] buf = _charBuffer;
- final int blen = buf.length;
- final int len2 = (len < blen) ? len : blen;
- text.getChars(start, start+len2, buf, 0);
- writeRaw(buf, 0, len2);
- start += len2;
- len -= len2;
- }
+ public void writeRaw(String text) throws IOException {
+ writeRaw(text, 0, text.length());
}
@Override
- public void writeRaw(String text, int offset, int len)
- throws IOException, JsonGenerationException
+ public void writeRaw(String text, int offset, int len) throws IOException
{
+ final char[] buf = _charBuffer;
+
+ // minor optimization: see if we can just get and copy
+ if (len <= buf.length) {
+ text.getChars(offset, offset+len, buf, 0);
+ _writeRawSegment(buf, 0, len);
+ return;
+ }
+
+ // If not, need segmented approach. For speed, let's also use input buffer
+ // size that is guaranteed to fit in output buffer; each char can expand to
+ // at most 3 bytes, so at most 1/3 of buffer size.
+ final int maxChunk = (_outputEnd >> 2) + (_outputEnd >> 4); // == (1/4 + 1/16) == 5/16
+ final int maxBytes = maxChunk * 3;
+
while (len > 0) {
- char[] buf = _charBuffer;
- final int blen = buf.length;
- final int len2 = (len < blen) ? len : blen;
+ int len2 = Math.min(maxChunk, len);
text.getChars(offset, offset+len2, buf, 0);
- writeRaw(buf, 0, len2);
+ if ((_outputTail + maxBytes) > _outputEnd) {
+ _flushBuffer();
+ }
+ // If this is NOT the last segment and if the last character looks like
+ // split surrogate second half, drop it
+ if (len > 0) {
+ char ch = buf[len2-1];
+ if ((ch >= SURR1_FIRST) && (ch <= SURR1_LAST)) {
+ --len2;
+ }
+ }
+ _writeRawSegment(buf, 0, len2);
offset += len2;
len -= len2;
}
}
@Override
- public void writeRaw(SerializableString text) throws IOException, JsonGenerationException
+ public void writeRaw(SerializableString text) throws IOException
{
byte[] raw = text.asUnquotedUTF8();
if (raw.length > 0) {
@@ -567,8 +578,7 @@
// @TODO: rewrite for speed...
@Override
- public final void writeRaw(char[] cbuf, int offset, int len)
- throws IOException, JsonGenerationException
+ public final void writeRaw(char[] cbuf, int offset, int len) throws IOException
{
// First: if we have 3 x charCount spaces, we know it'll fit just fine
{
@@ -610,8 +620,7 @@
}
@Override
- public void writeRaw(char ch)
- throws IOException, JsonGenerationException
+ public void writeRaw(char ch) throws IOException
{
if ((_outputTail + 3) >= _outputEnd) {
_flushBuffer();
@@ -631,14 +640,14 @@
* Helper method called when it is possible that output of raw section
* to output may cross buffer boundary
*/
- private final void _writeSegmentedRaw(char[] cbuf, int offset, int len)
- throws IOException, JsonGenerationException
+ private final void _writeSegmentedRaw(char[] cbuf, int offset, int len) throws IOException
{
final int end = _outputEnd;
final byte[] bbuf = _outputBuffer;
+ final int inputEnd = offset + len;
main_loop:
- while (offset < len) {
+ while (offset < inputEnd) {
inner_loop:
while (true) {
int ch = (int) cbuf[offset];
@@ -650,7 +659,7 @@
_flushBuffer();
}
bbuf[_outputTail++] = (byte) ch;
- if (++offset >= len) {
+ if (++offset >= inputEnd) {
break main_loop;
}
}
@@ -662,11 +671,45 @@
bbuf[_outputTail++] = (byte) (0xc0 | (ch >> 6));
bbuf[_outputTail++] = (byte) (0x80 | (ch & 0x3f));
} else {
- offset = _outputRawMultiByteChar(ch, cbuf, offset, len);
+ offset = _outputRawMultiByteChar(ch, cbuf, offset, inputEnd);
}
}
}
-
+
+ /**
+ * Helper method that is called for segmented write of raw content
+ * when explicitly outputting a segment of longer thing.
+ * Caller has to take care of ensuring there's no split surrogate
+ * pair at the end (that is, last char can not be first part of a
+ * surrogate char pair).
+ *
+ * @since 2.8.2
+ */
+ private void _writeRawSegment(char[] cbuf, int offset, int end) throws IOException
+ {
+ main_loop:
+ while (offset < end) {
+ inner_loop:
+ while (true) {
+ int ch = (int) cbuf[offset];
+ if (ch > 0x7F) {
+ break inner_loop;
+ }
+ _outputBuffer[_outputTail++] = (byte) ch;
+ if (++offset >= end) {
+ break main_loop;
+ }
+ }
+ char ch = cbuf[offset++];
+ if (ch < 0x800) { // 2-byte?
+ _outputBuffer[_outputTail++] = (byte) (0xc0 | (ch >> 6));
+ _outputBuffer[_outputTail++] = (byte) (0x80 | (ch & 0x3f));
+ } else {
+ offset = _outputRawMultiByteChar(ch, cbuf, offset, end);
+ }
+ }
+ }
+
/*
/**********************************************************
/* Output method implementations, base64-encoded binary
@@ -1873,18 +1916,19 @@
* 1- and 2-byte UTF-8 encodings, when outputting "raw"
* text (meaning it is not to be escaped or quoted)
*/
- private final int _outputRawMultiByteChar(int ch, char[] cbuf, int inputOffset, int inputLen)
+ private final int _outputRawMultiByteChar(int ch, char[] cbuf, int inputOffset, int inputEnd)
throws IOException
{
// Let's handle surrogates gracefully (as 4 byte output):
if (ch >= SURR1_FIRST) {
if (ch <= SURR2_LAST) { // yes, outside of BMP
// Do we have second part?
- if (inputOffset >= inputLen || cbuf == null) { // nope... have to note down
- _reportError("Split surrogate on writeRaw() input (last character)");
+ if (inputOffset >= inputEnd || cbuf == null) { // nope... have to note down
+ _reportError(String.format(
+"Split surrogate on writeRaw() input (last character): first character 0x%4x", ch));
}
_outputSurrogates(ch, cbuf[inputOffset]);
- return (inputOffset+1);
+ return inputOffset+1;
}
}
final byte[] bbuf = _outputBuffer;
diff --git a/src/test/java/com/fasterxml/jackson/core/json/RawValueWithSurrogatesTest.java b/src/test/java/com/fasterxml/jackson/core/json/RawValueWithSurrogatesTest.java
new file mode 100644
index 0000000..e94e4ed
--- /dev/null
+++ b/src/test/java/com/fasterxml/jackson/core/json/RawValueWithSurrogatesTest.java
@@ -0,0 +1,89 @@
+package com.fasterxml.jackson.core.json;
+
+import java.io.ByteArrayOutputStream;
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonGenerator;
+
+public class RawValueWithSurrogatesTest
+ extends com.fasterxml.jackson.core.BaseTest
+{
+ final String SURROGATES_307;
+ {
+ // This one fails:
+ String msg ="{'xxxxxxx':{'xxxx':'xxxxxxxxx','xx':'xxxxxxxxxxxxxxxxxxx','xxxxxxxxx':'xxxx://xxxxxxx.xxx',"
++"'xxxxxx':{'xxxx':'xxxxxxxxxxx','xxxxxxxx':{'xxxxxxxxxxx':'xx','xxxxxxxxxx':'xx-xx'}},"
++"'xxxxx':[{'xxxx':'xxxx','xxxx':'xx xxxxxxxxxxx: xxxxxxx xxxxxx xxxxxxxxxxxxx xxxxx xxxxxx. xxxxx xxxxxx xxxxx xxxxx. xx xxx xx xxxx xxx xxxx. xxxx xxxxx xxx xxxxxxxx xxxxx xxxxxx xxxxxxx😆👍'}]},"
++"'xxxxxxxxxxx':[{'xxxxxxx':'xxxxxx','xxxxxxxx':[{'xxxxxx':x,'xxxxxx':xxx,"
++"'xxxx':'xx xxxxxxxxxxx: xxxxxxx xxxxxx xxxxxxxxxxxxx xxxxx xxxxxx. xxxxx xxxxxx xxxxx xxxxx. xx xxx xx xxxx xxx xxxx. xxxx xxxxx xxx xxxxxxxx xxxxx xxxxxx xxxxxxx😆👍',"
++"'xxxxxx':{'xxxxxx':xx,'xxxxxx':x,'xxxx':'xxxxx'}},"
++"{'xxxxxx':x,'xxxxxx':xxx,'xxxx':'xx xxxxxxxxxxx: xxxxxxx xxxxxx xxxxxxxxxxxxx xxxxx xxxxxx. xxxxx xxxxxx xxxxx xxxxx. xx xxx xx xxxx xxx xxxx. xxxx xxxxx xxx xxxxxxxx xxxxx xxxxxx xxxxxxx😆👍'"
++",'xxxxxx':{'xxxxxx':xxx,'xxxxxx':x,'xxxx':'xxxxx'}}]},{'xxxxxxxxxxx':'xxxxxx','xxxxxxxx':[{'xxxxxx':x,'xxxxxx':xxx,"
++"'xxxx':'xx xxxxxxxxxxx: xxxxxxx xxxxxx xxxxxxxxxxxxx xxxxx xxxxxx. xxxxx xxxxxx xxxxx xxxxx. xx xxx xx xxxx xxx xxxx. xxxx xxxxx xxx xxxxxxxx xxxxx xxxxxx xxxxxxx😆👍',"
++"'xxxxxx':{'xxxxxx':xx,'xxxxxx':x,'xxxx':'xxxxx'}},"
++"{'xxxxxx':x,'xxxxxx':xxx,'xxxx':'xx xxxxxxxxxxx: xxxxxxx xxxxxx xxxxxxxxxxxxx xxxxx xxxxxx. xxxxx xxxxxx xxxxx xxxxx. xx xxx xx xxxx xxx xxxx. xxxx xxxxx xxx xxxxxxxx xxxxx xxxxxx xxxxxxx😆👍',"
++"'xxxxxx':{'xxxxxx':xxx,'xxxxxx':x,'xxxx':'xxxxx'}}]},{'xxxxxxxxxxx':'xxxxxx','xxxxxxxx':[{'xxxxxx':x,'xxxxxx':xxx,"
++"'xxxx':'xx xxxxxxxxxxx: xxxxxxx xxxxxx xxxxxxxxxxxxx xxxxx xxxxxx. xxxxx xxxxxx xxxxx xxxxx. xx xxx xx xxxx xxx xxxx. xxxx xxxxx xxx xxxxxxxx xxxxx xxxxxx xxxxxxx😆👍',"
++"'xxxxxx':{'xxxxxx':xx,'xxxxxx':x,'xxxx':'xxxxx'}},{'xxxxxx':x,'xxxxxx':xxx,"
++"'xxxx':'xx xxxxxxxxxxx: xxxxxxx xxxxxx xxxxxxxxxxxxx xxxxx xxxxxx. xxxxx xxxxxx xxxxx xxxxx. xx xxx xx xxxx xxx xxxx. xxxx xxxxx xxx xxxxxxxx xxxxx xxxxxx xxxxxxx😆👍',"
++"'xxxxxx':{'xxxxxx':xxx,'xxxxxx':x,'xxxx':'xxxxx'}}]},{'xxxxxxxxxxx':'xxxxxx','xxxxxxxx':[{'xxxxxx':x,'xxxxxx':xxx,"
++"'xxxx':'xx xxxxxxxxxxx: xxxxxxx xxxxxx xxxxxxxxxxxxx xxxxx xxxxxx. xxxxx xxxxxx xxxxx xxxxx. xx xxx xx xxxx xxx xxxx. xxxx xxxxx xxx xxxxxxxx xxxxx xxxxxx xxxxxxx😆👍',"
++"'xxxxxx':{'xxxxxx':xx,'xxxxxx':x,'xxxx':'xxxxx'}},{'xxxxxx':x,'xxxxxx':xxx,"
++"'xxxx':'xx xxxxxxxxxxx: xxxxxxx xxxxxx xxxxxxxxxxxxx xxxxx xxxxxx. xxxxx xxxxxx xxxxx xxxxx. xx xxx xx xxxx xxx xxxx. xxxx xxxxx xxx xxxxxxxx xxxxx xxxxxx xxxxxxx😆👍',"
++"'xxxxxx':{'xxxxxx':xxx,'xxxxxx':x,'xxxx':'xxxxx'}}]},{'xxxxxxxxxxx':'xxxxxx','xxxxxxxx':"
++"[{'xxxxxx':3,'xxxxxx':123,'xxxx':'xx xxxxxxxxxxx: xxxxxxx xxxxxx xxxxxxxxxxxxx xxxxx xxxxxx. xxxxx xxxxxx xxxxx xxxxx. xx xxx xx xxxx xxx xxxx. xxxx xxxxx xxx xxxxxxxx xxxxx xxxxxx xxxxxxx😆👍',"
++"'xxxxxx':{'xxxxxx':24,'xxxxxx':4,'xxxx':'xxxxx'}},{'xxxxxx':0,'xxxxxx':123,"
++"'xxxx':'xx xxxxxxxxxxx: xxxxxxx xxxxxx xxxxxxxxxxxxx xxxxx xxxxxx. xxxxx xxxxxx xxxxx xxxxx. xx xxx xx xxxx xxx xxxx. xxxx xxxxx xxx xxxxxxxx xxxxx xxxxxx xxxxxxx😆👍',"
++"'xxxxxx':{'xxxxxx':123,'xxxxxx':1,'xxxx':'xxxxx'}}]},{'xxxxxxxxxxx':'xxxxxx','xxxxxxxx':[{'xxxxxx':1,'xxxxxx':123,"
++"'xxxx':'xx xxxxxxxxxxx: xxxxxxx xxxxxx xxxxxxxxxxxxx xxxxx xxxxxx. xxxxx xxxxxx xxxxx xxxxx. xx xxx xx xxxx xxx xxxx. xxxx xxxxx xxx xxxxxxxx xxxxx xxxxxx xxxxxxx😆👍','xxxxxx':{'xxxxxx':xx,'xxxxxx':x,'xxxx':'xxxxx'}},"
++"{'xxxxxx':x,'xxxxxx':123,'xxxx':'xx xxxxxxxxxxx: xxxxxxx xxxxxx xxxxxxxxxxxxx xxxxx xxxxxx. xxxxx xxxxxx xxxxx xxxxx. xx xxx xx xxxx xxx xxxx. xxxx xxxxx xxx xxxxxxxx xxxxx xxxxxx xxxxxxx😆👍',"
++"'xxxxxx':{'xxxxxx':xxx,'xxxxxx':x,'xxxx':'xxxxx'}}]},{'xxxxxxxxxxx':'xxxxx','xxxxxxxx':[{'xxxxxx':x,'xxxxxx':xxx,"
++"'xxxx':'xx xxxxxxxxxxx: xxxxxxx xxxxxx xxxxxxxxxxxxx xxxxx xxxxxx. xxxxx xxxxxx xxxxx xxxxx. xx xxx xx xxxx xxx xxxx. xxxx xxxxx xxx xxxxxxxx xxxxx xxxxxx xxxxxxx😆👍',"
++"'xxxxxx':{'xxxxxx':xx,'xxxxxx':x,'xxxx':'xxxxx'}},{'xxxxxx':x,'xxxxxx':xxx,"
++"'xxxx':'xx xxxxxxxxxxx: xxxxxxx xxxxxx xxxxxxxxxxxxx xxxxx xxxxxx. xxxxx xxxxxx xxxxx xxxxx. xx xxx xx xxxx xxx xxxx. xxxx xxxxx xxx xxxxxxxx xxxxx xxxxxx xxxxxxx😆👍',"
++"'xxxxxx':{'xxxxxx':xxx,'xxxxxx':x,'xxxx':'xxxxx'}}]}]}";
+ // This one works:
+// String msg ="{'xxx':{'xxxx':'xxxxxxxxx','xx':'xxxxxxxxxxxxxxxxxxx','xxxxxxxxx':'xxxx://xxxxxxx.xxx','xxxxxx':{'xxxx':'xxxxxxxxxxx','xxxxxxxx':{'xxxxxxxxxxx':'xx','xxxxxxxxxx':'xx-xx'}},'xxxxx':[{'xxxx':'xxxx','xxxx':'xx xxxxxxxxxxx: xxxxxxx xxxxxx xxxxxxxxxxxxx xxxxx xxxxxx. xxxxx xxxxxx xxxxx xxxxx. xx xxx xx xxxx xxx xxxx. xxxx xxxxx xxx xxxxxxxx xxxxx xxxxxx xxxxxxx😆👍'}]},'xxxxxxxxxxx':[{'xxxxxxx':'xxxxxx','xxxxxxxx':[{'xxxxxx':x,'xxxxxx':xxx,'xxxx':'xx xxxxxxxxxxx: xxxxxxx xxxxxx xxxxxxxxxxxxx xxxxx xxxxxx. xxxxx xxxxxx xxxxx xxxxx. xx xxx xx xxxx xxx xxxx. xxxx xxxxx xxx xxxxxxxx xxxxx xxxxxx xxxxxxx😆👍','xxxxxx':{'xxxxxx':xx,'xxxxxx':x,'xxxx':'xxxxx'}},{'xxxxxx':x,'xxxxxx':xxx,'xxxx':'xx xxxxxxxxxxx: xxxxxxx xxxxxx xxxxxxxxxxxxx xxxxx xxxxxx. xxxxx xxxxxx xxxxx xxxxx. xx xxx xx xxxx xxx xxxx. xxxx xxxxx xxx xxxxxxxx xxxxx xxxxxx xxxxxxx😆👍','xxxxxx':{'xxxxxx':xxx,'xxxxxx':x,'xxxx':'xxxxx'}}]},{'xxxxxxxxxxx':'xxxxxx','xxxxxxxx':[{'xxxxxx':x,'xxxxxx':xxx,'xxxx':'xx xxxxxxxxxxx: xxxxxxx xxxxxx xxxxxxxxxxxxx xxxxx xxxxxx. xxxxx xxxxxx xxxxx xxxxx. xx xxx xx xxxx xxx xxxx. xxxx xxxxx xxx xxxxxxxx xxxxx xxxxxx xxxxxxx😆👍','xxxxxx':{'xxxxxx':xx,'xxxxxx':x,'xxxx':'xxxxx'}},{'xxxxxx':x,'xxxxxx':xxx,'xxxx':'xx xxxxxxxxxxx: xxxxxxx xxxxxx xxxxxxxxxxxxx xxxxx xxxxxx. xxxxx xxxxxx xxxxx xxxxx. xx xxx xx xxxx xxx xxxx. xxxx xxxxx xxx xxxxxxxx xxxxx xxxxxx xxxxxxx😆👍','xxxxxx':{'xxxxxx':xxx,'xxxxxx':x,'xxxx':'xxxxx'}}]},{'xxxxxxxxxxx':'xxxxxx','xxxxxxxx':[{'xxxxxx':x,'xxxxxx':xxx,'xxxx':'xx xxxxxxxxxxx: xxxxxxx xxxxxx xxxxxxxxxxxxx xxxxx xxxxxx. xxxxx xxxxxx xxxxx xxxxx. xx xxx xx xxxx xxx xxxx. xxxx xxxxx xxx xxxxxxxx xxxxx xxxxxx xxxxxxx😆👍','xxxxxx':{'xxxxxx':xx,'xxxxxx':x,'xxxx':'xxxxx'}},{'xxxxxx':x,'xxxxxx':xxx,'xxxx':'xx xxxxxxxxxxx: xxxxxxx xxxxxx xxxxxxxxxxxxx xxxxx xxxxxx. xxxxx xxxxxx xxxxx xxxxx. xx xxx xx xxxx xxx xxxx. xxxx xxxxx xxx xxxxxxxx xxxxx xxxxxx xxxxxxx😆👍','xxxxxx':{'xxxxxx':xxx,'xxxxxx':x,'xxxx':'xxxxx'}}]},{'xxxxxxxxxxx':'xxxxxx','xxxxxxxx':[{'xxxxxx':x,'xxxxxx':xxx,'xxxx':'xx xxxxxxxxxxx: xxxxxxx xxxxxx xxxxxxxxxxxxx xxxxx xxxxxx. xxxxx xxxxxx xxxxx xxxxx. xx xxx xx xxxx xxx xxxx. xxxx xxxxx xxx xxxxxxxx xxxxx xxxxxx xxxxxxx😆👍','xxxxxx':{'xxxxxx':xx,'xxxxxx':x,'xxxx':'xxxxx'}},{'xxxxxx':x,'xxxxxx':xxx,'xxxx':'xx xxxxxxxxxxx: xxxxxxx xxxxxx xxxxxxxxxxxxx xxxxx xxxxxx. xxxxx xxxxxx xxxxx xxxxx. xx xxx xx xxxx xxx xxxx. xxxx xxxxx xxx xxxxxxxx xxxxx xxxxxx xxxxxxx😆👍','xxxxxx':{'xxxxxx':xxx,'xxxxxx':x,'xxxx':'xxxxx'}}]},{'xxxxxxxxxxx':'xxxxxx','xxxxxxxx':[{'xxxxxx':x,'xxxxxx':xxx,'xxxx':'xx xxxxxxxxxxx: xxxxxxx xxxxxx xxxxxxxxxxxxx xxxxx xxxxxx. xxxxx xxxxxx xxxxx xxxxx. xx xxx xx xxxx xxx xxxx. xxxx xxxxx xxx xxxxxxxx xxxxx xxxxxx xxxxxxx😆👍','xxxxxx':{'xxxxxx':xx,'xxxxxx':x,'xxxx':'xxxxx'}},{'xxxxxx':x,'xxxxxx':xxx,'xxxx':'xx xxxxxxxxxxx: xxxxxxx xxxxxx xxxxxxxxxxxxx xxxxx xxxxxx. xxxxx xxxxxx xxxxx xxxxx. xx xxx xx xxxx xxx xxxx. xxxx xxxxx xxx xxxxxxxx xxxxx xxxxxx xxxxxxx😆👍','xxxxxx':{'xxxxxx':xxx,'xxxxxx':x,'xxxx':'xxxxx'}}]},{'xxxxxxxxxxx':'xxxxxx','xxxxxxxx':[{'xxxxxx':x,'xxxxxx':xxx,'xxxx':'xx xxxxxxxxxxx: xxxxxxx xxxxxx xxxxxxxxxxxxx xxxxx xxxxxx. xxxxx xxxxxx xxxxx xxxxx. xx xxx xx xxxx xxx xxxx. xxxx xxxxx xxx xxxxxxxx xxxxx xxxxxx xxxxxxx😆👍','xxxxxx':{'xxxxxx':xx,'xxxxxx':x,'xxxx':'xxxxx'}},{'xxxxxx':x,'xxxxxx':xxx,'xxxx':'xx xxxxxxxxxxx: xxxxxxx xxxxxx xxxxxxxxxxxxx xxxxx xxxxxx. xxxxx xxxxxx xxxxx xxxxx. xx xxx xx xxxx xxx xxxx. xxxx xxxxx xxx xxxxxxxx xxxxx xxxxxx xxxxxxx😆👍','xxxxxx':{'xxxxxx':xxx,'xxxxxx':x,'xxxx':'xxxxx'}}]},{'xxxxxxxxxxx':'xxxxx','xxxxxxxx':[{'xxxxxx':x,'xxxxxx':xxx,'xxxx':'xx xxxxxxxxxxx: xxxxxxx xxxxxx xxxxxxxxxxxxx xxxxx xxxxxx. xxxxx xxxxxx xxxxx xxxxx. xx xxx xx xxxx xxx xxxx. xxxx xxxxx xxx xxxxxxxx xxxxx xxxxxx xxxxxxx😆👍','xxxxxx':{'xxxxxx':xx,'xxxxxx':x,'xxxx':'xxxxx'}},{'xxxxxx':x,'xxxxxx':xxx,'xxxx':'xx xxxxxxxxxxx: xxxxxxx xxxxxx xxxxxxxxxxxxx xxxxx xxxxxx. xxxxx xxxxxx xxxxx xxxxx. xx xxx xx xxxx xxx xxxx. xxxx xxxxx xxx xxxxxxxx xxxxx xxxxxx xxxxxxx😆👍','xxxxxx':{'xxxxxx':xxx,'xxxxxx':x,'xxxx':'xxxxx'}}]}]}";
+
+ SURROGATES_307 = aposToQuotes(msg);
+ }
+
+ private final JsonFactory JSON_F = new JsonFactory();
+
+ // for [jackson-core#307]
+ public void testRawWithSurrogatesString() throws Exception {
+ _testRawWithSurrogatesString(false);
+ }
+
+ // for [jackson-core#307]
+ public void testRawWithSurrogatesCharArray() throws Exception {
+ _testRawWithSurrogatesString(true);
+ }
+
+ private void _testRawWithSurrogatesString(boolean useCharArray) throws Exception
+ {
+ // boundaries are not exact, may vary, so use this:
+
+ final int OFFSET = 3;
+ final int COUNT = 100;
+
+ for (int i = OFFSET; i < COUNT; ++i) {
+ StringBuilder sb = new StringBuilder(1000);
+ for (int j = 0; j < i; ++j) {
+ sb.append(' ');
+ }
+ sb.append(SURROGATES_307);
+ final String text = sb.toString();
+ ByteArrayOutputStream out = new ByteArrayOutputStream(1000);
+ JsonGenerator g = JSON_F.createGenerator(out);
+ if (useCharArray) {
+ char[] ch = text.toCharArray();
+ g.writeRawValue(ch, OFFSET, ch.length - OFFSET);
+ } else {
+ g.writeRawValue(text, OFFSET, text.length() - OFFSET);
+ }
+ g.close();
+ byte[] b = out.toByteArray();
+ assertNotNull(b);
+ }
+ }
+}