5106550: PNG writer merge standard metadata fails for TextEntry sans #IMPLIED attributes
authorbae
Fri, 12 Dec 2008 17:38:14 +0300
changeset 2368 5a872c1edd4f
parent 1741 f02cad8a9114
child 2369 b58cdc0321f5
5106550: PNG writer merge standard metadata fails for TextEntry sans #IMPLIED attributes Reviewed-by: igor, prr Contributed-by: Martin von Gagern <martin.vgagern@gmx.net>
jdk/src/share/classes/com/sun/imageio/plugins/png/PNGMetadata.java
jdk/test/javax/imageio/plugins/png/MergeStdCommentTest.java
--- a/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGMetadata.java	Mon Dec 08 17:04:22 2008 -0800
+++ b/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGMetadata.java	Fri Dec 12 17:38:14 2008 +0300
@@ -1040,7 +1040,7 @@
             node.setAttribute("language",
                               iTXt_languageTag.get(i));
             if (iTXt_compressionFlag.get(i)) {
-                node.setAttribute("compression", "deflate");
+                node.setAttribute("compression", "zip");
             } else {
                 node.setAttribute("compression", "none");
             }
@@ -1052,7 +1052,7 @@
             node = new IIOMetadataNode("TextEntry");
             node.setAttribute("keyword", (String)zTXt_keyword.get(i));
             node.setAttribute("value", (String)zTXt_text.get(i));
-            node.setAttribute("compression", "deflate");
+            node.setAttribute("compression", "zip");
 
             text_node.appendChild(node);
         }
@@ -1421,26 +1421,30 @@
                     }
 
                     String keyword = getAttribute(iTXt_node, "keyword");
-                    iTXt_keyword.add(keyword);
+                    if (isValidKeyword(keyword)) {
+                        iTXt_keyword.add(keyword);
 
-                    boolean compressionFlag =
-                        getBooleanAttribute(iTXt_node, "compressionFlag");
-                    iTXt_compressionFlag.add(Boolean.valueOf(compressionFlag));
+                        boolean compressionFlag =
+                            getBooleanAttribute(iTXt_node, "compressionFlag");
+                        iTXt_compressionFlag.add(Boolean.valueOf(compressionFlag));
 
-                    String compressionMethod =
-                        getAttribute(iTXt_node, "compressionMethod");
-                    iTXt_compressionMethod.add(Integer.valueOf(compressionMethod));
+                        String compressionMethod =
+                            getAttribute(iTXt_node, "compressionMethod");
+                        iTXt_compressionMethod.add(Integer.valueOf(compressionMethod));
 
-                    String languageTag =
-                        getAttribute(iTXt_node, "languageTag");
-                    iTXt_languageTag.add(languageTag);
+                        String languageTag =
+                            getAttribute(iTXt_node, "languageTag");
+                        iTXt_languageTag.add(languageTag);
 
-                    String translatedKeyword =
-                        getAttribute(iTXt_node, "translatedKeyword");
-                    iTXt_translatedKeyword.add(translatedKeyword);
+                        String translatedKeyword =
+                            getAttribute(iTXt_node, "translatedKeyword");
+                        iTXt_translatedKeyword.add(translatedKeyword);
 
-                    String text = getAttribute(iTXt_node, "text");
-                    iTXt_text.add(text);
+                        String text = getAttribute(iTXt_node, "text");
+                        iTXt_text.add(text);
+
+                    }
+                    // silently skip invalid text entry
 
                     iTXt_node = iTXt_node.getNextSibling();
                 }
@@ -1692,11 +1696,45 @@
         }
     }
 
