1 /*
   2  * Copyright (c) 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.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /**
  25  * @test
  26  * @bug     6945174
  27  * @summary Test verifies that PNG image readr throw correct exception if image contains
  28  *          a chunk with incorrect length.
  29  * @run     main ReadMalformedPngTest
  30  */
  31 
  32 import java.awt.Color;
  33 import java.awt.GradientPaint;
  34 import java.awt.Graphics2D;
  35 import java.awt.image.BufferedImage;
  36 import java.io.ByteArrayInputStream;
  37 import java.io.ByteArrayOutputStream;
  38 import java.io.IOException;
  39 import javax.imageio.IIOException;
  40 import javax.imageio.IIOImage;
  41 import javax.imageio.ImageIO;
  42 import javax.imageio.ImageTypeSpecifier;
  43 import javax.imageio.ImageWriteParam;
  44 import javax.imageio.ImageWriter;
  45 import javax.imageio.metadata.IIOMetadata;
  46 import javax.imageio.metadata.IIOMetadataNode;
  47 import javax.imageio.stream.ImageOutputStream;
  48 import org.w3c.dom.Node;
  49 
  50 public class ReadMalformedPngTest {
  51 
  52     public static void main(String[] args) throws IOException {
  53         ByteArrayInputStream bais = new ByteArrayInputStream(createTestPng());
  54 
  55         IIOException expected = null;
  56         try {
  57             ImageIO.read(bais);
  58         } catch (IIOException e) {
  59             expected = e;
  60         } catch (Throwable e) {
  61             throw new RuntimeException("Test failed!", e);
  62         }
  63 
  64         if (expected == null) {
  65             throw new RuntimeException("Test failed.");
  66         }
  67 
  68         System.out.println("Test passed.");
  69     }
  70 
  71     private static byte[] createTestPng() throws IOException {
  72         ByteArrayOutputStream baos = new ByteArrayOutputStream();
  73 
  74         BufferedImage img = createTestImage();
  75 
  76         try {
  77             ImageOutputStream ios = ImageIO.createImageOutputStream(baos);
  78 
  79             ImageWriter w = ImageIO.getImageWritersByFormatName("PNG").next();
  80 
  81             w.setOutput(ios);
  82 
  83             ImageWriteParam p = w.getDefaultWriteParam();
  84 
  85             ImageTypeSpecifier t = ImageTypeSpecifier.createFromRenderedImage(img);
  86 
  87             IIOMetadata m = w.getDefaultImageMetadata(t, p);
  88 
  89             String nativeMetadataFormat = m.getNativeMetadataFormatName();
  90 
  91             Node root = m.getAsTree(nativeMetadataFormat);
  92 
  93             IIOMetadataNode textEntry = new IIOMetadataNode("tEXtEntry");
  94             textEntry.setAttribute("keyword", "comment");
  95             textEntry.setAttribute("value", "This is a test image for JDK-6945174");
  96 
  97             IIOMetadataNode text = new IIOMetadataNode("tEXt");
  98             text.appendChild(textEntry);
  99 
 100             root.appendChild(text);
 101 
 102             m.mergeTree(nativeMetadataFormat, root);
 103 
 104             IIOImage iio_img = new IIOImage(img, null, m);
 105 
 106             w.write(iio_img);
 107 
 108             w.dispose();
 109             ios.flush();
 110             ios.close();
 111         } catch (IOException e) {
 112             throw new RuntimeException("Test failed.", e);
 113         }
 114 
 115         baos.flush();
 116 
 117         byte[] data = baos.toByteArray();
 118 
 119         adjustCommentLength(Integer.MAX_VALUE + 0x1000, data);
 120 
 121         return data;
 122     }
 123 
 124     private static void adjustCommentLength(int v, byte[] data) {
 125         final int pos = getCommentPos(data);
 126         data[pos + 3] = (byte) (v & 0xFF);
 127         v = v >> 8;
 128         data[pos + 2] = (byte) (v & 0xFF);
 129         v = v >> 8;
 130         data[pos + 1] = (byte) (v & 0xFF);
 131         v = v >> 8;
 132         data[pos + 0] = (byte) (v & 0xFF);
 133     }
 134 
 135     private static int getCommentPos(byte[] d) {
 136         int p = 8;
 137         while (p + 8 < d.length) {
 138             if (d[p + 4] == (byte) 0x74 && d[p + 5] == (byte) 0x45 &&
 139                 d[p + 6] == (byte) 0x58 && d[p + 7] == (byte) 0x74)
 140             {
 141                 return p;
 142             }
 143             p++;
 144         }
 145         throw new RuntimeException("Test chunk was not found!");
 146     }
 147 
 148     private static BufferedImage createTestImage() {
 149         final int w = 128;
 150         final int h = 128;
 151 
 152         BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_3BYTE_BGR);
 153         Graphics2D g = img.createGraphics();
 154         g.setPaint(new GradientPaint(0, 0, Color.blue,
 155                 w, h, Color.red));
 156         g.fillRect(0, 0, w, h);
 157         g.dispose();
 158         return img;
 159     }
 160 }