summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJohannes Rudolph <johannes.rudolph@gmail.com>2016-12-29 11:03:08 +0100
committerJohannes Rudolph <johannes.rudolph@gmail.com>2016-12-29 11:04:08 +0100
commit9ea645b0be33d740473c972dd7c4ae83bb1b81d8 (patch)
tree15661f01ccddeb74ae5292016745e50ccb9d17ce /src
parent537cb5bca7eb73750fc2e86e4a2ea6605714482b (diff)
downloadspray-json-9ea645b0be33d740473c972dd7c4ae83bb1b81d8.tar.gz
spray-json-9ea645b0be33d740473c972dd7c4ae83bb1b81d8.tar.bz2
spray-json-9ea645b0be33d740473c972dd7c4ae83bb1b81d8.zip
refactor utf8 decoding from indexed bytes into super class
This will allow third-party implementations of ParserInput without having to copy the code just to support other data structures like Akka's ByteString or java.nio.ByteBuffer.
Diffstat (limited to 'src')
-rw-r--r--src/main/scala/spray/json/JsonParser.scala27
1 files changed, 19 insertions, 8 deletions
diff --git a/src/main/scala/spray/json/JsonParser.scala b/src/main/scala/spray/json/JsonParser.scala
index b1e59d5..20057c1 100644
--- a/src/main/scala/spray/json/JsonParser.scala
+++ b/src/main/scala/spray/json/JsonParser.scala
@@ -266,23 +266,25 @@ object ParserInput {
private val UTF8 = Charset.forName("UTF-8")
/**
- * ParserInput reading directly off a byte array which is assumed to contain the UTF-8 encoded representation
- * of the JSON input, without requiring a separate decoding step.
+ * ParserInput that allows to create a ParserInput from any randomly accessible indexed byte storage.
*/
- class ByteArrayBasedParserInput(bytes: Array[Byte]) extends DefaultParserInput {
+ abstract class IndexedBytesParserInput extends DefaultParserInput {
+ def length: Int
+ protected def byteAt(offset: Int): Byte
+
private val byteBuffer = ByteBuffer.allocate(4)
private val charBuffer = CharBuffer.allocate(2)
private val decoder = UTF8.newDecoder()
def nextChar() = {
_cursor += 1
- if (_cursor < bytes.length) (bytes(_cursor) & 0xFF).toChar else EOI
+ if (_cursor < length) (byteAt(_cursor) & 0xFF).toChar else EOI
}
def nextUtf8Char() = {
@tailrec def decode(byte: Byte, remainingBytes: Int): Char = {
byteBuffer.put(byte)
if (remainingBytes > 0) {
_cursor += 1
- if (_cursor < bytes.length) decode(bytes(_cursor), remainingBytes - 1) else ErrorChar
+ if (_cursor < length) decode(byteAt(_cursor), remainingBytes - 1) else ErrorChar
} else {
byteBuffer.flip()
val coderResult = decoder.decode(byteBuffer, charBuffer, false)
@@ -300,8 +302,8 @@ object ParserInput {
result
} else {
_cursor += 1
- if (_cursor < bytes.length) {
- val byte = bytes(_cursor)
+ if (_cursor < length) {
+ val byte = byteAt(_cursor)
if (byte >= 0) byte.toChar // 7-Bit ASCII
else if ((byte & 0xE0) == 0xC0) decode(byte, 1) // 2-byte UTF-8 sequence
else if ((byte & 0xF0) == 0xE0) decode(byte, 2) // 3-byte UTF-8 sequence
@@ -310,7 +312,16 @@ object ParserInput {
} else EOI
}
}
- def length = bytes.length
+ }
+
+ /**
+ * ParserInput reading directly off a byte array which is assumed to contain the UTF-8 encoded representation
+ * of the JSON input, without requiring a separate decoding step.
+ */
+ class ByteArrayBasedParserInput(bytes: Array[Byte]) extends IndexedBytesParserInput {
+ protected def byteAt(offset: Int): Byte = bytes(offset)
+ def length: Int = bytes.length
+
def sliceString(start: Int, end: Int) = new String(bytes, start, end - start, UTF8)
def sliceCharArray(start: Int, end: Int) =
UTF8.decode(ByteBuffer.wrap(java.util.Arrays.copyOfRange(bytes, start, end))).array()