Backport to fix iTXt chunk handling for pngs
Deepak Bhole
dbhole at redhat.com
Thu Dec 23 14:17:54 PST 2010
* Deepak Bhole <dbhole at redhat.com> [2010-12-23 15:41]:
> Hi,
>
> Currently, iTXt chunks in pngs are handled incorrectly in icedtea6. This
> has been reported as 6541476 in the Oracle bug db and has been fixed in
> OpenJDK7 for a while:
> http://hg.openjdk.java.net/jdk7/jdk7/jdk/rev/3a9d06af8830
>
> In order to cleanly apply the above, this patch needs to be applied as
> well:
> http://hg.openjdk.java.net/jdk7/jdk7/jdk/rev/94bcd3503668
>
> 94bcd3503668 is already in the jdk6 repo and will be in b21. However,
> 3a9d06af8830 isn't in jdk6 and I've requested that it be backported[1].
>
> Since icedtea6 is currently at b20, both of the above commits need to
> be applied. Attached patch does so. There is also an rhbz associated
> with this issue:
> https://bugzilla.redhat.com/show_bug.cgi?id=665355
>
> Given that both have been in 7 for over 2 years, I'd like to propose
> that this also be applied to 1.7, 1.8 and 1.9.
>
Just noticed that the original email has an incorrect copyright header.
New patch with correct header attached.
Also, please see Joe's note here:
http://mail.openjdk.java.net/pipermail/jdk6-dev/2010-December/002185.html
Should we follow suit for IcedTea and backport 6782079 too? There are no
bugs open for it atm (that I know of), but it'd certainly be a nice fix
to have.
Cheers,
Deepak
> ChangeLog:
>
> -------------------------------------------------------------------------------
> 2010-12-23 Deepak Bhole <dbhole at redhat.com>
>
> Backport S6687968, S6541476
> * Makefile.am: Add missing "\" to the patch list, update to include
> new patches.
> * NEWS: Updated.
> * patches/openjdk/6687968-pngimagereader_mem_leak.patch: Backport to allow
> S6541476 fix to apply cleanly.
> * patches/openjdk/6541476-png-iTXt-chunk.patch: Backport to fix iTXt chunk
> handling for png images. Also addresses RH665355.
> -------------------------------------------------------------------------------
>
> Cheers,
> Deepak
>
> [1]: Request for JDK6 backport of 3a9d06af8830:
> http://mail.openjdk.java.net/pipermail/jdk6-dev/2010-December/002182.html
>
>
> diff -r 7219bd74962a Makefile.am
> --- a/Makefile.am Thu Dec 23 14:56:09 2010 +0100
> +++ b/Makefile.am Thu Dec 23 15:20:57 2010 -0500
> @@ -312,8 +312,10 @@
> patches/openjdk/6979979-gtk_font_size_rounding.patch \
> patches/openjdk/6795356-proxylazyvalue-leak.patch \
> patches/rendering-engine-tests.patch \
> - patches/jtreg-TestXEmbedServer-fix.patch
> - patches/openjdk/6800846-printing-quality.patch
> + patches/jtreg-TestXEmbedServer-fix.patch \
> + patches/openjdk/6800846-printing-quality.patch \
> + patches/openjdk/6687968-pngimagereader_mem_leak.patch \
> + patches/openjdk/6541476-png-iTXt-chunk.patch
>
> if WITH_ALT_HSBUILD
> ICEDTEA_PATCHES += \
> diff -r 7219bd74962a NEWS
> --- a/NEWS Thu Dec 23 14:56:09 2010 +0100
> +++ b/NEWS Thu Dec 23 15:20:57 2010 -0500
> @@ -51,6 +51,8 @@
> - S6979979, RH508185: Rounding error in font sizes selected by the GTK Look and Feel
> - S6795356: Leak caused by javax.swing.UIDefaults.ProxyLazyValue.acc
> - S6800846, RH662230: Printing quality degraded with Java 6 compared to 5.0, index out of bounds exception.
> + - S6687968: PNGImageReader leaks native memory through an Inflater
> + - S6541476, RH665355: PNG imageio plugin incorrectly handles iTXt chunk
>
> * Bug fixes
> - S7003777, RH647674: JTextPane produces incorrect content after parsing the html text
> diff -r 7219bd74962a patches/openjdk/6541476-png-iTXt-chunk.patch
> --- /dev/null Thu Jan 01 00:00:00 1970 +0000
> +++ b/patches/openjdk/6541476-png-iTXt-chunk.patch Thu Dec 23 15:20:57 2010 -0500
> @@ -0,0 +1,549 @@
> +diff -urN openjdk.orig/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGImageReader.java openjdk/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGImageReader.java
> +--- openjdk.orig/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGImageReader.java 2010-12-23 15:16:15.107446365 -0500
> ++++ openjdk/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGImageReader.java 2010-12-23 15:17:00.433446450 -0500
> +@@ -44,7 +44,6 @@
> + import java.util.Arrays;
> + import java.util.Enumeration;
> + import java.util.Iterator;
> +-import java.util.List;
> + import java.util.zip.Inflater;
> + import java.util.zip.InflaterInputStream;
> + import javax.imageio.IIOException;
> +@@ -57,6 +56,7 @@
> + import com.sun.imageio.plugins.common.InputStreamAdapter;
> + import com.sun.imageio.plugins.common.ReaderUtil;
> + import com.sun.imageio.plugins.common.SubImageInputStream;
> ++import java.io.ByteArrayOutputStream;
> + import sun.awt.image.ByteInterleavedRaster;
> +
> + class PNGImageDataEnumeration implements Enumeration {
> +@@ -209,6 +209,15 @@
> + resetStreamSettings();
> + }
> +
> ++ private String readNullTerminatedString(String charset) throws IOException {
> ++ ByteArrayOutputStream baos = new ByteArrayOutputStream();
> ++ int b;
> ++ while ((b = stream.read()) != 0) {
> ++ baos.write(b);
> ++ }
> ++ return new String(baos.toByteArray(), charset);
> ++ }
> ++
> + private String readNullTerminatedString() throws IOException {
> + StringBuilder b = new StringBuilder();
> + int c;
> +@@ -447,26 +456,27 @@
> + metadata.iTXt_keyword.add(keyword);
> +
> + int compressionFlag = stream.readUnsignedByte();
> +- metadata.iTXt_compressionFlag.add(new Integer(compressionFlag));
> ++ metadata.iTXt_compressionFlag.add(Boolean.valueOf(compressionFlag == 1));
> +
> + int compressionMethod = stream.readUnsignedByte();
> +- metadata.iTXt_compressionMethod.add(new Integer(compressionMethod));
> ++ metadata.iTXt_compressionMethod.add(Integer.valueOf(compressionMethod));
> +
> +- String languageTag = readNullTerminatedString();
> ++ String languageTag = readNullTerminatedString("UTF8");
> + metadata.iTXt_languageTag.add(languageTag);
> +
> +- String translatedKeyword = stream.readUTF();
> ++ String translatedKeyword =
> ++ readNullTerminatedString("UTF8");
> + metadata.iTXt_translatedKeyword.add(translatedKeyword);
> +- stream.skipBytes(1); // Null separator
> +
> + String text;
> ++ long pos = stream.getStreamPosition();
> ++ byte[] b = new byte[(int)(chunkStart + chunkLength - pos)];
> ++ stream.readFully(b);
> ++
> + if (compressionFlag == 1) { // Decompress the text
> +- long pos = stream.getStreamPosition();
> +- byte[] b = new byte[(int)(chunkStart + chunkLength - pos)];
> +- stream.readFully(b);
> +- text = inflate(b);
> ++ text = new String(inflate(b), "UTF8");
> + } else {
> +- text = stream.readUTF();
> ++ text = new String(b, "UTF8");
> + }
> + metadata.iTXt_text.add(text);
> + }
> +@@ -615,20 +625,20 @@
> + metadata.tRNS_present = true;
> + }
> +
> +- private static String inflate(byte[] b) throws IOException {
> ++ private static byte[] inflate(byte[] b) throws IOException {
> + InputStream bais = new ByteArrayInputStream(b);
> + InputStream iis = new InflaterInputStream(bais);
> ++ ByteArrayOutputStream baos = new ByteArrayOutputStream();
> +
> +- StringBuilder sb = new StringBuilder(80);
> + int c;
> + try {
> + while ((c = iis.read()) != -1) {
> +- sb.append((char)c);
> ++ baos.write(c);
> + }
> + } finally {
> + iis.close();
> + }
> +- return sb.toString();
> ++ return baos.toByteArray();
> + }
> +
> + private void parse_zTXt_chunk(int chunkLength) throws IOException {
> +@@ -640,7 +650,7 @@
> +
> + byte[] b = new byte[chunkLength - keyword.length() - 2];
> + stream.readFully(b);
> +- metadata.zTXt_text.add(inflate(b));
> ++ metadata.zTXt_text.add(new String(inflate(b)));
> + }
> +
> + private void readMetadata() throws IIOException {
> +diff -urN openjdk.orig/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java openjdk/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java
> +--- openjdk.orig/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java 2010-12-23 15:16:15.107446365 -0500
> ++++ openjdk/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java 2010-12-23 15:17:00.434446439 -0500
> +@@ -671,13 +671,13 @@
> + }
> + }
> +
> +- private byte[] deflate(String s) throws IOException {
> ++ private byte[] deflate(byte[] b) throws IOException {
> + ByteArrayOutputStream baos = new ByteArrayOutputStream();
> + DeflaterOutputStream dos = new DeflaterOutputStream(baos);
> +
> +- int len = s.length();
> ++ int len = b.length;
> + for (int i = 0; i < len; i++) {
> +- dos.write((int)s.charAt(i));
> ++ dos.write((int)(0xff & b[i]));
> + }
> + dos.close();
> +
> +@@ -685,38 +685,37 @@
> + }
> +
> + private void write_iTXt() throws IOException {
> +- Iterator keywordIter = metadata.iTXt_keyword.iterator();
> +- Iterator flagIter = metadata.iTXt_compressionFlag.iterator();
> +- Iterator methodIter = metadata.iTXt_compressionMethod.iterator();
> +- Iterator languageIter = metadata.iTXt_languageTag.iterator();
> +- Iterator translatedKeywordIter =
> ++ Iterator<String> keywordIter = metadata.iTXt_keyword.iterator();
> ++ Iterator<Boolean> flagIter = metadata.iTXt_compressionFlag.iterator();
> ++ Iterator<Integer> methodIter = metadata.iTXt_compressionMethod.iterator();
> ++ Iterator<String> languageIter = metadata.iTXt_languageTag.iterator();
> ++ Iterator<String> translatedKeywordIter =
> + metadata.iTXt_translatedKeyword.iterator();
> +- Iterator textIter = metadata.iTXt_text.iterator();
> ++ Iterator<String> textIter = metadata.iTXt_text.iterator();
> +
> + while (keywordIter.hasNext()) {
> + ChunkStream cs = new ChunkStream(PNGImageReader.iTXt_TYPE, stream);
> +- String keyword = (String)keywordIter.next();
> +- cs.writeBytes(keyword);
> ++
> ++ cs.writeBytes(keywordIter.next());
> + cs.writeByte(0);
> +
> +- int flag = ((Integer)flagIter.next()).intValue();
> +- cs.writeByte(flag);
> +- int method = ((Integer)methodIter.next()).intValue();
> +- cs.writeByte(method);
> ++ Boolean compressed = flagIter.next();
> ++ cs.writeByte(compressed ? 1 : 0);
> +
> +- String languageTag = (String)languageIter.next();
> +- cs.writeBytes(languageTag);
> ++ cs.writeByte(methodIter.next().intValue());
> ++
> ++ cs.writeBytes(languageIter.next());
> + cs.writeByte(0);
> +
> +- String translatedKeyword = (String)translatedKeywordIter.next();
> +- cs.writeBytes(translatedKeyword);
> ++
> ++ cs.write(translatedKeywordIter.next().getBytes("UTF8"));
> + cs.writeByte(0);
> +
> +- String text = (String)textIter.next();
> +- if (flag == 1) {
> +- cs.write(deflate(text));
> ++ String text = textIter.next();
> ++ if (compressed) {
> ++ cs.write(deflate(text.getBytes("UTF8")));
> + } else {
> +- cs.writeUTF(text);
> ++ cs.write(text.getBytes("UTF8"));
> + }
> + cs.finish();
> + }
> +@@ -737,7 +736,7 @@
> + cs.writeByte(compressionMethod);
> +
> + String text = (String)textIter.next();
> +- cs.write(deflate(text));
> ++ cs.write(deflate(text.getBytes()));
> + cs.finish();
> + }
> + }
> +diff -urN openjdk.orig/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGMetadata.java openjdk/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGMetadata.java
> +--- openjdk.orig/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGMetadata.java 2010-06-21 17:15:11.000000000 -0400
> ++++ openjdk/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGMetadata.java 2010-12-23 15:17:00.436446415 -0500
> +@@ -176,12 +176,12 @@
> + public byte[] iCCP_compressedProfile;
> +
> + // iTXt chunk
> +- public ArrayList iTXt_keyword = new ArrayList(); // Strings
> +- public ArrayList iTXt_compressionFlag = new ArrayList(); // Integers
> +- public ArrayList iTXt_compressionMethod = new ArrayList(); // Integers
> +- public ArrayList iTXt_languageTag = new ArrayList(); // Strings
> +- public ArrayList iTXt_translatedKeyword = new ArrayList(); // Strings
> +- public ArrayList iTXt_text = new ArrayList(); // Strings
> ++ public ArrayList<String> iTXt_keyword = new ArrayList<String>();
> ++ public ArrayList<Boolean> iTXt_compressionFlag = new ArrayList<Boolean>();
> ++ public ArrayList<Integer> iTXt_compressionMethod = new ArrayList<Integer>();
> ++ public ArrayList<String> iTXt_languageTag = new ArrayList<String>();
> ++ public ArrayList<String> iTXt_translatedKeyword = new ArrayList<String>();
> ++ public ArrayList<String> iTXt_text = new ArrayList<String>();
> +
> + // pHYs chunk
> + public boolean pHYs_present;
> +@@ -599,19 +599,17 @@
> + if (iTXt_keyword.size() > 0) {
> + IIOMetadataNode iTXt_parent = new IIOMetadataNode("iTXt");
> + for (int i = 0; i < iTXt_keyword.size(); i++) {
> +- Integer val;
> +-
> + IIOMetadataNode iTXt_node = new IIOMetadataNode("iTXtEntry");
> +- iTXt_node.setAttribute("keyword", (String)iTXt_keyword.get(i));
> +- val = (Integer)iTXt_compressionFlag.get(i);
> +- iTXt_node.setAttribute("compressionFlag", val.toString());
> +- val = (Integer)iTXt_compressionMethod.get(i);
> +- iTXt_node.setAttribute("compressionMethod", val.toString());
> ++ iTXt_node.setAttribute("keyword", iTXt_keyword.get(i));
> ++ iTXt_node.setAttribute("compressionFlag",
> ++ iTXt_compressionFlag.get(i) ? "1" : "0");
> ++ iTXt_node.setAttribute("compressionMethod",
> ++ iTXt_compressionMethod.get(i).toString());
> + iTXt_node.setAttribute("languageTag",
> +- (String)iTXt_languageTag.get(i));
> ++ iTXt_languageTag.get(i));
> + iTXt_node.setAttribute("translatedKeyword",
> +- (String)iTXt_translatedKeyword.get(i));
> +- iTXt_node.setAttribute("text", (String)iTXt_text.get(i));
> ++ iTXt_translatedKeyword.get(i));
> ++ iTXt_node.setAttribute("text", iTXt_text.get(i));
> +
> + iTXt_parent.appendChild(iTXt_node);
> + }
> +@@ -1039,11 +1037,11 @@
> +
> + for (int i = 0; i < iTXt_keyword.size(); i++) {
> + node = new IIOMetadataNode("TextEntry");
> +- node.setAttribute("keyword", (String)iTXt_keyword.get(i));
> +- node.setAttribute("value", (String)iTXt_text.get(i));
> ++ node.setAttribute("keyword", iTXt_keyword.get(i));
> ++ node.setAttribute("value", iTXt_text.get(i));
> + node.setAttribute("language",
> +- (String)iTXt_languageTag.get(i));
> +- if (((Integer)iTXt_compressionFlag.get(i)).intValue() == 1) {
> ++ iTXt_languageTag.get(i));
> ++ if (iTXt_compressionFlag.get(i)) {
> + node.setAttribute("compression", "deflate");
> + } else {
> + node.setAttribute("compression", "none");
> +@@ -1429,11 +1427,11 @@
> +
> + boolean compressionFlag =
> + getBooleanAttribute(iTXt_node, "compressionFlag");
> +- iTXt_compressionFlag.add(new Boolean(compressionFlag));
> ++ iTXt_compressionFlag.add(Boolean.valueOf(compressionFlag));
> +
> + String compressionMethod =
> + getAttribute(iTXt_node, "compressionMethod");
> +- iTXt_compressionMethod.add(compressionMethod);
> ++ iTXt_compressionMethod.add(Integer.valueOf(compressionMethod));
> +
> + String languageTag =
> + getAttribute(iTXt_node, "languageTag");
> +@@ -1952,13 +1950,10 @@
> + tEXt_text.add(value);
> + }
> + } else {
> +- int flag = compression.equals("zip") ?
> +- 1 : 0;
> +-
> + // Use an iTXt node
> + iTXt_keyword.add(keyword);
> +- iTXt_compressionFlag.add(new Integer(flag));
> +- iTXt_compressionMethod.add(new Integer(0));
> ++ iTXt_compressionFlag.add(Boolean.valueOf(compression.equals("zip")));
> ++ iTXt_compressionMethod.add(Integer.valueOf(0));
> + iTXt_languageTag.add(language);
> + iTXt_translatedKeyword.add(keyword); // fake it
> + iTXt_text.add(value);
> +@@ -1995,12 +1990,12 @@
> + gAMA_present = false;
> + hIST_present = false;
> + iCCP_present = false;
> +- iTXt_keyword = new ArrayList();
> +- iTXt_compressionFlag = new ArrayList();
> +- iTXt_compressionMethod = new ArrayList();
> +- iTXt_languageTag = new ArrayList();
> +- iTXt_translatedKeyword = new ArrayList();
> +- iTXt_text = new ArrayList();
> ++ iTXt_keyword = new ArrayList<String>();
> ++ iTXt_compressionFlag = new ArrayList<Boolean>();
> ++ iTXt_compressionMethod = new ArrayList<Integer>();
> ++ iTXt_languageTag = new ArrayList<String>();
> ++ iTXt_translatedKeyword = new ArrayList<String>();
> ++ iTXt_text = new ArrayList<String>();
> + pHYs_present = false;
> + sBIT_present = false;
> + sPLT_present = false;
> +diff -urN openjdk.orig/jdk/test/javax/imageio/plugins/png/ITXtTest.java openjdk/jdk/test/javax/imageio/plugins/png/ITXtTest.java
> +--- openjdk.orig/jdk/test/javax/imageio/plugins/png/ITXtTest.java 1969-12-31 19:00:00.000000000 -0500
> ++++ openjdk/jdk/test/javax/imageio/plugins/png/ITXtTest.java 2010-12-23 15:17:00.436446415 -0500
> +@@ -0,0 +1,236 @@
> ++/*
> ++ * 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 6541476
> ++ * @summary Test verifies that ImageIO PNG plugin correcly handles the
> ++ * iTxt chunk (International textual data).
> ++ *
> ++ * @run main ITXtTest
> ++ */
> ++
> ++
> ++import java.awt.Color;
> ++import java.awt.Graphics2D;
> ++import java.awt.image.BufferedImage;
> ++import java.io.File;
> ++
> ++import javax.imageio.ImageIO;
> ++import javax.imageio.ImageReader;
> ++import javax.imageio.IIOImage;
> ++import javax.imageio.ImageTypeSpecifier;
> ++import javax.imageio.ImageWriter;
> ++import javax.imageio.metadata.IIOMetadata;
> ++import javax.imageio.metadata.IIOMetadataNode;
> ++import javax.imageio.stream.ImageOutputStream;
> ++import javax.imageio.stream.ImageInputStream;
> ++
> ++import org.w3c.dom.Node;
> ++
> ++public class ITXtTest {
> ++ static public void main(String args[]) {
> ++ ITXtTest t_en = new ITXtTest();
> ++ t_en.description = "xml - en";
> ++ t_en.keyword = "XML:com.adobe.xmp";
> ++ t_en.isCompressed = false;
> ++ t_en.compression = 0;
> ++ t_en.language = "en";
> ++ t_en.trasKeyword = "XML:com.adobe.xmp";
> ++ t_en.text = "<xml>Something</xml>";
> ++
> ++ doTest(t_en);
> ++
> ++ // check compression case
> ++ t_en.isCompressed = true;
> ++ t_en.description = "xml - en - compressed";
> ++
> ++ doTest(t_en);
> ++
> ++ ITXtTest t_ru = new ITXtTest();
> ++ t_ru.description = "xml - ru";
> ++ t_ru.keyword = "XML:com.adobe.xmp";
> ++ t_ru.isCompressed = false;
> ++ t_ru.compression = 0;
> ++ t_ru.language = "ru";
> ++ t_ru.trasKeyword = "\u0410\u0410\u0410\u0410\u0410 XML";
> ++ t_ru.text = "<xml>\u042A\u042F\u042F\u042F\u042F\u042F\u042F</xml>";
> ++
> ++ doTest(t_ru);
> ++
> ++ t_ru.isCompressed = true;
> ++ t_ru.description = "xml - ru - compressed";
> ++
> ++ doTest(t_ru);
> ++ }
> ++
> ++
> ++ String description;
> ++
> ++ String keyword;
> ++ boolean isCompressed;
> ++ int compression;
> ++ String language;
> ++ String trasKeyword;
> ++ String text;
> ++
> ++
> ++ public IIOMetadataNode getNode() {
> ++ IIOMetadataNode iTXt = new IIOMetadataNode("iTXt");
> ++ IIOMetadataNode iTXtEntry = new IIOMetadataNode("iTXtEntry");
> ++ iTXtEntry.setAttribute("keyword", keyword);
> ++ iTXtEntry.setAttribute("compressionFlag",
> ++ isCompressed ? "true" : "false");
> ++ iTXtEntry.setAttribute("compressionMethod",
> ++ Integer.toString(compression));
> ++ iTXtEntry.setAttribute("languageTag", language);
> ++ iTXtEntry.setAttribute("translatedKeyword",
> ++ trasKeyword);
> ++ iTXtEntry.setAttribute("text", text);
> ++ iTXt.appendChild(iTXtEntry);
> ++ return iTXt;
> ++ }
> ++
> ++ public static ITXtTest getFromNode(IIOMetadataNode n) {
> ++ ITXtTest t = new ITXtTest();
> ++
> ++ if (!"iTXt".equals(n.getNodeName())) {
> ++ throw new RuntimeException("Invalid node");
> ++ }
> ++ IIOMetadataNode e = (IIOMetadataNode)n.getFirstChild();
> ++ if (!"iTXtEntry".equals(e.getNodeName())) {
> ++ throw new RuntimeException("Invalid entry node");
> ++ }
> ++ t.keyword = e.getAttribute("keyword");
> ++ t.isCompressed =
> ++ (Integer.valueOf(e.getAttribute("compressionFlag")).intValue() == 1);
> ++ t.compression =
> ++ Integer.valueOf(e.getAttribute("compressionMethod")).intValue();
> ++ t.language = e.getAttribute("languageTag");
> ++ t.trasKeyword = e.getAttribute("translatedKeyword");
> ++ t.text = e.getAttribute("text");
> ++
> ++ return t;
> ++ }
> ++
> ++ @Override
> ++ public boolean equals(Object o) {
> ++ if (! (o instanceof ITXtTest)) {
> ++ return false;
> ++ }
> ++ ITXtTest t = (ITXtTest)o;
> ++ if (!keyword.equals(t.keyword)) { return false; }
> ++ if (isCompressed != t.isCompressed) { return false; }
> ++ if (compression != t.compression) { return false; }
> ++ if (!language.equals(t.language)) { return false; }
> ++ if (!trasKeyword.equals(t.trasKeyword)) { return false; }
> ++ if (!text.equals(t.text)) { return false; }
> ++
> ++ return true;
> ++ }
> ++
> ++
> ++
> ++ private static void doTest(ITXtTest src) {
> ++
> ++ System.out.println("Test: " + src.description);
> ++
> ++ File file = new File("test.png");
> ++
> ++ writeTo(file, src);
> ++ ITXtTest dst = readFrom(file);
> ++
> ++ if (dst == null || !dst.equals(src)) {
> ++ throw new RuntimeException("Test failed.");
> ++ }
> ++
> ++ System.out.println("Test passed.");
> ++ }
> ++
> ++ private static void writeTo(File f, ITXtTest t) {
> ++ BufferedImage src = createBufferedImage();
> ++ try {
> ++ ImageOutputStream imageOutputStream =
> ++ ImageIO.createImageOutputStream(f);
> ++
> ++ ImageTypeSpecifier imageTypeSpecifier =
> ++ new ImageTypeSpecifier(src);
> ++ ImageWriter imageWriter =
> ++ ImageIO.getImageWritersByFormatName("PNG").next();
> ++
> ++ imageWriter.setOutput(imageOutputStream);
> ++
> ++ IIOMetadata m =
> ++ imageWriter.getDefaultImageMetadata(imageTypeSpecifier, null);
> ++
> ++ String format = m.getNativeMetadataFormatName();
> ++ Node root = m.getAsTree(format);
> ++
> ++ IIOMetadataNode iTXt = t.getNode();
> ++ root.appendChild(iTXt);
> ++ m.setFromTree(format, root);
> ++
> ++ imageWriter.write(new IIOImage(src, null, m));
> ++ imageOutputStream.close();
> ++ System.out.println("Writing done.");
> ++ } catch (Throwable e) {
> ++ throw new RuntimeException("Writing test failed.", e);
> ++ }
> ++ }
> ++
> ++ private static ITXtTest readFrom(File f) {
> ++ try {
> ++ ImageInputStream iis = ImageIO.createImageInputStream(f);
> ++ ImageReader r = ImageIO.getImageReaders(iis).next();
> ++ r.setInput(iis);
> ++
> ++ IIOImage dst = r.readAll(0, null);
> ++
> ++ // look for iTXt node
> ++ IIOMetadata m = dst.getMetadata();
> ++ Node root = m.getAsTree(m.getNativeMetadataFormatName());
> ++ Node n = root.getFirstChild();
> ++ while (n != null && !"iTXt".equals(n.getNodeName())) {
> ++ n = n.getNextSibling();
> ++ }
> ++ if (n == null) {
> ++ throw new RuntimeException("No iTXt node!");
> ++ }
> ++ ITXtTest t = ITXtTest.getFromNode((IIOMetadataNode)n);
> ++ return t;
> ++ } catch (Throwable e) {
> ++ throw new RuntimeException("Reading test failed.", e);
> ++ }
> ++ }
> ++
> ++ private static BufferedImage createBufferedImage() {
> ++ BufferedImage image = new BufferedImage(128, 128,
> ++ BufferedImage.TYPE_4BYTE_ABGR_PRE);
> ++ Graphics2D graph = image.createGraphics();
> ++ graph.setPaintMode();
> ++ graph.setColor(Color.orange);
> ++ graph.fillRect(32, 32, 64, 64);
> ++ graph.dispose();
> ++ return image;
> ++ }
> ++}
> diff -r 7219bd74962a patches/openjdk/6687968-pngimagereader_mem_leak.patch
> --- /dev/null Thu Jan 01 00:00:00 1970 +0000
> +++ b/patches/openjdk/6687968-pngimagereader_mem_leak.patch Thu Dec 23 15:20:57 2010 -0500
> @@ -0,0 +1,126 @@
> +diff -urN openjdk.orig/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGImageReader.java openjdk/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGImageReader.java
> +--- openjdk.orig/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGImageReader.java 2010-06-21 17:15:11.000000000 -0400
> ++++ openjdk/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGImageReader.java 2010-12-23 15:12:24.471446202 -0500
> +@@ -618,10 +618,15 @@
> + private static String inflate(byte[] b) throws IOException {
> + InputStream bais = new ByteArrayInputStream(b);
> + InputStream iis = new InflaterInputStream(bais);
> ++
> + StringBuilder sb = new StringBuilder(80);
> + int c;
> +- while ((c = iis.read()) != -1) {
> +- sb.append((char)c);
> ++ try {
> ++ while ((c = iis.read()) != -1) {
> ++ sb.append((char)c);
> ++ }
> ++ } finally {
> ++ iis.close();
> + }
> + return sb.toString();
> + }
> +@@ -1246,13 +1251,26 @@
> + destinationBands = param.getDestinationBands();
> + destinationOffset = param.getDestinationOffset();
> + }
> +-
> ++ Inflater inf = null;
> + try {
> + stream.seek(imageStartPosition);
> +
> + Enumeration e = new PNGImageDataEnumeration(stream);
> + InputStream is = new SequenceInputStream(e);
> +- is = new InflaterInputStream(is, new Inflater());
> ++
> ++ /* InflaterInputStream uses an Inflater instance which consumes
> ++ * native (non-GC visible) resources. This is normally implicitly
> ++ * freed when the stream is closed. However since the
> ++ * InflaterInputStream wraps a client-supplied input stream,
> ++ * we cannot close it.
> ++ * But the app may depend on GC finalization to close the stream.
> ++ * Therefore to ensure timely freeing of native resources we
> ++ * explicitly create the Inflater instance and free its resources
> ++ * when we are done with the InflaterInputStream by calling
> ++ * inf.end();
> ++ */
> ++ inf = new Inflater();
> ++ is = new InflaterInputStream(is, inf);
> + is = new BufferedInputStream(is);
> + this.pixelStream = new DataInputStream(is);
> +
> +@@ -1285,6 +1303,10 @@
> + }
> + } catch (IOException e) {
> + throw new IIOException("Error reading PNG image data", e);
> ++ } finally {
> ++ if (inf != null) {
> ++ inf.end();
> ++ }
> + }
> + }
> +
> +diff -urN openjdk.orig/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java openjdk/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java
> +--- openjdk.orig/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java 2010-06-21 17:15:11.000000000 -0400
> ++++ openjdk/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java 2010-12-23 15:12:24.472446225 -0500
> +@@ -244,13 +244,17 @@
> + }
> +
> + public void finish() throws IOException {
> +- if (!def.finished()) {
> +- def.finish();
> +- while (!def.finished()) {
> +- deflate();
> ++ try {
> ++ if (!def.finished()) {
> ++ def.finish();
> ++ while (!def.finished()) {
> ++ deflate();
> ++ }
> + }
> ++ finishChunk();
> ++ } finally {
> ++ def.end();
> + }
> +- finishChunk();
> + }
> +
> + protected void finalize() throws Throwable {
> +@@ -928,23 +932,24 @@
> + // Use sourceXOffset, etc.
> + private void write_IDAT(RenderedImage image) throws IOException {
> + IDATOutputStream ios = new IDATOutputStream(stream, 32768);
> +-
> +- if (metadata.IHDR_interlaceMethod == 1) {
> +- for (int i = 0; i < 7; i++) {
> +- encodePass(ios, image,
> +- PNGImageReader.adam7XOffset[i],
> +- PNGImageReader.adam7YOffset[i],
> +- PNGImageReader.adam7XSubsampling[i],
> +- PNGImageReader.adam7YSubsampling[i]);
> +- if (abortRequested()) {
> +- break;
> ++ try {
> ++ if (metadata.IHDR_interlaceMethod == 1) {
> ++ for (int i = 0; i < 7; i++) {
> ++ encodePass(ios, image,
> ++ PNGImageReader.adam7XOffset[i],
> ++ PNGImageReader.adam7YOffset[i],
> ++ PNGImageReader.adam7XSubsampling[i],
> ++ PNGImageReader.adam7YSubsampling[i]);
> ++ if (abortRequested()) {
> ++ break;
> ++ }
> + }
> ++ } else {
> ++ encodePass(ios, image, 0, 0, 1, 1);
> + }
> +- } else {
> +- encodePass(ios, image, 0, 0, 1, 1);
> ++ } finally {
> ++ ios.finish();
> + }
> +-
> +- ios.finish();
> + }
> +
> + private void writeIEND() throws IOException {
More information about the distro-pkg-dev
mailing list