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}s by reading 55 * from an {@code ImageInputStream}. 56 */ MarkerSegment(JPEGBuffer buffer)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 */ MarkerSegment(int tag)78 MarkerSegment(int tag) { 79 this.tag = tag; 80 length = 0; 81 } 82 83 /** 84 * Construct a MarkerSegment from an "unknown" DOM Node. 85 */ MarkerSegment(Node node)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 */ clone()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 */ loadData(JPEGBuffer buffer)131 void loadData(JPEGBuffer buffer) throws IOException { 132 data = new byte[length]; 133 buffer.readData(data); 134 } 135 getNativeNode()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 getAttributeValue(Node node, NamedNodeMap attrs, String name, int min, int max, boolean required)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 */ writeTag(ImageOutputStream ios)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 */ write(ImageOutputStream ios)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 write2bytes(ImageOutputStream ios, int value)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 printTag(String prefix)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 print()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 } 230