Jackson Core Source Code

Jackson is "the Java JSON library" or "the best JSON parser for Java". Or simply as "JSON for Java".

Jackson Core Source Code files are provided in the source packge (jackson-core-2.12.4-sources.jar). You can download it at Jackson Maven Website.

You can also browse Jackson Core Source Code below:

✍: FYIcenter.com

com/fasterxml/jackson/core/io/UTF32Reader.java

package com.fasterxml.jackson.core.io;

import java.io.*;


/**
 * Since JDK does not come with UTF-32/UCS-4, let's implement a simple
 * decoder to use.
 */
public class UTF32Reader extends Reader
{
    /**
     * JSON actually limits available Unicode range in the high end
     * to the same as xml (to basically limit UTF-8 max byte sequence
     * length to 4)
     */
    final protected static int LAST_VALID_UNICODE_CHAR = 0x10FFFF;

    final protected static char NC = (char) 0;

    final protected IOContext _context;

    protected InputStream _in;

    protected byte[] _buffer;

    protected int _ptr;
    protected int _length;

    protected final boolean _bigEndian;

    /**
     * Although input is fine with full Unicode set, Java still uses
     * 16-bit chars, so we may have to split high-order chars into
     * surrogate pairs.
     */
    protected char _surrogate = NC;

    /**
     * Total read character count; used for error reporting purposes
     */
    protected int _charCount;

    /**
     * Total read byte count; used for error reporting purposes
     */
    protected int _byteCount;

    protected final boolean _managedBuffers;
    
    /*
    /**********************************************************
    /* Life-cycle
    /**********************************************************
     */

    public UTF32Reader(IOContext ctxt, InputStream in, byte[] buf, int ptr, int len, boolean isBigEndian) {
        _context = ctxt;
        _in = in;
        _buffer = buf;
        _ptr = ptr;
        _length = len;
        _bigEndian = isBigEndian;
        _managedBuffers = (in != null);
    }

    /*
    /**********************************************************
    /* Public API
    /**********************************************************
     */

    @Override
    public void close() throws IOException {
        InputStream in = _in;

        if (in != null) {
            _in = null;
            freeBuffers();
            in.close();
        }
    }

    protected char[] _tmpBuf;

    /**
     * Although this method is implemented by the base class, AND it should
     * never be called by main code, let's still implement it bit more
     * efficiently just in case
     */
    @Override
    public int read() throws IOException {
        if (_tmpBuf == null) {
            _tmpBuf = new char[1];
        }
        if (read(_tmpBuf, 0, 1) < 1) {
            return -1;
        }
        return _tmpBuf[0];
    }
    
    @Override
    public int read(char[] cbuf, int start, int len) throws IOException {
        // Already EOF?
        if (_buffer == null) { return -1; }
        if (len < 1) { return len; }
        // Let's then ensure there's enough room...
        if (start < 0 || (start+len) > cbuf.length) {
            reportBounds(cbuf, start, len);
        }

        int outPtr = start;
        final int outEnd = len+start;

        // Ok, first; do we have a surrogate from last round?
        if (_surrogate != NC) {
            cbuf[outPtr++] = _surrogate;
            _surrogate = NC;
            // No need to load more, already got one char
        } else {
            // Note: we'll try to avoid blocking as much as possible. As a
            // result, we only need to get 4 bytes for a full char.
            int left = (_length - _ptr);
            if (left < 4) {
                if (!loadMore(left)) { // (legal) EOF?
                    // Ok if (but only if!) was at boundary
                    if (left == 0) {
                        return -1;
                    }
                    reportUnexpectedEOF(_length - _ptr, 4);
                }
            }
        }

        // 02-Jun-2017, tatu: Must ensure we don't try to read past buffer end:
        final int lastValidInputStart = (_length - 4);
        
        main_loop:
        while (outPtr < outEnd) {
            int ptr = _ptr;
            int hi, lo;

            if (_bigEndian) {
                hi = (_buffer[ptr] << 8) | (_buffer[ptr+1] & 0xFF);
                lo = ((_buffer[ptr+2] & 0xFF) << 8) | (_buffer[ptr+3] & 0xFF);
            } else {
                lo = (_buffer[ptr] & 0xFF) | ((_buffer[ptr+1] & 0xFF) << 8);
                hi = (_buffer[ptr+2] & 0xFF)| (_buffer[ptr+3] << 8);
            }
            _ptr += 4;

            // Does it need to be split to surrogates?
            // (also, we can and need to verify illegal chars)
            if (hi != 0) { // need to split into surrogates?
                hi &= 0xFFFF; // since it may be sign extended
                int ch = ((hi - 1) << 16) | lo; // ch -= 0x10000; to normalize starting with 0x0
                if (hi > 0x10) { // last valid is 0x10FFFF
                    reportInvalid(ch, outPtr-start,
                            String.format(" (above 0x%08x)", LAST_VALID_UNICODE_CHAR));
                }
                cbuf[outPtr++] = (char) (0xD800 + (ch >> 10));
                // hmmh. can this ever be 0? (not legal, at least?)
                lo = (0xDC00 | (ch & 0x03FF));
                // Room for second part?
                if (outPtr >= outEnd) { // nope
                    _surrogate = (char) ch;
                    break main_loop;
                }
            }
            cbuf[outPtr++] = (char) lo;
            if (_ptr > lastValidInputStart) {
                break main_loop;
            }
        }
        int actualLen = (outPtr - start);
        _charCount += actualLen;
        return actualLen;
    }

