blob: 8771bc984d5dd455a2c5e4f3e9138c7b4bf2de4f [file] [log] [blame]
package org.codehaus.jackson.impl;
import java.io.*;
import org.codehaus.jackson.*;
import org.codehaus.jackson.io.IOContext;
/**
* This is a simple low-level input reader base class, used by
* JSON parser.
* The reason for sub-classing (over composition)
* is due to need for direct access to character buffers
* and positions.
*
* @author Tatu Saloranta
*
* @deprecated Since 1.9 sub-classes should just include code
* from here as is.
*/
@Deprecated
public abstract class ReaderBasedParserBase
extends JsonParserBase
{
/*
/**********************************************************
/* Configuration
/**********************************************************
*/
/**
* Reader that can be used for reading more content, if one
* buffer from input source, but in some cases pre-loaded buffer
* is handed to the parser.
*/
protected Reader _reader;
/*
/**********************************************************
/* Current input data
/**********************************************************
*/
/**
* Current buffer from which data is read; generally data is read into
* buffer from input source.
*/
protected char[] _inputBuffer;
/*
/**********************************************************
/* Life-cycle
/**********************************************************
*/
protected ReaderBasedParserBase(IOContext ctxt, int features, Reader r)
{
super(ctxt, features);
_reader = r;
_inputBuffer = ctxt.allocTokenBuffer();
}
/*
/**********************************************************
/* Overrides
/**********************************************************
*/
@Override
public int releaseBuffered(Writer w) throws IOException
{
int count = _inputEnd - _inputPtr;
if (count < 1) {
return 0;
}
// let's just advance ptr to end
int origPtr = _inputPtr;
w.write(_inputBuffer, origPtr, count);
return count;
}
@Override
public Object getInputSource() {
return _reader;
}
/*
/**********************************************************
/* Low-level reading, other
/**********************************************************
*/
@Override
protected final boolean loadMore() throws IOException
{
_currInputProcessed += _inputEnd;
_currInputRowStart -= _inputEnd;
if (_reader != null) {
int count = _reader.read(_inputBuffer, 0, _inputBuffer.length);
if (count > 0) {
_inputPtr = 0;
_inputEnd = count;
return true;
}
// End of input
_closeInput();
// Should never return 0, so let's fail
if (count == 0) {
throw new IOException("Reader returned 0 characters when trying to read "+_inputEnd);
}
}
return false;
}
protected char getNextChar(String eofMsg)
throws IOException, JsonParseException
{
if (_inputPtr >= _inputEnd) {
if (!loadMore()) {
_reportInvalidEOF(eofMsg);
}
}
return _inputBuffer[_inputPtr++];
}
@Override
protected void _closeInput() throws IOException
{
/* 25-Nov-2008, tatus: As per [JACKSON-16] we are not to call close()
* on the underlying Reader, unless we "own" it, or auto-closing
* feature is enabled.
* One downside is that when using our optimized
* Reader (granted, we only do that for UTF-32...) this
* means that buffer recycling won't work correctly.
*/
if (_reader != null) {
if (_ioContext.isResourceManaged() || isEnabled(Feature.AUTO_CLOSE_SOURCE)) {
_reader.close();
}
_reader = null;
}
}
/**
* Method called to release internal buffers owned by the base
* reader. This may be called along with {@link #_closeInput} (for
* example, when explicitly closing this reader instance), or
* separately (if need be).
*/
@Override
protected void _releaseBuffers()
throws IOException
{
super._releaseBuffers();
char[] buf = _inputBuffer;
if (buf != null) {
_inputBuffer = null;
_ioContext.releaseTokenBuffer(buf);
}
}
/*
/**********************************************************
/* Helper methods for subclasses
/**********************************************************
*/
/**
* Helper method for checking whether input matches expected token
*
* @since 1.8
*/
protected final boolean _matchToken(String matchStr, int i)
throws IOException, JsonParseException
{
final int len = matchStr.length();
do {
if (_inputPtr >= _inputEnd) {
if (!loadMore()) {
_reportInvalidEOFInValue();
}
}
if (_inputBuffer[_inputPtr] != matchStr.charAt(i)) {
_reportInvalidToken(matchStr.substring(0, i), "'null', 'true', 'false' or NaN");
}
++_inputPtr;
} while (++i < len);
// but let's also ensure we either get EOF, or non-alphanum char...
if (_inputPtr >= _inputEnd) {
if (!loadMore()) {
return true;
}
}
char c = _inputBuffer[_inputPtr];
// if Java letter, it's a problem tho
if (Character.isJavaIdentifierPart(c)) {
++_inputPtr;
_reportInvalidToken(matchStr.substring(0, i), "'null', 'true', 'false' or NaN");
}
return true;
}
protected void _reportInvalidToken(String matchedPart, String msg)
throws IOException, JsonParseException
{
StringBuilder sb = new StringBuilder(matchedPart);
/* Let's just try to find what appears to be the token, using
* regular Java identifier character rules. It's just a heuristic,
* nothing fancy here.
*/
while (true) {
if (_inputPtr >= _inputEnd) {
if (!loadMore()) {
break;
}
}
char c = _inputBuffer[_inputPtr];
if (!Character.isJavaIdentifierPart(c)) {
break;
}
++_inputPtr;
sb.append(c);
}
_reportError("Unrecognized token '"+sb.toString()+"': was expecting ");
}
}