/*****************************************************************************
 * Copyright (C) The Apache Software Foundation. All rights reserved.        *
 * ------------------------------------------------------------------------- *
 * This software is published under the terms of the Apache Software License *
 * version 1.1, a copy of which has been included with this distribution in  *
 * the LICENSE file.                                                         *
 *****************************************************************************/

package org.apache.batik.util.io;

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

/**
 * This class represents an object which decodes UTF-16 characters from
 * a stream of bytes.
 *
 * @author <a href="mailto:stephane@hillion.org">Stephane Hillion</a>
 * @version $Id: UTF16Decoder.java,v 1.2 2003/04/11 13:59:35 vhardy Exp $
 */
public class UTF16Decoder extends AbstractCharDecoder {

    /**
     * Whether the stream's byte-order is big-endian.
     */
    protected boolean bigEndian;
    
    /**
     * Creates a new UTF16Decoder.
     * It is assumed that the byte-order mark is present.
     * @param is The stream to decode.
     */
    public UTF16Decoder(InputStream is) throws IOException {
        super(is);
        // Byte-order detection.
        int b1 = is.read();
        if (b1 == -1) {
            endOfStreamError("UTF-16");
        }
        int b2 = is.read();
        if (b2 == -1) {
            endOfStreamError("UTF-16");
        }
        int m = (((b1 & 0xff) << 8) | (b2 & 0xff));
        switch (m) {
        case 0xfeff:
            bigEndian = true;
            break;
        case 0xfffe:
            break;
        default:
            charError("UTF-16");
        }
    }

    /**
     * Creates a new UTF16Decoder.
     * @param is The stream to decode. 
     * @param be Whether or not the given stream's byte-order is
     * big-endian.
     */
    public UTF16Decoder(InputStream is, boolean be) {
        super(is);
        bigEndian = be;
    }

    /**
     * Reads the next character.
     * @return a character or END_OF_STREAM.
     */
    public int readChar() throws IOException {
        if (position == count) {
            fillBuffer();
        }
        if (count == -1) {
            return END_OF_STREAM;
        }
        byte b1 = buffer[position++];
        if (position == count) {
            fillBuffer();
        }
        if (count == -1) {
            endOfStreamError("UTF-16");
        }
        byte b2 = buffer[position++];
        int c = (bigEndian)
            ? (((b1 & 0xff) << 8) | (b2 & 0xff))
            : (((b2 & 0xff) << 8) | (b1 & 0xff));
        if (c == 0xfffe) {
            charError("UTF-16");
        }
        return c;
    }
}
