001: /*
002: * Copyright 2001 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package com.sun.imageio.plugins.jpeg;
027:
028: import javax.imageio.metadata.IIOInvalidTreeException;
029: import javax.imageio.metadata.IIOMetadataNode;
030: import javax.imageio.stream.ImageOutputStream;
031:
032: import java.io.IOException;
033:
034: import org.w3c.dom.Node;
035: import org.w3c.dom.NamedNodeMap;
036:
037: /**
038: * All metadata is stored in MarkerSegments. Marker segments
039: * that we know about are stored in subclasses of this
040: * basic class, which used for unrecognized APPn marker
041: * segments. XXX break out UnknownMarkerSegment as a subclass
042: * and make this abstract, avoiding unused data field.
043: */
044: class MarkerSegment implements Cloneable {
045: protected static final int LENGTH_SIZE = 2; // length is 2 bytes
046: int tag; // See JPEG.java
047: int length; /* Sometimes needed by subclasses; doesn't include
048: itself. Meaningful only if constructed from a stream */
049: byte[] data = null; // Raw segment data, used for unrecognized segments
050: boolean unknown = false; // Set to true if the tag is not recognized
051:
052: /**
053: * Constructor for creating <code>MarkerSegment</code>s by reading
054: * from an <code>ImageInputStream</code>.
055: */
056: MarkerSegment(JPEGBuffer buffer) throws IOException {
057:
058: buffer.loadBuf(3); // tag plus length
059: tag = buffer.buf[buffer.bufPtr++] & 0xff;
060: length = (buffer.buf[buffer.bufPtr++] & 0xff) << 8;
061: length |= buffer.buf[buffer.bufPtr++] & 0xff;
062: length -= 2; // JPEG length includes itself, we don't
063: buffer.bufAvail -= 3;
064: // Now that we know the true length, ensure that we've got it,
065: // or at least a bufferful if length is too big.
066: buffer.loadBuf(length);
067: }
068:
069: /**
070: * Constructor used when creating segments other than by
071: * reading them from a stream.
072: */
073: MarkerSegment(int tag) {
074: this .tag = tag;
075: length = 0;
076: }
077:
078: /**
079: * Construct a MarkerSegment from an "unknown" DOM Node.
080: */
081: MarkerSegment(Node node) throws IIOInvalidTreeException {
082: // The type of node should have been verified already.
083: // get the attribute and assign it to the tag
084: tag = getAttributeValue(node, null, "MarkerTag", 0, 255, true);
085: length = 0;
086: // get the user object and clone it to the data
087: if (node instanceof IIOMetadataNode) {
088: IIOMetadataNode iioNode = (IIOMetadataNode) node;
089: try {
090: data = (byte[]) iioNode.getUserObject();
091: } catch (Exception e) {
092: IIOInvalidTreeException newGuy = new IIOInvalidTreeException(
093: "Can't get User Object", node);
094: newGuy.initCause(e);
095: throw newGuy;
096: }
097: } else {
098: throw new IIOInvalidTreeException(
099: "Node must have User Object", node);
100: }
101: }
102:
103: /**
104: * Deep copy of data array.
105: */
106: protected Object clone() {
107: MarkerSegment newGuy = null;
108: try {
109: newGuy = (MarkerSegment) super .clone();
110: } catch (CloneNotSupportedException e) {
111: } // won't happen
112: if (this .data != null) {
113: newGuy.data = (byte[]) data.clone();
114: }
115: return newGuy;
116: }
117:
118: /**
119: * We have determined that we don't know the type, so load
120: * the data using the length parameter.
121: */
122: void loadData(JPEGBuffer buffer) throws IOException {
123: data = new byte[length];
124: buffer.readData(data);
125: }
126:
127: IIOMetadataNode getNativeNode() {
128: IIOMetadataNode node = new IIOMetadataNode("unknown");
129: node.setAttribute("MarkerTag", Integer.toString(tag));
130: node.setUserObject(data);
131:
132: return node;
133: }
134:
135: static int getAttributeValue(Node node, NamedNodeMap attrs,
136: String name, int min, int max, boolean required)
137: throws IIOInvalidTreeException {
138: if (attrs == null) {
139: attrs = node.getAttributes();
140: }
141: String valueString = attrs.getNamedItem(name).getNodeValue();
142: int value = -1;
143: if (valueString == null) {
144: if (required) {
145: throw new IIOInvalidTreeException(name
146: + " attribute not found", node);
147: }
148: } else {
149: value = Integer.parseInt(valueString);
150: if ((value < min) || (value > max)) {
151: throw new IIOInvalidTreeException(name
152: + " attribute out of range", node);
153: }
154: }
155: return value;
156: }
157:
158: /**
159: * Writes the marker, tag, and length. Note that length
160: * should be verified by the caller as a correct JPEG
161: * length, i.e it includes itself.
162: */
163: void writeTag(ImageOutputStream ios) throws IOException {
164: ios.write(0xff);
165: ios.write(tag);
166: write2bytes(ios, length);
167: }
168:
169: /**
170: * Writes the data for this segment to the stream in
171: * valid JPEG format.
172: */
173: void write(ImageOutputStream ios) throws IOException {
174: length = 2 + ((data != null) ? data.length : 0);
175: writeTag(ios);
176: if (data != null) {
177: ios.write(data);
178: }
179: }
180:
181: static void write2bytes(ImageOutputStream ios, int value)
182: throws IOException {
183: ios.write((value >> 8) & 0xff);
184: ios.write(value & 0xff);
185:
186: }
187:
188: void printTag(String prefix) {
189: System.out.println(prefix + " marker segment - marker = 0x"
190: + Integer.toHexString(tag));
191: System.out.println("length: " + length);
192: }
193:
194: void print() {
195: printTag("Unknown");
196: if (length > 10) {
197: System.out.print("First 5 bytes:");
198: for (int i = 0; i < 5; i++) {
199: System.out.print(" Ox"
200: + Integer.toHexString((int) data[i]));
201: }
202: System.out.print("\nLast 5 bytes:");
203: for (int i = data.length - 5; i < data.length; i++) {
204: System.out.print(" Ox"
205: + Integer.toHexString((int) data[i]));
206: }
207: } else {
208: System.out.print("Data:");
209: for (int i = 0; i < data.length; i++) {
210: System.out.print(" Ox"
211: + Integer.toHexString((int) data[i]));
212: }
213: }
214: System.out.println();
215: }
216: }
|