1 /* 2 * Copyright (c) 2005, 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.gif; 27 28 import javax.imageio.metadata.IIOInvalidTreeException; 29 import javax.imageio.metadata.IIOMetadata; 30 import javax.imageio.metadata.IIOMetadataFormatImpl; 31 import org.w3c.dom.Node; 32 33 /** 34 * Class which adds utility DOM element attribute access methods to 35 * {@code IIOMetadata} for subclass use. 36 */ 37 abstract class GIFMetadata extends IIOMetadata { 38 39 /** 40 * Represents an undefined value of integer attributes. 41 */ 42 static final int UNDEFINED_INTEGER_VALUE = -1; 43 44 // 45 // Note: These attribute methods were shamelessly lifted from 46 // com.sun.imageio.plugins.png.PNGMetadata and modified. 47 // 48 49 // Shorthand for throwing an IIOInvalidTreeException fatal(Node node, String reason)50 protected static void fatal(Node node, String reason) 51 throws IIOInvalidTreeException { 52 throw new IIOInvalidTreeException(reason, node); 53 } 54 55 // Get an integer-valued attribute getStringAttribute(Node node, String name, String defaultValue, boolean required, String[] range)56 protected static String getStringAttribute(Node node, String name, 57 String defaultValue, 58 boolean required, 59 String[] range) 60 throws IIOInvalidTreeException { 61 Node attr = node.getAttributes().getNamedItem(name); 62 if (attr == null) { 63 if (!required) { 64 return defaultValue; 65 } else { 66 fatal(node, "Required attribute " + name + " not present!"); 67 } 68 } 69 String value = attr.getNodeValue(); 70 71 if (range != null) { 72 if (value == null) { 73 fatal(node, 74 "Null value for "+node.getNodeName()+ 75 " attribute "+name+"!"); 76 } 77 boolean validValue = false; 78 int len = range.length; 79 for (int i = 0; i < len; i++) { 80 if (value.equals(range[i])) { 81 validValue = true; 82 break; 83 } 84 } 85 if (!validValue) { 86 fatal(node, 87 "Bad value for "+node.getNodeName()+ 88 " attribute "+name+"!"); 89 } 90 } 91 92 return value; 93 } 94 95 96 // Get an integer-valued attribute getIntAttribute(Node node, String name, int defaultValue, boolean required, boolean bounded, int min, int max)97 protected static int getIntAttribute(Node node, String name, 98 int defaultValue, boolean required, 99 boolean bounded, int min, int max) 100 throws IIOInvalidTreeException { 101 String value = getStringAttribute(node, name, null, required, null); 102 if (value == null || "".equals(value)) { 103 return defaultValue; 104 } 105 106 int intValue = defaultValue; 107 try { 108 intValue = Integer.parseInt(value); 109 } catch (NumberFormatException e) { 110 fatal(node, 111 "Bad value for "+node.getNodeName()+ 112 " attribute "+name+"!"); 113 } 114 if (bounded && (intValue < min || intValue > max)) { 115 fatal(node, 116 "Bad value for "+node.getNodeName()+ 117 " attribute "+name+"!"); 118 } 119 return intValue; 120 } 121 122 // Get a float-valued attribute getFloatAttribute(Node node, String name, float defaultValue, boolean required)123 protected static float getFloatAttribute(Node node, String name, 124 float defaultValue, 125 boolean required) 126 throws IIOInvalidTreeException { 127 String value = getStringAttribute(node, name, null, required, null); 128 if (value == null) { 129 return defaultValue; 130 } 131 return Float.parseFloat(value); 132 } 133 134 // Get a required integer-valued attribute getIntAttribute(Node node, String name, boolean bounded, int min, int max)135 protected static int getIntAttribute(Node node, String name, 136 boolean bounded, int min, int max) 137 throws IIOInvalidTreeException { 138 return getIntAttribute(node, name, -1, true, bounded, min, max); 139 } 140 141 // Get a required float-valued attribute getFloatAttribute(Node node, String name)142 protected static float getFloatAttribute(Node node, String name) 143 throws IIOInvalidTreeException { 144 return getFloatAttribute(node, name, -1.0F, true); 145 } 146 147 // Get a boolean-valued attribute getBooleanAttribute(Node node, String name, boolean defaultValue, boolean required)148 protected static boolean getBooleanAttribute(Node node, String name, 149 boolean defaultValue, 150 boolean required) 151 throws IIOInvalidTreeException { 152 Node attr = node.getAttributes().getNamedItem(name); 153 if (attr == null) { 154 if (!required) { 155 return defaultValue; 156 } else { 157 fatal(node, "Required attribute " + name + " not present!"); 158 } 159 } 160 String value = attr.getNodeValue(); 161 // Allow lower case booleans for backward compatibility, #5082756 162 if (value.equals("TRUE") || value.equals("true")) { 163 return true; 164 } else if (value.equals("FALSE") || value.equals("false")) { 165 return false; 166 } else { 167 fatal(node, "Attribute " + name + " must be 'TRUE' or 'FALSE'!"); 168 return false; 169 } 170 } 171 172 // Get a required boolean-valued attribute getBooleanAttribute(Node node, String name)173 protected static boolean getBooleanAttribute(Node node, String name) 174 throws IIOInvalidTreeException { 175 return getBooleanAttribute(node, name, false, true); 176 } 177 178 // Get an enumerated attribute as an index into a String array getEnumeratedAttribute(Node node, String name, String[] legalNames, int defaultValue, boolean required)179 protected static int getEnumeratedAttribute(Node node, 180 String name, 181 String[] legalNames, 182 int defaultValue, 183 boolean required) 184 throws IIOInvalidTreeException { 185 Node attr = node.getAttributes().getNamedItem(name); 186 if (attr == null) { 187 if (!required) { 188 return defaultValue; 189 } else { 190 fatal(node, "Required attribute " + name + " not present!"); 191 } 192 } 193 String value = attr.getNodeValue(); 194 for (int i = 0; i < legalNames.length; i++) { 195 if(value.equals(legalNames[i])) { 196 return i; 197 } 198 } 199 200 fatal(node, "Illegal value for attribute " + name + "!"); 201 return -1; 202 } 203 204 // Get a required enumerated attribute as an index into a String array getEnumeratedAttribute(Node node, String name, String[] legalNames)205 protected static int getEnumeratedAttribute(Node node, 206 String name, 207 String[] legalNames) 208 throws IIOInvalidTreeException { 209 return getEnumeratedAttribute(node, name, legalNames, -1, true); 210 } 211 212 // Get a String-valued attribute getAttribute(Node node, String name, String defaultValue, boolean required)213 protected static String getAttribute(Node node, String name, 214 String defaultValue, boolean required) 215 throws IIOInvalidTreeException { 216 Node attr = node.getAttributes().getNamedItem(name); 217 if (attr == null) { 218 if (!required) { 219 return defaultValue; 220 } else { 221 fatal(node, "Required attribute " + name + " not present!"); 222 } 223 } 224 return attr.getNodeValue(); 225 } 226 227 // Get a required String-valued attribute getAttribute(Node node, String name)228 protected static String getAttribute(Node node, String name) 229 throws IIOInvalidTreeException { 230 return getAttribute(node, name, null, true); 231 } 232 GIFMetadata(boolean standardMetadataFormatSupported, String nativeMetadataFormatName, String nativeMetadataFormatClassName, String[] extraMetadataFormatNames, String[] extraMetadataFormatClassNames)233 protected GIFMetadata(boolean standardMetadataFormatSupported, 234 String nativeMetadataFormatName, 235 String nativeMetadataFormatClassName, 236 String[] extraMetadataFormatNames, 237 String[] extraMetadataFormatClassNames) { 238 super(standardMetadataFormatSupported, 239 nativeMetadataFormatName, 240 nativeMetadataFormatClassName, 241 extraMetadataFormatNames, 242 extraMetadataFormatClassNames); 243 } 244 mergeTree(String formatName, Node root)245 public void mergeTree(String formatName, Node root) 246 throws IIOInvalidTreeException { 247 if (formatName.equals(nativeMetadataFormatName)) { 248 if (root == null) { 249 throw new IllegalArgumentException("root == null!"); 250 } 251 mergeNativeTree(root); 252 } else if (formatName.equals 253 (IIOMetadataFormatImpl.standardMetadataFormatName)) { 254 if (root == null) { 255 throw new IllegalArgumentException("root == null!"); 256 } 257 mergeStandardTree(root); 258 } else { 259 throw new IllegalArgumentException("Not a recognized format!"); 260 } 261 } 262 getColorTable(Node colorTableNode, String entryNodeName, boolean lengthExpected, int expectedLength)263 protected byte[] getColorTable(Node colorTableNode, 264 String entryNodeName, 265 boolean lengthExpected, 266 int expectedLength) 267 throws IIOInvalidTreeException { 268 byte[] red = new byte[256]; 269 byte[] green = new byte[256]; 270 byte[] blue = new byte[256]; 271 int maxIndex = -1; 272 273 Node entry = colorTableNode.getFirstChild(); 274 if (entry == null) { 275 fatal(colorTableNode, "Palette has no entries!"); 276 } 277 278 while (entry != null) { 279 if (!entry.getNodeName().equals(entryNodeName)) { 280 fatal(colorTableNode, 281 "Only a "+entryNodeName+" may be a child of a "+ 282 entry.getNodeName()+"!"); 283 } 284 285 int index = getIntAttribute(entry, "index", true, 0, 255); 286 if (index > maxIndex) { 287 maxIndex = index; 288 } 289 red[index] = (byte)getIntAttribute(entry, "red", true, 0, 255); 290 green[index] = (byte)getIntAttribute(entry, "green", true, 0, 255); 291 blue[index] = (byte)getIntAttribute(entry, "blue", true, 0, 255); 292 293 entry = entry.getNextSibling(); 294 } 295 296 int numEntries = maxIndex + 1; 297 298 if (lengthExpected && numEntries != expectedLength) { 299 fatal(colorTableNode, "Unexpected length for palette!"); 300 } 301 302 byte[] colorTable = new byte[3*numEntries]; 303 for (int i = 0, j = 0; i < numEntries; i++) { 304 colorTable[j++] = red[i]; 305 colorTable[j++] = green[i]; 306 colorTable[j++] = blue[i]; 307 } 308 309 return colorTable; 310 } 311 mergeNativeTree(Node root)312 protected abstract void mergeNativeTree(Node root) 313 throws IIOInvalidTreeException; 314 mergeStandardTree(Node root)315 protected abstract void mergeStandardTree(Node root) 316 throws IIOInvalidTreeException; 317 } 318