All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.antiaction.common.json.JSONDecoderCharset Maven / Gradle / Ivy

/*
 * JSON library.
 * Copyright 2012-2013 Antiaction (http://antiaction.com/)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.antiaction.common.json;

import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CoderMalfunctionError;
import java.nio.charset.CoderResult;
import java.nio.charset.CodingErrorAction;

/**
 * JSON Decoder implementation using a given Charset.
 * This implementation is not thread safe!
 *
 * @author Nicholas
 * Created on 10/09/2012
 */
public class JSONDecoderCharset implements JSONDecoder {

	/** Charset Decoder used. */
	protected CharsetDecoder decoder;

	/** Byte array used by ByteBuffer. */
	protected byte[] byteArray;

	/** Internal staging byte buffer prior to decoding. */
	protected ByteBuffer byteBuffer;

	/** InputStream currently used. */
	protected InputStream in;

	/** Is inputstream EOF. */
	protected boolean bEof;

	/** Conversion errors pending where replacement still has to be written to the char buffer. */
	protected int errorsPending;

	/** Has a conversion error occurred. */
	protected boolean bConversionError;

	/** Replacement string used in conversion errors. */
	protected String replacement;

	/** Length of replacement string. */
	protected int replacementLength;

	/**
	 * Construct a reusable JSON Decoder using the provided Charset using the default buffer size.
	 * @param charset charset to use when decoding text
	 */
	public JSONDecoderCharset(Charset charset) {
		this( charset, 8192 );
	}

	/**
	 * Construct a reusable JSON Decoder using the provided Charset and buffer size.
	 * @param charset charset to use when decoding text
	 * @param bufferSize size of the internal buffers used for converting
	 */
	public JSONDecoderCharset(Charset charset, int bufferSize) {
		decoder = charset.newDecoder();
		decoder.onMalformedInput( CodingErrorAction.REPORT );
		decoder.onUnmappableCharacter( CodingErrorAction.REPORT );
		byteArray = new byte[ bufferSize ];
		byteBuffer = ByteBuffer.wrap( byteArray );
	}

	@Override
	public void init(InputStream in) {
		decoder.reset();
		this.in = in;
		bEof = false;
		errorsPending = 0;
		bConversionError = false;
		replacement = decoder.replacement();
		replacementLength = replacement.length();
		byteBuffer.clear();
	}

	/*
	 * Assume charBuffer in write mode.
	 * @see com.antiaction.common.json.JSONDecoder#fill(java.nio.CharBuffer)
	 */
	@Override
	public boolean fill(CharBuffer charBuffer) throws IOException {
		int read;
		while ( errorsPending > 0 && charBuffer.remaining() >= replacementLength ) {
			charBuffer.append( replacement );
			--errorsPending;
		}
		if ( charBuffer.hasRemaining() ) {
			while ( !bEof && byteBuffer.hasRemaining() ) {
				read = in.read( byteArray, byteBuffer.position(), byteBuffer.remaining() );
				if ( read != -1 ) {
					byteBuffer.position( byteBuffer.position() + read );
				}
				else {
					bEof = true;
				}
			}
			// Switch buffer to read mode.
			byteBuffer.flip();
			if ( byteBuffer.hasRemaining() ) {
				try {
					boolean bDecodeLoop = true;
					while ( bDecodeLoop ) {
						CoderResult result = decoder.decode( byteBuffer, charBuffer, bEof );
						if ( result == CoderResult.UNDERFLOW ) {
							bDecodeLoop = false;
						}
						else if ( result == CoderResult.OVERFLOW ) {
							bDecodeLoop = false;
						}
						else if ( result.isError() ) {
							bConversionError = true;
							byteBuffer.position( Math.min( byteBuffer.position() + result.length(), byteBuffer.limit() ) );
							//errorsPending += result.length();
							++errorsPending;
							while ( errorsPending > 0 && charBuffer.remaining() >= replacementLength ) {
								charBuffer.append( replacement );
								--errorsPending;
							}
							if ( errorsPending > 0 ) {
								   bDecodeLoop = false;
							}
						}
					}
				}
				catch (CoderMalfunctionError e) {
					throw new IOException( "Colder malfunction!", e );
				}
			}
			// Switch buffer to write mode.
			byteBuffer.compact();
		}
		return (bEof && byteBuffer.position() == 0 && errorsPending == 0);
	}

	@Override
	public boolean isEof() {
		return (bEof && byteBuffer.position() == 0 && errorsPending == 0);
	}

	@Override
	public boolean hasConversionError() {
		return bConversionError;
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy