/* * Copyright (c) 2012, 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. * * 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. */ // import java.io.PrintStream; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.StringTokenizer; import javax.imageio.metadata.IIOMetadata; import javax.imageio.metadata.IIOMetadataFormat; import javax.imageio.metadata.IIOMetadataFormatImpl; import javax.imageio.spi.IIORegistry; import javax.imageio.spi.ImageReaderSpi; import com.sun.imageio.plugins.png.PNGMetadata; public class MetadataFormatPrinter { private int indentLevel = 0; private int column = 0; private PrintStream out; private static final int maxColumn = 75; private static String[] dataTypeNames = { "String", "Boolean", "Integer", "Float", "Double" }; // "Infinite" values private static String maxInteger = Integer.toString(Integer.MAX_VALUE); public MetadataFormatPrinter(PrintStream out) { this.out = out; } private void println() { out.println(); column = 0; } private void println(String s) { out.println(s); column = 0; } private void printWrapped(String in, int leftIndent) { StringTokenizer t = new StringTokenizer(in); while (t.hasMoreTokens()) { String s = t.nextToken(); int length = s.length(); if (column + length > maxColumn) { println(); indent(); for (int i = 0; i < leftIndent; i++) { print(" "); } } out.print(s); out.print(" "); column += length + 1; } } private void print(String s) { int length = s.length(); if (column + length > maxColumn) { println(); indent(); print(" "); } out.print(s); column += length; } private void print(IIOMetadataFormat format) { String rootName = format.getRootName(); println("<!DOCTYPE \"" + rootName + "\" ["); ++indentLevel; print(format, rootName); --indentLevel; print("]>"); println(); println(); } private void indent() { for (int i = 0; i < indentLevel; i++) { out.print(" "); column += 2; } } private void printElementInfo(IIOMetadataFormat format, String elementName) { println(); indent(); print("<!ELEMENT \"" + elementName + "\""); String[] childNames = format.getChildNames(elementName); boolean hasChildren = true; String separator = " "; // symbol to place between children String terminator = ""; // symbol to follow last child String repeater = ""; // "*" if repeating switch (format.getChildPolicy(elementName)) { case IIOMetadataFormat.CHILD_POLICY_EMPTY: hasChildren = false; break; case IIOMetadataFormat.CHILD_POLICY_ALL: separator = ", "; break; case IIOMetadataFormat.CHILD_POLICY_SOME: separator = "?, "; terminator = "?"; break; case IIOMetadataFormat.CHILD_POLICY_CHOICE: separator = " | "; break; case IIOMetadataFormat.CHILD_POLICY_SEQUENCE: separator = " | "; repeater = "*"; break; case IIOMetadataFormat.CHILD_POLICY_REPEAT: repeater = "*"; break; default: break; } if (hasChildren) { print(" ("); for (int i = 0; i < childNames.length - 1; i++) { print(childNames[i] + separator); } print(childNames[childNames.length - 1] + terminator); print(")" + repeater + ">"); } else { print(" EMPTY>"); } println(); String description = format.getElementDescription(elementName, null); if (description != null) { ++indentLevel; indent(); printWrapped("<!-- " + description + " -->", 5); println(); --indentLevel; } if (format.getChildPolicy(elementName) == IIOMetadataFormat.CHILD_POLICY_REPEAT) { int minChildren = format.getElementMinChildren(elementName); if (minChildren != 0) { indent(); println(" <!-- Min children: " + minChildren + " -->"); } int maxChildren = format.getElementMaxChildren(elementName); if (maxChildren != Integer.MAX_VALUE) { indent(); println(" <!-- Max children: " + maxChildren + " -->"); } } } private void printAttributeInfo(IIOMetadataFormat format, String elementName, String attrName) { indent(); print("<!ATTLIST \"" + elementName + "\" \"" + attrName + "\""); int attrValueType = format.getAttributeValueType(elementName, attrName); switch (attrValueType) { case IIOMetadataFormat.VALUE_NONE: throw new RuntimeException ("Encountered VALUE_NONE for an attribute!"); // break; case IIOMetadataFormat.VALUE_ARBITRARY: print(" #CDATA"); break; case IIOMetadataFormat.VALUE_RANGE: case IIOMetadataFormat.VALUE_RANGE_MIN_INCLUSIVE: case IIOMetadataFormat.VALUE_RANGE_MAX_INCLUSIVE: case IIOMetadataFormat.VALUE_RANGE_MIN_MAX_INCLUSIVE: print(" #CDATA"); break; case IIOMetadataFormat.VALUE_ENUMERATION: print(" ("); String[] attrValues = format.getAttributeEnumerations(elementName, attrName); for (int j = 0; j < attrValues.length - 1; j++) { print("\"" + attrValues[j] + "\" | "); } print("\"" + attrValues[attrValues.length - 1] + "\")"); break; case IIOMetadataFormat.VALUE_LIST: print(" #CDATA"); break; default: throw new RuntimeException ("Encountered unknown value type for an attribute!"); // break; } String defaultValue = format.getAttributeDefaultValue(elementName, attrName); if (defaultValue != null) { print(" "); print("\"" + defaultValue + "\""); } else { if (format.isAttributeRequired(elementName, attrName)) { print(" #REQUIRED"); } else { print(" #IMPLIED"); } } println(">"); String description = format.getAttributeDescription(elementName, attrName, null); if (description != null) { ++indentLevel; indent(); printWrapped("<!-- " + description + " -->", 5); println(); --indentLevel; } int dataType = format.getAttributeDataType(elementName, attrName); switch (attrValueType) { case IIOMetadataFormat.VALUE_ARBITRARY: indent(); println(" <!-- Data type: " + dataTypeNames[dataType] + " -->"); break; case IIOMetadataFormat.VALUE_RANGE: case IIOMetadataFormat.VALUE_RANGE_MIN_INCLUSIVE: case IIOMetadataFormat.VALUE_RANGE_MAX_INCLUSIVE: case IIOMetadataFormat.VALUE_RANGE_MIN_MAX_INCLUSIVE: indent(); println(" <!-- Data type: " + dataTypeNames[dataType] + " -->"); boolean minInclusive = (attrValueType & IIOMetadataFormat.VALUE_RANGE_MIN_INCLUSIVE_MASK) != 0; boolean maxInclusive = (attrValueType & IIOMetadataFormat.VALUE_RANGE_MAX_INCLUSIVE_MASK) != 0; indent(); println(" <!-- Min value: " + format.getAttributeMinValue(elementName, attrName) + " " + (minInclusive ? "(inclusive)" : "(exclusive)") + " -->"); String maxValue = format.getAttributeMaxValue(elementName, attrName); // Hack: don't print "infinite" max values if (dataType != IIOMetadataFormat.DATATYPE_INTEGER || !maxValue.equals(maxInteger)) { indent(); println(" <!-- Max value: " + maxValue + " " + (maxInclusive ? "(inclusive)" : "(exclusive)") + " -->"); } break; case IIOMetadataFormat.VALUE_LIST: indent(); println(" <!-- Data type: List of " + dataTypeNames[dataType] + " -->"); int minLength = format.getAttributeListMinLength(elementName, attrName); if (minLength != 0) { indent(); println(" <!-- Min length: " + minLength + " -->"); } int maxLength = format.getAttributeListMaxLength(elementName, attrName); if (maxLength != Integer.MAX_VALUE) { indent(); println(" <!-- Max length: " + maxLength + " -->"); } break; } } private void printObjectInfo(IIOMetadataFormat format, String elementName) { int objectType = format.getObjectValueType(elementName); if (objectType == IIOMetadataFormat.VALUE_NONE) { return; } Class objectClass = format.getObjectClass(elementName); if (objectClass != null) { indent(); if (objectType == IIOMetadataFormat.VALUE_LIST) { println(" <!-- User object: array of " + objectClass.getName() + " -->"); } else { println(" <!-- User object: " + objectClass.getName() + " -->"); } Object defaultValue = format.getObjectDefaultValue(elementName); if (defaultValue != null) { indent(); println(" <!-- Default value: " + defaultValue.toString() + " -->"); } switch (objectType) { case IIOMetadataFormat.VALUE_RANGE: indent(); println(" <!-- Min value: " + format.getObjectMinValue(elementName).toString() + " -->"); indent(); println(" <!-- Max value: " + format.getObjectMaxValue(elementName).toString() + " -->"); break; case IIOMetadataFormat.VALUE_ENUMERATION: Object[] enums = format.getObjectEnumerations(elementName); for (int i = 0; i < enums.length; i++) { indent(); println(" <!-- Enumerated value: " + enums[i].toString() + " -->"); } break; case IIOMetadataFormat.VALUE_LIST: int minLength = format.getObjectArrayMinLength(elementName); if (minLength != 0) { indent(); println(" <!-- Min length: " + minLength + " -->"); } int maxLength = format.getObjectArrayMaxLength(elementName); if (maxLength != Integer.MAX_VALUE) { indent(); println(" <!-- Max length: " + maxLength + " -->"); } break; } } } // Set of elements that have been printed already Set printedElements = new HashSet(); // Set of elements that have been scheduled to be printed Set scheduledElements = new HashSet(); private void print(IIOMetadataFormat format, String elementName) { // Don't print elements more than once if (printedElements.contains(elementName)) { return; } printedElements.add(elementName); // Add the unscheduled children of this node to a list, // and mark them as scheduled List children = new ArrayList(); String[] childNames = format.getChildNames(elementName); if (childNames != null) { for (int i = 0; i < childNames.length; i++) { String childName = childNames[i]; if (!scheduledElements.contains(childName)) { children.add(childName); scheduledElements.add(childName); } } } printElementInfo(format, elementName); printObjectInfo(format, elementName); ++indentLevel; String[] attrNames = format.getAttributeNames(elementName); for (int i = 0; i < attrNames.length; i++) { printAttributeInfo(format, elementName, attrNames[i]); } // Recurse on child nodes Iterator iter = children.iterator(); while (iter.hasNext()) { print(format, (String)iter.next()); } --indentLevel; } public static void main(String[] args) { IIOMetadataFormat format = null; if (args.length == 0 || args[0].equals("javax_imageio_1.0")) { format = IIOMetadataFormatImpl.getStandardFormatInstance(); } else { IIORegistry registry = IIORegistry.getDefaultInstance(); Iterator iter = registry.getServiceProviders(ImageReaderSpi.class, false); while (iter.hasNext()) { ImageReaderSpi spi = (ImageReaderSpi)iter.next(); if (args[0].equals (spi.getNativeStreamMetadataFormatName())) { System.out.print(spi.getDescription(null)); System.out.println(": native stream format"); format = spi.getStreamMetadataFormat(args[0]); break; } String[] extraStreamFormatNames = spi.getExtraStreamMetadataFormatNames(); if (extraStreamFormatNames != null && Arrays.asList(extraStreamFormatNames). contains(args[0])) { System.out.print(spi.getDescription(null)); System.out.println(": extra stream format"); format = spi.getStreamMetadataFormat(args[0]); break; } if (args[0].equals (spi.getNativeImageMetadataFormatName())) { System.out.print(spi.getDescription(null)); System.out.println(": native image format"); format = spi.getImageMetadataFormat(args[0]); break; } String[] extraImageFormatNames = spi.getExtraImageMetadataFormatNames(); if (extraImageFormatNames != null && Arrays.asList(extraImageFormatNames).contains(args[0])) { System.out.print(spi.getDescription(null)); System.out.println(": extra image format"); format = spi.getImageMetadataFormat(args[0]); break; } } } if (format == null) { System.err.println("Unknown format: " + args[0]); System.exit(0); } MetadataFormatPrinter printer = new MetadataFormatPrinter(System.out); printer.print(format); } }