0N/A/*
2362N/A * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage com.sun.imageio.plugins.jpeg;
0N/A
0N/Aimport javax.imageio.stream.ImageInputStream;
0N/Aimport javax.imageio.IIOException;
0N/A
0N/Aimport java.io.IOException;
0N/A
0N/A/**
0N/A * A class wrapping a buffer and its state. For efficiency,
0N/A * the members are made visible to other classes in this package.
0N/A */
0N/Aclass JPEGBuffer {
0N/A
0N/A private boolean debug = false;
0N/A
0N/A /**
0N/A * The size of the buffer. This is large enough to hold all
0N/A * known marker segments (other than thumbnails and icc profiles)
0N/A */
0N/A final int BUFFER_SIZE = 4096;
0N/A
0N/A /**
0N/A * The actual buffer.
0N/A */
0N/A byte [] buf;
0N/A
0N/A /**
0N/A * The number of bytes available for reading from the buffer.
0N/A * Anytime data is read from the buffer, this should be updated.
0N/A */
0N/A int bufAvail;
0N/A
0N/A /**
0N/A * A pointer to the next available byte in the buffer. This is
0N/A * used to read data from the buffer and must be updated to
0N/A * move through the buffer.
0N/A */
0N/A int bufPtr;
0N/A
0N/A /**
0N/A * The ImageInputStream buffered.
0N/A */
0N/A ImageInputStream iis;
0N/A
0N/A JPEGBuffer (ImageInputStream iis) {
0N/A buf = new byte[BUFFER_SIZE];
0N/A bufAvail = 0;
0N/A bufPtr = 0;
0N/A this.iis = iis;
0N/A }
0N/A
0N/A /**
0N/A * Ensures that there are at least <code>count</code> bytes available
0N/A * in the buffer, loading more data and moving any remaining
0N/A * bytes to the front. A count of 0 means to just fill the buffer.
0N/A * If the count is larger than the buffer size, just fills the buffer.
0N/A * If the end of the stream is encountered before a non-0 count can
0N/A * be satisfied, an <code>IIOException</code> is thrown with the
0N/A * message "Image Format Error".
0N/A */
0N/A void loadBuf(int count) throws IOException {
0N/A if (debug) {
0N/A System.out.print("loadbuf called with ");
0N/A System.out.print("count " + count + ", ");
0N/A System.out.println("bufAvail " + bufAvail + ", ");
0N/A }
0N/A if (count != 0) {
0N/A if (bufAvail >= count) { // have enough
0N/A return;
0N/A }
0N/A } else {
0N/A if (bufAvail == BUFFER_SIZE) { // already full
0N/A return;
0N/A }
0N/A }
0N/A // First copy any remaining bytes down to the beginning
0N/A if ((bufAvail > 0) && (bufAvail < BUFFER_SIZE)) {
0N/A System.arraycopy(buf, bufPtr, buf, 0, bufAvail);
0N/A }
0N/A // Now fill the rest of the buffer
0N/A int ret = iis.read(buf, bufAvail, buf.length - bufAvail);
0N/A if (debug) {
0N/A System.out.println("iis.read returned " + ret);
0N/A }
0N/A if (ret != -1) {
0N/A bufAvail += ret;
0N/A }
0N/A bufPtr = 0;
0N/A int minimum = Math.min(BUFFER_SIZE, count);
0N/A if (bufAvail < minimum) {
0N/A throw new IIOException ("Image Format Error");
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Fills the data array from the stream, starting with
0N/A * the buffer and then reading directly from the stream
0N/A * if necessary. The buffer is left in an appropriate
0N/A * state. If the end of the stream is encountered, an
0N/A * <code>IIOException</code> is thrown with the
0N/A * message "Image Format Error".
0N/A */
0N/A void readData(byte [] data) throws IOException {
0N/A int count = data.length;
0N/A // First see what's left in the buffer.
0N/A if (bufAvail >= count) { // It's enough
0N/A System.arraycopy(buf, bufPtr, data, 0, count);
0N/A bufAvail -= count;
0N/A bufPtr += count;
0N/A return;
0N/A }
0N/A int offset = 0;
0N/A if (bufAvail > 0) { // Some there, but not enough
0N/A System.arraycopy(buf, bufPtr, data, 0, bufAvail);
0N/A offset = bufAvail;
0N/A count -= bufAvail;
0N/A bufAvail = 0;
0N/A bufPtr = 0;
0N/A }
0N/A // Now read the rest directly from the stream
0N/A if (iis.read(data, offset, count) != count) {
0N/A throw new IIOException ("Image format Error");
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Skips <code>count</code> bytes, leaving the buffer
0N/A * in an appropriate state. If the end of the stream is
0N/A * encountered, an <code>IIOException</code> is thrown with the
0N/A * message "Image Format Error".
0N/A */
0N/A void skipData(int count) throws IOException {
0N/A // First see what's left in the buffer.
0N/A if (bufAvail >= count) { // It's enough
0N/A bufAvail -= count;
0N/A bufPtr += count;
0N/A return;
0N/A }
0N/A if (bufAvail > 0) { // Some there, but not enough
0N/A count -= bufAvail;
0N/A bufAvail = 0;
0N/A bufPtr = 0;
0N/A }
0N/A // Now read the rest directly from the stream
0N/A if (iis.skipBytes(count) != count) {
0N/A throw new IIOException ("Image format Error");
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Push back the remaining contents of the buffer by
0N/A * repositioning the input stream.
0N/A */
0N/A void pushBack() throws IOException {
0N/A iis.seek(iis.getStreamPosition()-bufAvail);
0N/A bufAvail = 0;
0N/A bufPtr = 0;
0N/A }
0N/A
0N/A /**
0N/A * Return the stream position corresponding to the next
0N/A * available byte in the buffer.
0N/A */
0N/A long getStreamPosition() throws IOException {
0N/A return (iis.getStreamPosition()-bufAvail);
0N/A }
0N/A
0N/A /**
0N/A * Scan the buffer until the next 0xff byte, reloading
0N/A * the buffer as necessary. The buffer position is left
0N/A * pointing to the first non-0xff byte after a run of
0N/A * 0xff bytes. If the end of the stream is encountered,
0N/A * an EOI marker is inserted into the buffer and <code>true</code>
0N/A * is returned. Otherwise returns <code>false</code>.
0N/A */
0N/A boolean scanForFF(JPEGImageReader reader) throws IOException {
0N/A boolean retval = false;
0N/A boolean foundFF = false;
0N/A while (foundFF == false) {
0N/A while (bufAvail > 0) {
0N/A if ((buf[bufPtr++] & 0xff) == 0xff) {
0N/A bufAvail--;
0N/A foundFF = true;
0N/A break; // out of inner while
0N/A }
0N/A bufAvail--;
0N/A }
0N/A // Reload the buffer and keep going
0N/A loadBuf(0);
0N/A // Skip any remaining pad bytes
0N/A if (foundFF == true) {
0N/A while ((bufAvail > 0) && (buf[bufPtr] & 0xff) == 0xff) {
0N/A bufPtr++; // Only if it still is 0xff
0N/A bufAvail--;
0N/A }
0N/A }
0N/A if (bufAvail == 0) { // Premature EOF
0N/A // send out a warning, but treat it as EOI
0N/A //reader.warningOccurred(JPEGImageReader.WARNING_NO_EOI);
0N/A retval = true;
0N/A buf[0] = (byte)JPEG.EOI;
0N/A bufAvail = 1;
0N/A bufPtr = 0;
0N/A foundFF = true;
0N/A }
0N/A }
0N/A return retval;
0N/A }
0N/A
0N/A /**
0N/A * Prints the contents of the buffer, in hex.
0N/A * @param count the number of bytes to print,
0N/A * starting at the current available byte.
0N/A */
0N/A void print(int count) {
0N/A System.out.print("buffer has ");
0N/A System.out.print(bufAvail);
0N/A System.out.println(" bytes available");
0N/A if (bufAvail < count) {
0N/A count = bufAvail;
0N/A }
0N/A for (int ptr = bufPtr; count > 0; count--) {
0N/A int val = (int)buf[ptr++] & 0xff;
0N/A System.out.print(" " + Integer.toHexString(val));
0N/A }
0N/A System.out.println();
0N/A }
0N/A
0N/A}