    /*
    /**********************************************************
    /* Internal methods
    /**********************************************************
     */

    private void reportUnexpectedEOF(int gotBytes, int needed) throws IOException {
        int bytePos = _byteCount + gotBytes, charPos = _charCount;

        throw new CharConversionException("Unexpected EOF in the middle of a 4-byte UTF-32 char: got "+gotBytes+", needed "+needed+", at char #"+charPos+", byte #"+bytePos+")");
    }

    private void reportInvalid(int value, int offset, String msg) throws IOException {
        int bytePos = _byteCount + _ptr - 1, charPos = _charCount + offset;

        throw new CharConversionException("Invalid UTF-32 character 0x"+Integer.toHexString(value)+msg+" at char #"+charPos+", byte #"+bytePos+")");
    }

    /**
     * @param available Number of "unused" bytes in the input buffer
     *
     * @return True, if enough bytes were read to allow decoding of at least
     *   one full character; false if EOF was encountered instead.
     */
    private boolean loadMore(int available) throws IOException {
        _byteCount += (_length - available);

        // Bytes that need to be moved to the beginning of buffer?
        if (available > 0) {
            if (_ptr > 0) {
                System.arraycopy(_buffer, _ptr, _buffer, 0, available);
                _ptr = 0;
            }
            _length = available;
        } else {
            /* Ok; here we can actually reasonably expect an EOF,
             * so let's do a separate read right away:
             */
            _ptr = 0;
            int count = (_in == null) ? -1 : _in.read(_buffer);
            if (count < 1) {
                _length = 0;
                if (count < 0) { // -1
                    if (_managedBuffers) {
                        freeBuffers(); // to help GC?
                    }
                    return false;
                }
                // 0 count is no good; let's err out
                reportStrangeStream();
            }
            _length = count;
        }

        /* Need at least 4 bytes; if we don't get that many, it's an
         * error.
         */
        while (_length < 4) {
            int count = (_in == null) ? -1 : _in.read(_buffer, _length, _buffer.length - _length);
            if (count < 1) {
                if (count < 0) { // -1, EOF... no good!
                    if (_managedBuffers) {
                        freeBuffers(); // to help GC?
                    }
                    reportUnexpectedEOF(_length, 4);
                }
                // 0 count is no good; let's err out
                reportStrangeStream();
            }
            _length += count;
        }
        return true;
    }

    /**
     * This method should be called along with (or instead of) normal
     * close. After calling this method, no further reads should be tried.
     * Method will try to recycle read buffers (if any).
     */
    private void freeBuffers() {
        byte[] buf = _buffer;
        if (buf != null) {
            _buffer = null;
            _context.releaseReadIOBuffer(buf);
        }
    }

    private void reportBounds(char[] cbuf, int start, int len) throws IOException {
        throw new ArrayIndexOutOfBoundsException("read(buf,"+start+","+len+"), cbuf["+cbuf.length+"]");
    }

    private void reportStrangeStream() throws IOException {
        throw new IOException("Strange I/O stream, returned 0 bytes on read");
    }
}

com/fasterxml/jackson/core/io/UTF32Reader.java

 

⇒ Download and Install Jackson Binary Package

⇐ What Is Jackson

⇑ Downloading and Reviewing jackson-*.jar

⇑⇑ Jackson - Java JSON library

2016-02-03, 29610👍, 1💬