diff options
author | Johannes Rudolph <johannes.rudolph@gmail.com> | 2016-12-29 11:03:08 +0100 |
---|---|---|
committer | Johannes Rudolph <johannes.rudolph@gmail.com> | 2016-12-29 11:04:08 +0100 |
commit | 9ea645b0be33d740473c972dd7c4ae83bb1b81d8 (patch) | |
tree | 15661f01ccddeb74ae5292016745e50ccb9d17ce /src/main/scala | |
parent | 537cb5bca7eb73750fc2e86e4a2ea6605714482b (diff) | |
download | spray-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/main/scala')
-rw-r--r-- | src/main/scala/spray/json/JsonParser.scala | 27 |
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() |