/imageio/imageio-core/src/main/java/com/twelvemonkeys/imageio/util/IIOInputStreamAdapter.java

https://github.com/conceptboard/TwelveMonkeys · Java · 177 lines · 90 code · 21 blank · 66 comment · 14 complexity · 8992d0f7efc9c51cee4dc8d6e2835a2b MD5 · raw file

  1. /*
  2. * Copyright (c) 2008, Harald Kuhr
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * * Neither the name "TwelveMonkeys" nor the
  13. * names of its contributors may be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  17. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  18. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  19. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  20. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  21. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  22. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  23. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  24. * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  25. * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  26. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27. */
  28. package com.twelvemonkeys.imageio.util;
  29. import javax.imageio.stream.ImageInputStream;
  30. import java.io.IOException;
  31. import java.io.InputStream;
  32. /**
  33. * IIOInputStreamAdapter
  34. * <p/>
  35. * Note: You should always wrap this stream in a {@code BufferedInputStream}.
  36. * If not, performance may degrade significantly.
  37. *
  38. * @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
  39. * @author last modified by $Author: haraldk$
  40. * @version $Id: IIOInputStreamAdapter.java,v 1.0 Sep 26, 2007 11:35:59 AM haraldk Exp$
  41. */
  42. class IIOInputStreamAdapter extends InputStream {
  43. private ImageInputStream input;
  44. private final boolean hasLength;
  45. private long left;
  46. private long markPosition;
  47. // TODO: Enforce stream boundaries!
  48. // TODO: Stream start position....
  49. /**
  50. * Creates an {@code InputStream} that reads from the given {@code ImageInputStream}.
  51. * The input stream will read from the current stream position, until the end of the
  52. * underlying stream.
  53. *
  54. * @param pInput the {@code ImageInputStream} to read from.
  55. */
  56. public IIOInputStreamAdapter(final ImageInputStream pInput) {
  57. this(pInput, -1, false);
  58. }
  59. /**
  60. * Creates an {@code InputStream} that reads from the given {@code ImageInputStream}.
  61. * The input stream will read from the current stream position, until at most
  62. * {@code pLength} bytes has been read.
  63. *
  64. * @param pInput the {@code ImageInputStream} to read from.
  65. * @param pLength the length of the stream
  66. */
  67. public IIOInputStreamAdapter(final ImageInputStream pInput, final long pLength) {
  68. this(pInput, pLength, true);
  69. }
  70. private IIOInputStreamAdapter(ImageInputStream pInput, long pLength, boolean pHasLength) {
  71. if (pInput == null) {
  72. throw new IllegalArgumentException("stream == null");
  73. }
  74. if (pHasLength && pLength < 0) {
  75. throw new IllegalArgumentException("length < 0");
  76. }
  77. input = pInput;
  78. hasLength = pHasLength;
  79. left = pLength;
  80. }
  81. /**
  82. * Marks this stream as closed.
  83. * This implementation does <em>not</em> close the underlying stream.
  84. */
  85. public void close() throws IOException {
  86. if (hasLength) {
  87. input.seek(input.getStreamPosition() + left);
  88. }
  89. left = 0;
  90. input = null;
  91. }
  92. public int available() throws IOException {
  93. if (hasLength) {
  94. return left > 0 ? (int) Math.min(Integer.MAX_VALUE, left) : 0;
  95. }
  96. return 0; // We don't really know, so we say 0 to be safe.
  97. }
  98. @Override
  99. public boolean markSupported() {
  100. return true;
  101. }
  102. public void mark(int pReadLimit) {
  103. try {
  104. markPosition = input.getStreamPosition();
  105. }
  106. catch (IOException e) {
  107. // Let's hope this never happens, because it's not possible to reset then...
  108. throw new IllegalStateException("Could not read stream position: " + e.getMessage(), e);
  109. }
  110. }
  111. public void reset() throws IOException {
  112. long diff = input.getStreamPosition() - markPosition;
  113. input.seek(markPosition);
  114. left += diff;
  115. }
  116. public int read() throws IOException {
  117. if (hasLength && left-- <= 0) {
  118. left = 0;
  119. return -1;
  120. }
  121. return input.read();
  122. }
  123. public final int read(byte[] pBytes) throws IOException {
  124. return read(pBytes, 0, pBytes.length);
  125. }
  126. public int read(final byte[] pBytes, final int pOffset, final int pLength) throws IOException {
  127. if (hasLength && left <= 0) {
  128. return -1;
  129. }
  130. int read = input.read(pBytes, pOffset, (int) findMaxLen(pLength));
  131. if (hasLength) {
  132. left = read < 0 ? 0 : left - read;
  133. }
  134. return read;
  135. }
  136. /**
  137. * Finds the maximum number of bytes we can read or skip, from this stream.
  138. * The number will be in the range {@code [0 ... bytes left]}.
  139. *
  140. * @param pLength the requested length
  141. * @return the maximum number of bytes to read
  142. */
  143. private long findMaxLen(long pLength) {
  144. if (hasLength && left < pLength) {
  145. return Math.max(left, 0);
  146. }
  147. else {
  148. return Math.max(pLength, 0);
  149. }
  150. }
  151. public long skip(long pLength) throws IOException {
  152. long skipped = input.skipBytes(findMaxLen(pLength)); // Skips 0 or more, never -1
  153. left -= skipped;
  154. return skipped;
  155. }
  156. }