View Javadoc
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</code> 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</code> 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</code> 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</code> bytes, leaving the buffer
153      * in an appropriate state.  If the end of the stream is
154      * encountered, an <code>IIOException</code> 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</code>
199      * is returned.  Otherwise returns <code>false</code>.
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 }