-    private boolean isISOLatin(String s) {
+    /*
+     * Accrding to PNG spec, keywords are restricted to 1 to 79 bytes
+     * in length. Keywords shall contain only printable Latin-1 characters
+     * and spaces; To reduce the chances for human misreading of a keyword,
+     * leading spaces, trailing spaces, and consecutive spaces are not
+     * permitted in keywords.
+     *
+     * See: http://www.w3.org/TR/PNG/#11keywords
+     */
+    private boolean isValidKeyword(String s) {
+        int len = s.length();
+        if (len < 1 || len >= 80) {
+            return false;
+        }
+        if (s.startsWith(" ") || s.endsWith(" ") || s.contains("  ")) {
+            return false;
+        }
+        return isISOLatin(s, false);
+    }
+
+    /*
+     * According to PNG spec, keyword shall contain only printable
+     * Latin-1 [ISO-8859-1] characters and spaces; that is, only
+     * character codes 32-126 and 161-255 decimal are allowed.
+     * For Latin-1 value fields the 0x10 (linefeed) control
+     * character is aloowed too.
+     *
+     * See: http://www.w3.org/TR/PNG/#11keywords
+     */
+    private boolean isISOLatin(String s, boolean isLineFeedAllowed) {
         int len = s.length();
         for (int i = 0; i < len; i++) {
-            if (s.charAt(i) > 255) {
-                return false;
+            char c = s.charAt(i);
+            if (c < 32 || c > 255 || (c > 126 && c < 161)) {
+                // not printable. Check whether this is an allowed
+                // control char
+                if (!isLineFeedAllowed || c != 0x10) {
+                    return false;
+                }
             }
         }
         return true;
@@ -1929,19 +1967,22 @@
                 while (child != null) {
                     String childName = child.getNodeName();
                     if (childName.equals("TextEntry")) {
-                        String keyword = getAttribute(child, "keyword");
+                        String keyword =
+                            getAttribute(child, "keyword", "", false);
                         String value = getAttribute(child, "value");
-                        String encoding = getAttribute(child, "encoding");
-                        String language = getAttribute(child, "language");
+                        String language =
+                            getAttribute(child, "language", "", false);
                         String compression =
-                            getAttribute(child, "compression");
+                            getAttribute(child, "compression", "none", false);
 
-                        if (isISOLatin(value)) {
+                        if (!isValidKeyword(keyword)) {
+                            // Just ignore this node, PNG requires keywords
+                        } else if (isISOLatin(value, true)) {
                             if (compression.equals("zip")) {
                                 // Use a zTXt node
                                 zTXt_keyword.add(keyword);
                                 zTXt_text.add(value);
-                                zTXt_compressionMethod.add(new Integer(0));
+                                zTXt_compressionMethod.add(Integer.valueOf(0));
                             } else {
                                 // Use a tEXt node
                                 tEXt_keyword.add(keyword);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/imageio/plugins/png/MergeStdCommentTest.java	Fri Dec 12 17:38:14 2008 +0300
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/**
+ * @test
+ * @bug 5106550
+ * @summary Merge a comment using the standard metdata format
+ *          and only a minimal set of attributes
+ */
+
+import java.awt.image.BufferedImage;
+import javax.imageio.ImageIO;
+import javax.imageio.ImageTypeSpecifier;
+import javax.imageio.ImageWriter;
+import javax.imageio.metadata.IIOMetadata;
+import org.w3c.dom.DOMImplementation;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.bootstrap.DOMImplementationRegistry;
+
+public class MergeStdCommentTest {
+
+    public static void main(String[] args) throws Exception {
+        String format = "javax_imageio_1.0";
+        BufferedImage img =
+            new BufferedImage(16, 16, BufferedImage.TYPE_INT_RGB);
+        ImageWriter iw = ImageIO.getImageWritersByMIMEType("image/png").next();
+        IIOMetadata meta =
+            iw.getDefaultImageMetadata(new ImageTypeSpecifier(img), null);
+        DOMImplementationRegistry registry;
+        registry = DOMImplementationRegistry.newInstance();
+        DOMImplementation impl = registry.getDOMImplementation("XML 3.0");
+        Document doc = impl.createDocument(null, format, null);
+        Element root, text, entry;
+        root = doc.getDocumentElement();
+        root.appendChild(text = doc.createElement("Text"));
+        text.appendChild(entry = doc.createElement("TextEntry"));
+        // keyword isn't #REQUIRED by the standard metadata format.
+        // However, it is required by the PNG format, so we include it here.
+        entry.setAttribute("keyword", "Comment");
+        entry.setAttribute("value", "Some demo comment");
+        meta.mergeTree(format, root);
+    }
+}