1/*
2 * Copyright (c) 2016, 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 8145014
27 * @summary Verify reader correctly fails for zero-entry IFDs and EOFs
28 *          encountered in locateImage().
29 */
30
31import java.awt.Image;
32import java.awt.image.*;
33import java.io.*;
34import java.util.Iterator;
35import javax.imageio.*;
36import javax.imageio.stream.*;
37
38public class BogusSecondImageTest {
39    public static void main(String[] args) throws Throwable {
40        int failures = 0;
41
42        try {
43            testZeroEntryIFD();
44        } catch (Exception e) {
45            System.out.printf("Failed testZeroEntryIFD: %s%n", e);
46            failures++;
47        }
48
49        try {
50            testOutOfStreamIFD();
51        } catch (Exception e) {
52            System.out.printf("Failed testOutOfStreamIFD: %s%n", e);
53            failures++;
54        }
55
56        if (failures == 0) {
57            System.out.println("Test succeeded");
58        } else {
59            throw new RuntimeException
60                ("Test failed with " + failures + " errors");
61        }
62    }
63
64    private static void testZeroEntryIFD() throws Exception {
65        // Create an image.
66        File f = createImageFile();
67
68        ImageOutputStream s = new FileImageOutputStream(f);
69        long length = s.length();
70
71        // Skip the endianness and magic number
72        s.skipBytes(4);
73
74        // Read and seek to offset of 0th IFD
75        long ifd0 = s.readUnsignedInt();
76        s.seek(ifd0);
77
78        // Read number of 0th IFD entries and skip over them
79        int entries0 = s.readUnsignedShort();
80        s.skipBytes(12*entries0);
81
82        // Write the offset of the 1st IFD as the current file length
83        s.write((int)length);
84
85        // Seek to the 1st IFD and write a zero entry count to it
86        s.seek(length);
87        s.writeShort(0);
88        s.close();
89
90        try {
91            Load(f);
92        } catch (Exception e) {
93            throw e;
94        } finally {
95            f.delete();
96        }
97    }
98
99    private static void testOutOfStreamIFD() throws Exception {
100        // Create an image.
101        File f = createImageFile();
102        ImageOutputStream s = new FileImageOutputStream(f);
103        long length = s.length();
104
105        // Skip the endianness and magic number
106        s.skipBytes(4);
107
108        // Read and seek to offset of 0th IFD
109        long ifd0 = s.readUnsignedInt();
110        s.seek(ifd0);
111
112        // Read number of 0th IFD entries and skip over them
113        int entries0 = s.readUnsignedShort();
114        s.skipBytes(12*entries0);
115
116        // Write the offset of the 1st IFD as the current file length + 7
117        s.write((int)length + 7);
118        s.close();
119
120        try {
121            Load(f);
122        } catch (Exception e) {
123            throw e;
124        } finally {
125            f.delete();
126        }
127    }
128
129    private static File createImageFile() throws Exception {
130        BufferedImage im =
131        new BufferedImage(100, 100, BufferedImage.TYPE_BYTE_GRAY);
132        File f = File.createTempFile("BogusSecondImage", "tif", new File("."));
133        f.deleteOnExit();
134        if (!ImageIO.write(im, "TIFF", f)) {
135            throw new RuntimeException("Failed to write " + f);
136        }
137        return f;
138    }
139
140    private final static boolean printTrace = false;
141
142    public static void Load(File file) {
143        if (!file.exists()) {
144            throw new IllegalArgumentException(file + " does not exist");
145        } else if (!file.isFile()) {
146            throw new IllegalArgumentException(file + " is not a regular file");
147        } else if (!file.canRead()) {
148            throw new IllegalArgumentException(file + " cannot be read");
149        }
150
151        ImageInputStream input = null;
152        try {
153            input = ImageIO.createImageInputStream(file);
154        } catch (Throwable e) {
155            System.err.println("NOK: createImageInputStream()\t" + e.getMessage());
156            if (printTrace) { e.printStackTrace(); }
157            return;
158        }
159
160        Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName("TIFF");
161        if (!readers.hasNext()) { throw new RuntimeException("No readers available for TIFF"); }
162        ImageReader reader = readers.next();
163        reader.setInput(input);
164
165        Image images[] = null;
166        int numImages = 0;
167
168        int failures = 0;
169        try {
170            numImages = reader.getNumImages(true);
171            images = new Image[numImages];
172        } catch (Throwable e) {
173            failures++;
174            System.err.println("NOK: getNumImages()\t" + e.getMessage());
175            if (printTrace) { e.printStackTrace(); }
176        }
177        System.out.printf("numImages %d%n", numImages);
178
179        for (int i = 0; i < numImages; i++) {
180            System.out.printf("reading image %d%n", i);
181            try {
182                images[i] = reader.read(i);
183            } catch (Throwable e) {
184                failures++;
185                System.err.println("NOK: read()\t" + e.getMessage());
186                if (printTrace) { e.printStackTrace(); }
187            }
188        }
189
190        if (failures == 0) {
191            System.err.println("OK");
192        } else {
193            throw new RuntimeException("NOK");
194        }
195    }
196}
197