json-iterator / java

jsoniter (json-iterator) is fast and flexible JSON parser available in Java and Go
http://jsoniter.com/
MIT License
1.51k stars 518 forks source link

com.jsoniter.spi.JsonException: unreadByte: unread too many bytes, head: 0 #212

Open RogerChickering opened 6 years ago

RogerChickering commented 6 years ago

Thanks for maintaining this awesome JSON parsing library!!!!

If the last character in a stream being parsed is a space, and that space is returned in a read of only one byte (the last byte in the stream), JsonIterator.unreadByte throws an exception because head is 0:

Exception in thread "main" com.jsoniter.spi.JsonException: unreadByte: unread too many bytes, head: 0, peek: , buf: } at com.jsoniter.JsonIterator.reportError(JsonIterator.java:136) at com.jsoniter.JsonIterator.unreadByte(JsonIterator.java:121) at com.jsoniter.JsonIterator.whatIsNext(JsonIterator.java:393) at TestBufferBoundrary.main(TestBufferBoundrary.java:30)

The following program illustrates the issue:

import com.jsoniter.JsonIterator;
import com.jsoniter.ValueType;

import java.io.IOException;
import java.io.InputStream;

public class TestBufferBoundrary
{
    static class BreakJsonIterInputStream extends InputStream
    {
        final byte[] buf = new byte[] { '{', '}', ' ' };
        int off = 0;

        public void close() throws IOException
        {
        }

        public int read() throws IOException
        {
            if (off >= buf.length) {
                return -1;
            }
            return buf[off++];
        }
    }

    public static void main(String[] args) throws IOException
    {
        JsonIterator jiter = JsonIterator.parse(new BreakJsonIterInputStream(), 2);
        while (jiter.whatIsNext() == ValueType.OBJECT) {
            jiter.readObject();
        }
    }
}

One fix is to change JsonIterator.whatIsNext to the following:

    public ValueType whatIsNext() throws IOException {
        ValueType valueType = valueTypes[IterImpl.nextToken(this)];
        if (valueType != ValueType.INVALID) {
            unreadByte();
        }
        return valueType;
    }

Thanks! -Roger