| /* |
| * Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| package com.sun.imageio.plugins.jpeg; |
| |
| import javax.imageio.metadata.IIOInvalidTreeException; |
| import javax.imageio.metadata.IIOMetadataNode; |
| import javax.imageio.stream.ImageOutputStream; |
| |
| import java.io.IOException; |
| |
| import org.w3c.dom.Node; |
| import org.w3c.dom.NamedNodeMap; |
| |
| /** |
| * All metadata is stored in MarkerSegments. Marker segments |
| * that we know about are stored in subclasses of this |
| * basic class, which used for unrecognized APPn marker |
| * segments. XXX break out UnknownMarkerSegment as a subclass |
| * and make this abstract, avoiding unused data field. |
| */ |
| class MarkerSegment implements Cloneable { |
| protected static final int LENGTH_SIZE = 2; // length is 2 bytes |
| int tag; // See JPEG.java |
| int length; /* Sometimes needed by subclasses; doesn't include |
| itself. Meaningful only if constructed from a stream */ |
| byte [] data = null; // Raw segment data, used for unrecognized segments |
| boolean unknown = false; // Set to true if the tag is not recognized |
| |
| /** |
| * Constructor for creating <code>MarkerSegment</code>s by reading |
| * from an <code>ImageInputStream</code>. |
| */ |
| MarkerSegment(JPEGBuffer buffer) throws IOException { |
| |
| buffer.loadBuf(3); // tag plus length |
| tag = buffer.buf[buffer.bufPtr++] & 0xff; |
| length = (buffer.buf[buffer.bufPtr++] & 0xff) << 8; |
| length |= buffer.buf[buffer.bufPtr++] & 0xff; |
| length -= 2; // JPEG length includes itself, we don't |
| buffer.bufAvail -= 3; |
| // Now that we know the true length, ensure that we've got it, |
| // or at least a bufferful if length is too big. |
| buffer.loadBuf(length); |
| } |
| |
| /** |
| * Constructor used when creating segments other than by |
| * reading them from a stream. |
| */ |
| MarkerSegment(int tag) { |
| this.tag = tag; |
| length = 0; |
| } |
| |
| /** |
| * Construct a MarkerSegment from an "unknown" DOM Node. |
| */ |
| MarkerSegment(Node node) throws IIOInvalidTreeException { |
| // The type of node should have been verified already. |
| // get the attribute and assign it to the tag |
| tag = getAttributeValue(node, |
| null, |
| "MarkerTag", |
| 0, 255, |
| true); |
| length = 0; |
| // get the user object and clone it to the data |
| if (node instanceof IIOMetadataNode) { |
| IIOMetadataNode iioNode = (IIOMetadataNode) node; |
| try { |
| data = (byte []) iioNode.getUserObject(); |
| } catch (Exception e) { |
| IIOInvalidTreeException newGuy = |
| new IIOInvalidTreeException |
| ("Can't get User Object", node); |
| newGuy.initCause(e); |
| throw newGuy; |
| } |
| } else { |
| throw new IIOInvalidTreeException |
| ("Node must have User Object", node); |
| } |
| } |
| |
| /** |
| * Deep copy of data array. |
| */ |
| protected Object clone() { |
| MarkerSegment newGuy = null; |
| try { |
| newGuy = (MarkerSegment) super.clone(); |
| } catch (CloneNotSupportedException e) {} // won't happen |
| if (this.data != null) { |
| newGuy.data = (byte[]) data.clone(); |
| } |
| return newGuy; |
| } |
| |
| /** |
| * We have determined that we don't know the type, so load |
| * the data using the length parameter. |
| */ |
| void loadData(JPEGBuffer buffer) throws IOException { |
| data = new byte[length]; |
| buffer.readData(data); |
| } |
| |
| IIOMetadataNode getNativeNode() { |
| IIOMetadataNode node = new IIOMetadataNode("unknown"); |
| node.setAttribute("MarkerTag", Integer.toString(tag)); |
| node.setUserObject(data); |
| |
| return node; |
| } |
| |
| static int getAttributeValue(Node node, |
| NamedNodeMap attrs, |
| String name, |
| int min, |
| int max, |
| boolean required) |
| throws IIOInvalidTreeException { |
| if (attrs == null) { |
| attrs = node.getAttributes(); |
| } |
| String valueString = attrs.getNamedItem(name).getNodeValue(); |
| int value = -1; |
| if (valueString == null) { |
| if (required) { |
| throw new IIOInvalidTreeException |
| (name + " attribute not found", node); |
| } |
| } else { |
| value = Integer.parseInt(valueString); |
| if ((value < min) || (value > max)) { |
| throw new IIOInvalidTreeException |
| (name + " attribute out of range", node); |
| } |
| } |
| return value; |
| } |
| |
| /** |
| * Writes the marker, tag, and length. Note that length |
| * should be verified by the caller as a correct JPEG |
| * length, i.e it includes itself. |
| */ |
| void writeTag(ImageOutputStream ios) throws IOException { |
| ios.write(0xff); |
| ios.write(tag); |
| write2bytes(ios, length); |
| } |
| |
| /** |
| * Writes the data for this segment to the stream in |
| * valid JPEG format. |
| */ |
| void write(ImageOutputStream ios) throws IOException { |
| length = 2 + ((data != null) ? data.length : 0); |
| writeTag(ios); |
| if (data != null) { |
| ios.write(data); |
| } |
| } |
| |
| static void write2bytes(ImageOutputStream ios, |
| int value) throws IOException { |
| ios.write((value >> 8) & 0xff); |
| ios.write(value & 0xff); |
| |
| } |
| |
| void printTag(String prefix) { |
| System.out.println(prefix + " marker segment - marker = 0x" |
| + Integer.toHexString(tag)); |
| System.out.println("length: " + length); |
| } |
| |
| void print() { |
| printTag("Unknown"); |
| if (length > 10) { |
| System.out.print("First 5 bytes:"); |
| for (int i=0;i<5;i++) { |
| System.out.print(" Ox" |
| + Integer.toHexString((int)data[i])); |
| } |
| System.out.print("\nLast 5 bytes:"); |
| for (int i=data.length-5;i<data.length;i++) { |
| System.out.print(" Ox" |
| + Integer.toHexString((int)data[i])); |
| } |
| } else { |
| System.out.print("Data:"); |
| for (int i=0;i<data.length;i++) { |
| System.out.print(" Ox" |
| + Integer.toHexString((int)data[i])); |
| } |
| } |
| System.out.println(); |
| } |
| } |