001: /*
002:
003: Licensed to the Apache Software Foundation (ASF) under one or more
004: contributor license agreements. See the NOTICE file distributed with
005: this work for additional information regarding copyright ownership.
006: The ASF licenses this file to You under the Apache License, Version 2.0
007: (the "License"); you may not use this file except in compliance with
008: the License. You may obtain a copy of the License at
009:
010: http://www.apache.org/licenses/LICENSE-2.0
011:
012: Unless required by applicable law or agreed to in writing, software
013: distributed under the License is distributed on an "AS IS" BASIS,
014: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: See the License for the specific language governing permissions and
016: limitations under the License.
017:
018: */
019: package org.apache.batik.ext.awt.image.spi;
020:
021: import java.io.IOException;
022: import java.io.InputStream;
023: import java.io.StreamCorruptedException;
024:
025: /**
026: * This Image tag registry entry is built around the notion of magic
027: * numbers. These are strings of bytes that are at a well known
028: * location in the input stream (often the start).
029: *
030: * This base class can handle the compatiblity check based on a list
031: * of Magic Numbers that correspond to your format (Some formats have
032: * multiple magic numbers associated with them).
033: *
034: * @version $Id: MagicNumberRegistryEntry.java 498740 2007-01-22 18:35:57Z dvholten $
035: */
036: public abstract class MagicNumberRegistryEntry extends
037: AbstractRegistryEntry implements StreamRegistryEntry {
038:
039: public static final float PRIORITY = 1000;
040:
041: /**
042: * Inner class that represents one magic number. Simply consists
043: * of an offset in bytes from the start of the file, and a byte
044: * array that must match.
045: */
046: public static class MagicNumber {
047: int offset;
048: byte[] magicNumber;
049: byte[] buffer;
050:
051: /**
052: * Constructor.
053: * @param offset the location of the magic number in file.
054: * @param magicNumber the sequence of bytes that must match.
055: */
056: public MagicNumber(int offset, byte[] magicNumber) {
057: this .offset = offset;
058: this .magicNumber = (byte[]) magicNumber.clone();
059: buffer = new byte[magicNumber.length];
060: }
061:
062: /**
063: * Returns the maximum number of bytes that will be read for
064: * this magic number compairison.
065: */
066: int getReadlimit() {
067: return offset + magicNumber.length;
068: }
069:
070: /**
071: * Performs the check of is.
072: */
073: boolean isMatch(InputStream is) throws StreamCorruptedException {
074: int idx = 0;
075: is.mark(getReadlimit());
076: try {
077: // Skip to the offset location.
078: while (idx < offset) {
079: int rn = (int) is.skip(offset - idx);
080: if (rn == -1)
081: return false;
082: idx += rn;
083: }
084:
085: idx = 0;
086: while (idx < buffer.length) {
087: int rn = is.read(buffer, idx, buffer.length - idx);
088: if (rn == -1)
089: return false;
090: idx += rn;
091: }
092:
093: for (int i = 0; i < magicNumber.length; i++) {
094: if (magicNumber[i] != buffer[i])
095: return false;
096: }
097: } catch (IOException ioe) {
098: return false;
099: } finally {
100: try {
101: // Make sure we always put back what we have read.
102: // If this throws an IOException then the current
103: // stream should be closed an reopend by the registry.
104: is.reset();
105: } catch (IOException ioe) {
106: throw new StreamCorruptedException(ioe.getMessage());
107: }
108: }
109: return true;
110: }
111: }
112:
113: /** The list of magic numbers associated with this entry */
114: MagicNumber[] magicNumbers;
115:
116: /**
117: * Constructor, simplifies construction of entry when only
118: * one extension and one magic number is required.
119: * @param name Format Name
120: * @param priority the priority of the RegistryEntry
121: * @param ext Standard extension
122: * @param mimeType the supported MIME type
123: * @param offset Offset of magic number
124: * @param magicNumber byte array to match.
125: */
126: public MagicNumberRegistryEntry(String name, float priority,
127: String ext, String mimeType, int offset, byte[] magicNumber) {
128: super (name, priority, ext, mimeType);
129: magicNumbers = new MagicNumber[1];
130: magicNumbers[0] = new MagicNumber(offset, magicNumber);
131: }
132:
133: /**
134: * Constructor, simplifies construction of entry when only
135: * one extension and one magic number is required.
136: * @param name Format Name
137: * @param ext Standard extension
138: * @param mimeType the supported MIME type
139: * @param offset Offset of magic number
140: * @param magicNumber byte array to match.
141: */
142: public MagicNumberRegistryEntry(String name, String ext,
143: String mimeType, int offset, byte[] magicNumber) {
144: this (name, PRIORITY, ext, mimeType, offset, magicNumber);
145: }
146:
147: /**
148: * Constructor, simplifies construction of entry when only
149: * one extension is required.
150: * @param name Format Name
151: * @param priority the priority of the RegistryEntry
152: * @param ext Standard extension
153: * @param mimeType the supported MIME type
154: * @param magicNumbers Array of magic numbers any of which can match.
155: */
156: public MagicNumberRegistryEntry(String name, float priority,
157: String ext, String mimeType, MagicNumber[] magicNumbers) {
158: super (name, priority, ext, mimeType);
159: this .magicNumbers = magicNumbers;
160: }
161:
162: /**
163: * Constructor, simplifies construction of entry when only
164: * one extension is required.
165: * @param name Format Name
166: * @param ext Standard extension
167: * @param mimeType the supported MIME type
168: * @param magicNumbers Array of magic numbers any of which can match.
169: */
170: public MagicNumberRegistryEntry(String name, String ext,
171: String mimeType, MagicNumber[] magicNumbers) {
172: this (name, PRIORITY, ext, mimeType, magicNumbers);
173: }
174:
175: /**
176: * Constructor, simplifies construction of entry when only
177: * one magic number is required.
178: * @param name Format Name
179: * @param priority the priority of the RegistryEntry
180: * @param exts Standard set of extensions
181: * @param mimeTypes array of supported MIME types
182: * @param offset Offset of magic number
183: * @param magicNumber byte array to match.
184: */
185: public MagicNumberRegistryEntry(String name, float priority,
186: String[] exts, String[] mimeTypes, int offset,
187: byte[] magicNumber) {
188: super (name, priority, exts, mimeTypes);
189: magicNumbers = new MagicNumber[1];
190: magicNumbers[0] = new MagicNumber(offset, magicNumber);
191: }
192:
193: /**
194: * Constructor, simplifies construction of entry when only
195: * one magic number is required.
196: * @param name Format Name
197: * @param exts Standard set of extensions
198: * @param mimeTypes array of supported MIME types
199: * @param offset Offset of magic number
200: * @param magicNumbers byte array to match.
201: */
202: public MagicNumberRegistryEntry(String name, String[] exts,
203: String[] mimeTypes, int offset, byte[] magicNumbers) {
204: this (name, PRIORITY, exts, mimeTypes, offset, magicNumbers);
205: }
206:
207: /**
208: * Constructor
209: * @param name Format Name
210: * @param priority the priority of the RegistryEntry
211: * @param exts Standard set of extensions
212: * @param mimeTypes array of supported MIME types
213: * @param magicNumbers array of magic numbers any of which can match.
214: */
215: public MagicNumberRegistryEntry(String name, float priority,
216: String[] exts, String[] mimeTypes,
217: MagicNumber[] magicNumbers) {
218: super (name, priority, exts, mimeTypes);
219: this .magicNumbers = magicNumbers;
220: }
221:
222: /**
223: * Constructor
224: * @param name Format Name
225: * @param exts Standard set of extensions
226: * @param mimeTypes array of supported MIME types
227: * @param magicNumbers array of magic numbers any of which can match.
228: */
229: public MagicNumberRegistryEntry(String name, String[] exts,
230: String[] mimeTypes, MagicNumber[] magicNumbers) {
231: this (name, PRIORITY, exts, mimeTypes, magicNumbers);
232: }
233:
234: /**
235: * Constructor, allows for overriding the default priority of
236: * magic number entries. This should be needed very rarely since
237: * magic number checks are fairly relyable and hence aren't usually
238: * sensative to order issues.
239: * @param name Format Name
240: * @param exts Standard set of extensions
241: * @param magicNumbers array of magic numbers any of which can match.
242: * @param priority The priority of this entry (1000 is baseline)
243: */
244: public MagicNumberRegistryEntry(String name, String[] exts,
245: String[] mimeTypes, MagicNumber[] magicNumbers,
246: float priority) {
247: super (name, priority, exts, mimeTypes);
248: this .magicNumbers = magicNumbers;
249: }
250:
251: /**
252: * Returns the maximume read ahead needed for all magic numbers.
253: */
254: public int getReadlimit() {
255: int maxbuf = 0;
256: for (int i = 0; i < magicNumbers.length; i++) {
257: int req = magicNumbers[i].getReadlimit();
258: if (req > maxbuf)
259: maxbuf = req;
260: }
261: return maxbuf;
262: }
263:
264: /**
265: * Check if the stream contains an image that can be
266: * handled by this format handler
267: */
268: public boolean isCompatibleStream(InputStream is)
269: throws StreamCorruptedException {
270: for (int i = 0; i < magicNumbers.length; i++) {
271: if (magicNumbers[i].isMatch(is))
272: return true;
273: }
274:
275: return false;
276: }
277: }
|