Skip to content

Commit ac1ad7e

Browse files
committed
Take care of incomplete multi-bytes at the tail of buffer
1 parent 9ad0405 commit ac1ad7e

File tree

2 files changed

+40
-4
lines changed

2 files changed

+40
-4
lines changed

msgpack-core/src/main/java/org/msgpack/core/MessageUnpacker.java

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1025,13 +1025,20 @@ public String unpackString()
10251025
decodeBuffer.clear();
10261026
StringBuilder sb = new StringBuilder();
10271027

1028+
boolean incompleteMultiBytes = false;
10281029
while (cursor < strLen) {
10291030
int readLen = Math.min(position < buffer.size() ? buffer.size() - position : buffer.size(), strLen - cursor);
1031+
if (incompleteMultiBytes) {
1032+
// Prepare enough buffer for decoding multi-bytes character right after running into incomplete one
1033+
readLen = Math.min(config.getStringDecoderBufferSize(), strLen - cursor);
1034+
}
10301035
if (!ensure(readLen)) {
10311036
throw new EOFException();
10321037
}
10331038

1039+
incompleteMultiBytes = false;
10341040
ByteBuffer bb = buffer.toByteBuffer(position, readLen);
1041+
int startPos = bb.position();
10351042

10361043
while (bb.hasRemaining()) {
10371044
boolean endOfInput = (cursor + readLen) >= strLen;
@@ -1051,10 +1058,9 @@ public String unpackString()
10511058
if (config.getActionOnMalFormedInput() == CodingErrorAction.REPORT) {
10521059
throw new MalformedInputException(strLen);
10531060
}
1054-
// trash truncated bytes
1055-
while (bb.hasRemaining()) {
1056-
bb.get();
1057-
}
1061+
incompleteMultiBytes = true;
1062+
// Proceed the cursor with the length already decoded successfully.
1063+
readLen = bb.position() - startPos;
10581064
}
10591065

10601066
if (cr.isError()) {
@@ -1068,6 +1074,10 @@ public String unpackString()
10681074
sb.append(decodeBuffer);
10691075

10701076
decodeBuffer.clear();
1077+
1078+
if (incompleteMultiBytes) {
1079+
break;
1080+
}
10711081
}
10721082

10731083
cursor += readLen;

msgpack-core/src/test/scala/org/msgpack/core/MessageUnpackerTest.scala

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package org.msgpack.core
1717

1818
import java.io._
19+
import java.nio.ByteBuffer
1920

2021
import org.msgpack.core.buffer._
2122
import org.msgpack.value.ValueType
@@ -663,5 +664,30 @@ class MessageUnpackerTest extends MessagePackSpec {
663664
unpacker.getTotalReadBytes shouldBe arr.length
664665
}
665666
}
667+
668+
"unpack string crossing end of buffer" in {
669+
def check(expected: String, strLen: Int) = {
670+
val bytes = new Array[Byte](strLen)
671+
val out = new ByteArrayOutputStream
672+
673+
val packer = MessagePack.newDefaultPacker(out)
674+
packer.packBinaryHeader(bytes.length)
675+
packer.writePayload(bytes)
676+
packer.packString(expected)
677+
packer.close
678+
679+
val unpacker = new MessageUnpacker(new InputStreamBufferInput(new ByteArrayInputStream(out.toByteArray)))
680+
val len = unpacker.unpackBinaryHeader
681+
unpacker.readPayload(len)
682+
val got = unpacker.unpackString
683+
unpacker.close
684+
685+
got shouldBe expected
686+
}
687+
688+
Seq("", "aあ", "あa", "あいうえおかきくけこさしすせそ").foreach { s =>
689+
Seq(8185, 8186, 8187, 8188, 16377, 16378, 16379, 16380).foreach { n => check(s, n)}
690+
}
691+
}
666692
}
667693
}

0 commit comments

Comments
 (0)