001 /*
002 * Copyright (c) Andrey Kuznetsov. All Rights Reserved.
003 *
004 * http://uio.imagero.com
005 *
006 * Redistribution and use in source and binary forms, with or without
007 * modification, are permitted provided that the following conditions are met:
008 *
009 * o Redistributions of source code must retain the above copyright notice,
010 * this list of conditions and the following disclaimer.
011 *
012 * o Redistributions in binary form must reproduce the above copyright notice,
013 * this list of conditions and the following disclaimer in the documentation
014 * and/or other materials provided with the distribution.
015 *
016 * o Neither the name of Andrey Kuznetsov nor the names of
017 * its contributors may be used to endorse or promote products derived
018 * from this software without specific prior written permission.
019 *
020 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
021 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
022 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
023 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
024 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
025 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
026 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
027 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
028 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
029 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
030 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
031 */
032
033 package com.imagero.uio.io;
034
035 import java.io.FilterInputStream;
036 import java.io.IOException;
037 import java.io.InputStream;
038
039 /**
040 * Read one or more App13 block(s)
041 * @author Andrey Kuznetsov
042 */
043 public class App13InputStream extends FilterInputStream {
044
045 private static final byte[] ID8 = "8BIM".getBytes();
046 private static final byte[] PHOTOSHOP = "Photoshop3.0".getBytes();
047
048 boolean finished;
049
050 /**
051 * Create new App13InputStream.
052 * Note that <code>in</code> should support <code>mark()</code>
053 * @param in InputStream
054 * @throws IOException
055 */
056 public App13InputStream(InputStream in) throws IOException {
057 super(in);
058 }
059
060 void initBlock() throws IOException {
061 in.mark(3);
062 int marker = in.read();
063 int app13 = in.read();
064 if (marker != 0xFF || app13 != 0xED) {
065 finished = true;
066 in.reset();
067 return;
068 }
069 length = (in.read() << 8) | (in.read() & 0xFF) - 2;
070
071 in.mark(4);
072 byte[] b = new byte[4];
073 for (int i = 0; i < 4; i++) {
074 b[i] = (byte) in.read();
075 }
076 in.reset();
077
078 boolean photoshop = true;
079
080 //some applications "forget" to write 'Photoshop 3.0' Identifier
081 for (int i = 0; i < b.length; i++) {
082 if (b[i] != PHOTOSHOP[i]) {
083 photoshop = false;
084 break;
085 }
086 }
087
088 if (photoshop) {
089 for (int i = 0; i < 14; i++) {
090 in.read();
091 }
092 length -= 14;
093 }
094 else {
095 for (int i = 0; i < b.length; i++) {
096 if (b[i] != ID8[i]) {
097 throw new IOException("not App13 stream");
098 }
099 }
100 }
101 }
102
103 int length;
104
105 public int read() throws IOException {
106 if (finished) {
107 return -1;
108 }
109 if (length == 0) {
110 initBlock();
111 if (finished) {
112 return -1;
113 }
114 }
115 length--;
116 return super.read();
117 }
118
119 public int read(byte b[]) throws IOException {
120 return read(b, 0, b.length);
121 }
122
123 public int read(byte b[], int off, int len) throws IOException {
124 if (b == null) {
125 throw new NullPointerException();
126 }
127 if (off + len > b.length || off < 0) {
128 throw new ArrayIndexOutOfBoundsException();
129 }
130 int read = 1;
131 int a = read();
132 if (a == -1) {
133 return -1;
134 }
135 b[off] = (byte) a;
136 for (int i = off + 1; i < len; i++) {
137 a = read();
138 if (a == -1) {
139 break;
140 }
141 read++;
142 b[i] = (byte) a;
143 }
144 return read;
145 }
146
147 public long skip(long n) throws IOException {
148 long remaining = n;
149 while (remaining > 0) {
150 int a = read();
151 if (a == -1) {
152 break;
153 }
154 remaining--;
155 }
156 return n - remaining;
157 }
158
159 public int available() throws IOException {
160 if (finished) {
161 return 0;
162 }
163 if (length == 0) {
164 initBlock();
165 if (finished) {
166 return 0;
167 }
168 }
169 return length;
170 }
171
172 public synchronized void mark(int readlimit) {
173
174 }
175
176 public synchronized void reset() throws IOException {
177
178 }
179
180 public boolean markSupported() {
181 return false;
182 }
183 }