1 /* 2 * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.imageio.plugins.jpeg; 27 28 import javax.imageio.metadata.IIOInvalidTreeException; 29 import javax.imageio.metadata.IIOMetadataNode; 30 import javax.imageio.stream.ImageOutputStream; 31 import javax.imageio.IIOException; 32 33 import java.io.IOException; 34 35 import org.w3c.dom.Node; 36 import org.w3c.dom.NamedNodeMap; 37 38 /** 39 * All metadata is stored in MarkerSegments. Marker segments 40 * that we know about are stored in subclasses of this 41 * basic class, which used for unrecognized APPn marker 42 * segments. XXX break out UnknownMarkerSegment as a subclass 43 * and make this abstract, avoiding unused data field. 44 */ 45 class MarkerSegment implements Cloneable { 46 protected static final int LENGTH_SIZE = 2; // length is 2 bytes 47 int tag; // See JPEG.java 48 int length; /* Sometimes needed by subclasses; doesn't include 49 itself. Meaningful only if constructed from a stream */ 50 byte [] data = null; // Raw segment data, used for unrecognized segments 51 boolean unknown = false; // Set to true if the tag is not recognized 52 53 /** 54 * Constructor for creating <code>MarkerSegment</code>s by reading 55 * from an <code>ImageInputStream</code>. 56 */ 57 MarkerSegment(JPEGBuffer buffer) throws IOException { 58 59 buffer.loadBuf(3); // tag plus length 60 tag = buffer.buf[buffer.bufPtr++] & 0xff; 61 length = (buffer.buf[buffer.bufPtr++] & 0xff) << 8; 62 length |= buffer.buf[buffer.bufPtr++] & 0xff; 63 length -= 2; // JPEG length includes itself, we don't 64 65 if (length < 0) { 66 throw new IIOException("Invalid segment length: " + length); 67 } 68 buffer.bufAvail -= 3; 69 // Now that we know the true length, ensure that we've got it, 70 // or at least a bufferful if length is too big. 71 buffer.loadBuf(length); 72 } 73 74 /** 75 * Constructor used when creating segments other than by 76 * reading them from a stream. 77 */ 78 MarkerSegment(int tag) { 79 this.tag = tag; 80 length = 0; 81 } 82 83 /** 84 * Construct a MarkerSegment from an "unknown" DOM Node. 85 */ 86 MarkerSegment(Node node) throws IIOInvalidTreeException { 87 // The type of node should have been verified already. 88 // get the attribute and assign it to the tag 89 tag = getAttributeValue(node, 90 null, 91 "MarkerTag", 92 0, 255, 93 true); 94 length = 0; 95 // get the user object and clone it to the data 96 if (node instanceof IIOMetadataNode) { 97 IIOMetadataNode iioNode = (IIOMetadataNode) node; 98 try { 99 data = (byte []) iioNode.getUserObject(); 100 } catch (Exception e) { 101 IIOInvalidTreeException newGuy = 102 new IIOInvalidTreeException 103 ("Can't get User Object", node); 104 newGuy.initCause(e); 105 throw newGuy; 106 } 107 } else { 108 throw new IIOInvalidTreeException 109 ("Node must have User Object", node); 110 } 111 } 112 113 /** 114 * Deep copy of data array. 115 */ 116 protected Object clone() { 117 MarkerSegment newGuy = null; 118 try { 119 newGuy = (MarkerSegment) super.clone(); 120 } catch (CloneNotSupportedException e) {} // won't happen 121 if (this.data != null) { 122 newGuy.data = data.clone(); 123 } 124 return newGuy; 125 } 126 127 /** 128 * We have determined that we don't know the type, so load 129 * the data using the length parameter. 130 */ 131 void loadData(JPEGBuffer buffer) throws IOException { 132 data = new byte[length]; 133 buffer.readData(data); 134 } 135 136 IIOMetadataNode getNativeNode() { 137 IIOMetadataNode node = new IIOMetadataNode("unknown"); 138 node.setAttribute("MarkerTag", Integer.toString(tag)); 139 node.setUserObject(data); 140 141 return node; 142 } 143 144 static int getAttributeValue(Node node, 145 NamedNodeMap attrs, 146 String name, 147 int min, 148 int max, 149 boolean required) 150 throws IIOInvalidTreeException { 151 if (attrs == null) { 152 attrs = node.getAttributes(); 153 } 154 String valueString = attrs.getNamedItem(name).getNodeValue(); 155 int value = -1; 156 if (valueString == null) { 157 if (required) { 158 throw new IIOInvalidTreeException 159 (name + " attribute not found", node); 160 } 161 } else { 162 value = Integer.parseInt(valueString); 163 if ((value < min) || (value > max)) { 164 throw new IIOInvalidTreeException 165 (name + " attribute out of range", node); 166 } 167 } 168 return value; 169 } 170 171 /** 172 * Writes the marker, tag, and length. Note that length 173 * should be verified by the caller as a correct JPEG 174 * length, i.e it includes itself. 175 */ 176 void writeTag(ImageOutputStream ios) throws IOException { 177 ios.write(0xff); 178 ios.write(tag); 179 write2bytes(ios, length); 180 } 181 182 /** 183 * Writes the data for this segment to the stream in 184 * valid JPEG format. 185 */ 186 void write(ImageOutputStream ios) throws IOException { 187 length = 2 + ((data != null) ? data.length : 0); 188 writeTag(ios); 189 if (data != null) { 190 ios.write(data); 191 } 192 } 193 194 static void write2bytes(ImageOutputStream ios, 195 int value) throws IOException { 196 ios.write((value >> 8) & 0xff); 197 ios.write(value & 0xff); 198 199 } 200 201 void printTag(String prefix) { 202 System.out.println(prefix + " marker segment - marker = 0x" 203 + Integer.toHexString(tag)); 204 System.out.println("length: " + length); 205 } 206 207 void print() { 208 printTag("Unknown"); 209 if (length > 10) { 210 System.out.print("First 5 bytes:"); 211 for (int i=0;i<5;i++) { 212 System.out.print(" Ox" 213 + Integer.toHexString((int)data[i])); 214 } 215 System.out.print("\nLast 5 bytes:"); 216 for (int i=data.length-5;i<data.length;i++) { 217 System.out.print(" Ox" 218 + Integer.toHexString((int)data[i])); 219 } 220 } else { 221 System.out.print("Data:"); 222 for (int i=0;i<data.length;i++) { 223 System.out.print(" Ox" 224 + Integer.toHexString((int)data[i])); 225 } 226 } 227 System.out.println(); 228 } 229 }