1 /* 2 * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.imageio.plugins.jpeg; 27 28 import javax.imageio.stream.ImageInputStream; 29 import javax.imageio.IIOException; 30 31 import java.io.IOException; 32 33 /** 34 * A class wrapping a buffer and its state. For efficiency, 35 * the members are made visible to other classes in this package. 36 */ 37 class JPEGBuffer { 38 39 private boolean debug = false; 40 41 /** 42 * The size of the buffer. This is large enough to hold all 43 * known marker segments (other than thumbnails and icc profiles) 44 */ 45 final int BUFFER_SIZE = 4096; 46 47 /** 48 * The actual buffer. 49 */ 50 byte [] buf; 51 52 /** 53 * The number of bytes available for reading from the buffer. 54 * Anytime data is read from the buffer, this should be updated. 55 */ 56 int bufAvail; 57 58 /** 59 * A pointer to the next available byte in the buffer. This is 60 * used to read data from the buffer and must be updated to 61 * move through the buffer. 62 */ 63 int bufPtr; 64 65 /** 66 * The ImageInputStream buffered. 67 */ 68 ImageInputStream iis; 69 70 JPEGBuffer (ImageInputStream iis) { 71 buf = new byte[BUFFER_SIZE]; 72 bufAvail = 0; 73 bufPtr = 0; 74 this.iis = iis; 75 } 76 77 /** 78 * Ensures that there are at least {@code count} bytes available 79 * in the buffer, loading more data and moving any remaining 80 * bytes to the front. A count of 0 means to just fill the buffer. 81 * If the count is larger than the buffer size, just fills the buffer. 82 * If the end of the stream is encountered before a non-0 count can 83 * be satisfied, an {@code IIOException} is thrown with the 84 * message "Image Format Error". 85 */ 86 void loadBuf(int count) throws IOException { 87 if (debug) { 88 System.out.print("loadbuf called with "); 89 System.out.print("count " + count + ", "); 90 System.out.println("bufAvail " + bufAvail + ", "); 91 } 92 if (count != 0) { 93 if (bufAvail >= count) { // have enough 94 return; 95 } 96 } else { 97 if (bufAvail == BUFFER_SIZE) { // already full 98 return; 99 } 100 } 101 // First copy any remaining bytes down to the beginning 102 if ((bufAvail > 0) && (bufAvail < BUFFER_SIZE)) { 103 System.arraycopy(buf, bufPtr, buf, 0, bufAvail); 104 } 105 // Now fill the rest of the buffer 106 int ret = iis.read(buf, bufAvail, buf.length - bufAvail); 107 if (debug) { 108 System.out.println("iis.read returned " + ret); 109 } 110 if (ret != -1) { 111 bufAvail += ret; 112 } 113 bufPtr = 0; 114 int minimum = Math.min(BUFFER_SIZE, count); 115 if (bufAvail < minimum) { 116 throw new IIOException ("Image Format Error"); 117 } 118 } 119 120 /** 121 * Fills the data array from the stream, starting with 122 * the buffer and then reading directly from the stream 123 * if necessary. The buffer is left in an appropriate 124 * state. If the end of the stream is encountered, an 125 * {@code IIOException} is thrown with the 126 * message "Image Format Error". 127 */ 128 void readData(byte [] data) throws IOException { 129 int count = data.length; 130 // First see what's left in the buffer. 131 if (bufAvail >= count) { // It's enough 132 System.arraycopy(buf, bufPtr, data, 0, count); 133 bufAvail -= count; 134 bufPtr += count; 135 return; 136 } 137 int offset = 0; 138 if (bufAvail > 0) { // Some there, but not enough 139 System.arraycopy(buf, bufPtr, data, 0, bufAvail); 140 offset = bufAvail; 141 count -= bufAvail; 142 bufAvail = 0; 143 bufPtr = 0; 144 } 145 // Now read the rest directly from the stream 146 if (iis.read(data, offset, count) != count) { 147 throw new IIOException ("Image format Error"); 148 } 149 } 150 151 /** 152 * Skips {@code count} bytes, leaving the buffer 153 * in an appropriate state. If the end of the stream is 154 * encountered, an {@code IIOException} is thrown with the 155 * message "Image Format Error". 156 */ 157 void skipData(int count) throws IOException { 158 // First see what's left in the buffer. 159 if (bufAvail >= count) { // It's enough 160 bufAvail -= count; 161 bufPtr += count; 162 return; 163 } 164 if (bufAvail > 0) { // Some there, but not enough 165 count -= bufAvail; 166 bufAvail = 0; 167 bufPtr = 0; 168 } 169 // Now read the rest directly from the stream 170 if (iis.skipBytes(count) != count) { 171 throw new IIOException ("Image format Error"); 172 } 173 } 174 175 /** 176 * Push back the remaining contents of the buffer by 177 * repositioning the input stream. 178 */ 179 void pushBack() throws IOException { 180 iis.seek(iis.getStreamPosition()-bufAvail); 181 bufAvail = 0; 182 bufPtr = 0; 183 } 184 185 /** 186 * Return the stream position corresponding to the next 187 * available byte in the buffer. 188 */ 189 long getStreamPosition() throws IOException { 190 return (iis.getStreamPosition()-bufAvail); 191 } 192 193 /** 194 * Scan the buffer until the next 0xff byte, reloading 195 * the buffer as necessary. The buffer position is left 196 * pointing to the first non-0xff byte after a run of 197 * 0xff bytes. If the end of the stream is encountered, 198 * an EOI marker is inserted into the buffer and {@code true} 199 * is returned. Otherwise returns {@code false}. 200 */ 201 boolean scanForFF(JPEGImageReader reader) throws IOException { 202 boolean retval = false; 203 boolean foundFF = false; 204 while (foundFF == false) { 205 while (bufAvail > 0) { 206 if ((buf[bufPtr++] & 0xff) == 0xff) { 207 bufAvail--; 208 foundFF = true; 209 break; // out of inner while 210 } 211 bufAvail--; 212 } 213 // Reload the buffer and keep going 214 loadBuf(0); 215 // Skip any remaining pad bytes 216 if (foundFF == true) { 217 while ((bufAvail > 0) && (buf[bufPtr] & 0xff) == 0xff) { 218 bufPtr++; // Only if it still is 0xff 219 bufAvail--; 220 } 221 } 222 if (bufAvail == 0) { // Premature EOF 223 // send out a warning, but treat it as EOI 224 //reader.warningOccurred(JPEGImageReader.WARNING_NO_EOI); 225 retval = true; 226 buf[0] = (byte)JPEG.EOI; 227 bufAvail = 1; 228 bufPtr = 0; 229 foundFF = true; 230 } 231 } 232 return retval; 233 } 234 235 /** 236 * Prints the contents of the buffer, in hex. 237 * @param count the number of bytes to print, 238 * starting at the current available byte. 239 */ 240 void print(int count) { 241 System.out.print("buffer has "); 242 System.out.print(bufAvail); 243 System.out.println(" bytes available"); 244 if (bufAvail < count) { 245 count = bufAvail; 246 } 247 for (int ptr = bufPtr; count > 0; count--) { 248 int val = (int)buf[ptr++] & 0xff; 249 System.out.print(" " + Integer.toHexString(val)); 250 } 251 System.out.println(); 252 } 253 254 } --- EOF ---