1. /*
  2. * @(#)JPEGBuffer.java 1.7 03/01/23
  3. *
  4. * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package com.sun.imageio.plugins.jpeg;
  8. import javax.imageio.stream.ImageInputStream;
  9. import javax.imageio.IIOException;
  10. import java.io.IOException;
  11. /**
  12. * A class wrapping a buffer and its state. For efficiency,
  13. * the members are made visible to other classes in this package.
  14. */
  15. class JPEGBuffer {
  16. private boolean debug = false;
  17. /**
  18. * The size of the buffer. This is large enough to hold all
  19. * known marker segments (other than thumbnails and icc profiles)
  20. */
  21. final int BUFFER_SIZE = 4096;
  22. /**
  23. * The actual buffer.
  24. */
  25. byte [] buf;
  26. /**
  27. * The number of bytes available for reading from the buffer.
  28. * Anytime data is read from the buffer, this should be updated.
  29. */
  30. int bufAvail;
  31. /**
  32. * A pointer to the next available byte in the buffer. This is
  33. * used to read data from the buffer and must be updated to
  34. * move through the buffer.
  35. */
  36. int bufPtr;
  37. /**
  38. * The ImageInputStream buffered.
  39. */
  40. ImageInputStream iis;
  41. JPEGBuffer (ImageInputStream iis) {
  42. buf = new byte[BUFFER_SIZE];
  43. bufAvail = 0;
  44. bufPtr = 0;
  45. this.iis = iis;
  46. }
  47. /**
  48. * Ensures that there are at least <code>count</code> bytes available
  49. * in the buffer, loading more data and moving any remaining
  50. * bytes to the front. A count of 0 means to just fill the buffer.
  51. * If the count is larger than the buffer size, just fills the buffer.
  52. * If the end of the stream is encountered before a non-0 count can
  53. * be satisfied, an <code>IIOException</code> is thrown with the
  54. * message "Image Format Error".
  55. */
  56. void loadBuf(int count) throws IOException {
  57. if (debug) {
  58. System.out.print("loadbuf called with ");
  59. System.out.print("count " + count + ", ");
  60. System.out.println("bufAvail " + bufAvail + ", ");
  61. }
  62. if (count != 0) {
  63. if (bufAvail >= count) { // have enough
  64. return;
  65. }
  66. } else {
  67. if (bufAvail == BUFFER_SIZE) { // already full
  68. return;
  69. }
  70. }
  71. // First copy any remaining bytes down to the beginning
  72. if ((bufAvail > 0) && (bufAvail < BUFFER_SIZE)) {
  73. System.arraycopy(buf, bufPtr, buf, 0, bufAvail);
  74. }
  75. // Now fill the rest of the buffer
  76. int ret = iis.read(buf, bufAvail, buf.length - bufAvail);
  77. if (debug) {
  78. System.out.println("iis.read returned " + ret);
  79. }
  80. if (ret != -1) {
  81. bufAvail += ret;
  82. }
  83. bufPtr = 0;
  84. int minimum = Math.min(BUFFER_SIZE, count);
  85. if (bufAvail < minimum) {
  86. throw new IIOException ("Image Format Error");
  87. }
  88. }
  89. /**
  90. * Fills the data array from the stream, starting with
  91. * the buffer and then reading directly from the stream
  92. * if necessary. The buffer is left in an appropriate
  93. * state. If the end of the stream is encountered, an
  94. * <code>IIOException</code> is thrown with the
  95. * message "Image Format Error".
  96. */
  97. void readData(byte [] data) throws IOException {
  98. int count = data.length;
  99. // First see what's left in the buffer.
  100. if (bufAvail >= count) { // It's enough
  101. System.arraycopy(buf, bufPtr, data, 0, count);
  102. bufAvail -= count;
  103. bufPtr += count;
  104. return;
  105. }
  106. int offset = 0;
  107. if (bufAvail > 0) { // Some there, but not enough
  108. System.arraycopy(buf, bufPtr, data, 0, bufAvail);
  109. offset = bufAvail;
  110. count -= bufAvail;
  111. bufAvail = 0;
  112. bufPtr = 0;
  113. }
  114. // Now read the rest directly from the stream
  115. if (iis.read(data, offset, count) != count) {
  116. throw new IIOException ("Image format Error");
  117. }
  118. }
  119. /**
  120. * Skips <code>count</code> bytes, leaving the buffer
  121. * in an appropriate state. If the end of the stream is
  122. * encountered, an <code>IIOException</code> is thrown with the
  123. * message "Image Format Error".
  124. */
  125. void skipData(int count) throws IOException {
  126. // First see what's left in the buffer.
  127. if (bufAvail >= count) { // It's enough
  128. bufAvail -= count;
  129. bufPtr += count;
  130. return;
  131. }
  132. if (bufAvail > 0) { // Some there, but not enough
  133. count -= bufAvail;
  134. bufAvail = 0;
  135. bufPtr = 0;
  136. }
  137. // Now read the rest directly from the stream
  138. if (iis.skipBytes(count) != count) {
  139. throw new IIOException ("Image format Error");
  140. }
  141. }
  142. /**
  143. * Push back the remaining contents of the buffer by
  144. * repositioning the input stream.
  145. */
  146. void pushBack() throws IOException {
  147. iis.seek(iis.getStreamPosition()-bufAvail);
  148. bufAvail = 0;
  149. bufPtr = 0;
  150. }
  151. /**
  152. * Return the stream position corresponding to the next
  153. * available byte in the buffer.
  154. */
  155. long getStreamPosition() throws IOException {
  156. return (iis.getStreamPosition()-bufAvail);
  157. }
  158. /**
  159. * Scan the buffer until the next 0xff byte, reloading
  160. * the buffer as necessary. The buffer position is left
  161. * pointing to the first non-0xff byte after a run of
  162. * 0xff bytes. If the end of the stream is encountered,
  163. * an EOI marker is inserted into the buffer and <code>true</code>
  164. * is returned. Otherwise returns <code>false</code>.
  165. */
  166. boolean scanForFF(JPEGImageReader reader) throws IOException {
  167. boolean retval = false;
  168. boolean foundFF = false;
  169. while (foundFF == false) {
  170. while (bufAvail > 0) {
  171. if ((buf[bufPtr++] & 0xff) == 0xff) {
  172. bufAvail--;
  173. foundFF = true;
  174. break; // out of inner while
  175. }
  176. bufAvail--;
  177. }
  178. // Reload the buffer and keep going
  179. loadBuf(0);
  180. // Skip any remaining pad bytes
  181. if (foundFF == true) {
  182. while ((bufAvail > 0) && (buf[bufPtr] & 0xff) == 0xff) {
  183. bufPtr++; // Only if it still is 0xff
  184. bufAvail--;
  185. }
  186. }
  187. if (bufAvail == 0) { // Premature EOF
  188. // send out a warning, but treat it as EOI
  189. //reader.warningOccurred(JPEGImageReader.WARNING_NO_EOI);
  190. retval = true;
  191. buf[0] = (byte)JPEG.EOI;
  192. bufAvail = 1;
  193. bufPtr = 0;
  194. foundFF = true;
  195. }
  196. }
  197. return retval;
  198. }
  199. /**
  200. * Prints the contents of the buffer, in hex.
  201. * @param count the number of bytes to print,
  202. * starting at the current available byte.
  203. */
  204. void print(int count) {
  205. System.out.print("buffer has ");
  206. System.out.print(bufAvail);
  207. System.out.println(" bytes available");
  208. if (bufAvail < count) {
  209. count = bufAvail;
  210. }
  211. for (int ptr = bufPtr; count > 0; count--) {
  212. int val = (int)buf[ptr++] & 0xff;
  213. System.out.print(" " + Integer.toHexString(val));
  214. }
  215. System.out.println();
  216. }
  217. }