CatalogTest.java
/*
* Copyright (c) 2008, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.thumbsdb;
import com.twelvemonkeys.io.FastByteArrayOutputStream;
import com.twelvemonkeys.io.LittleEndianDataInputStream;
import com.twelvemonkeys.io.LittleEndianDataOutputStream;
import com.twelvemonkeys.io.ole2.CompoundDocument;
import com.twelvemonkeys.io.ole2.Entry;
import javax.imageio.IIOException;
import javax.imageio.ImageIO;
import javax.imageio.stream.ImageInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInput;
import java.io.IOException;
import java.nio.ByteOrder;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
/**
* CatalogTest
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
*/
public class CatalogTest {
private static void writeHeader(final LittleEndianDataOutputStream out, final int thumbCount) throws IOException {
out.writeShort(16); // length? always 16 for real data, matches the size
out.writeShort(7); // reserved2 (not sure what this is, but always 7 in sample files I've seen)
out.writeInt(thumbCount);
out.writeInt(96); // max width
out.writeInt(96); // max height
}
private static void writeItem(final LittleEndianDataOutputStream out, final int itemId, final String name) throws IOException {
// 16 byte fixed part (size + itemId + timestamp) + UTF-16LE name + NUL + 2 byte padding
int size = 16 + (name.length() + 1) * 2 + 2;
out.writeInt(size);
out.writeInt(itemId);
out.writeLong(0L); // last modified
for (int i = 0; i < name.length(); i++) {
out.writeChar(name.charAt(i));
}
out.writeChar(0); // NUL terminator
out.writeShort(0); // padding
}
private static DataInput catalogWith(final int itemId, final String name) throws IOException {
FastByteArrayOutputStream bytes = new FastByteArrayOutputStream(1024);
LittleEndianDataOutputStream out = new LittleEndianDataOutputStream(bytes);
writeHeader(out, 1);
writeItem(out, itemId, name);
out.flush();
return new LittleEndianDataInputStream(bytes.createInputStream());
}
@Test
void testReadValidItem() throws IOException {
Catalog catalog = Catalog.read(catalogWith(1, "3\\folder\\image.jpg"));
assertEquals(1, catalog.getThumbnailCount());
assertEquals("image.jpg", catalog.getItem(0).getName());
}
@Test
void testFilenameLongerThanAllowed() throws IOException {
// Creates a crafted Catalog with a single entry and file name above the limit of 260 chars
StringBuilder name = new StringBuilder();
for (int i = 0; i < 400; i++) {
name.append('a');
}
assertThrows(IIOException.class, () -> Catalog.read(catalogWith(1, name.toString())));
}
@Test
void testItemIdBelowRange() {
// Creates a crafted Catalog with entry less than the minimum 1
assertThrows(IIOException.class, () -> Catalog.read(catalogWith(0, "image.jpg")));
}
@Test
void testItemIdAboveRange() {
// Creates a crafted Catalog with entry above the range
assertThrows(IIOException.class, () -> Catalog.read(catalogWith(9, "image.jpg")));
}
@Test
void testRealInput() throws IOException {
try (ImageInputStream input = ImageIO.createImageInputStream(getClass().getResourceAsStream("/thumbsdb/Thumbs.db"))) {
input.setByteOrder(ByteOrder.LITTLE_ENDIAN);
Entry root = new CompoundDocument(input).getRootEntry();
Entry child = root.getChildEntry("Catalog");
assertNotNull(child);
Catalog catalog = Catalog.read(child.getInputStream());
assertNotNull(catalog);
assertEquals(9, catalog.getThumbnailCount());
assertEquals("{A42CD7B6-E9B9-4D02-B7A6-288B71AD28BA}", catalog.getItem(0).getName());
assertEquals("CoffeeBean.bmp", catalog.getItem(1).getName());
assertEquals("JavaCup.ico", catalog.getItem(2).getName());
assertEquals("office_05.gif", catalog.getItem(3).getName());
assertEquals("sunflower.jpg", catalog.getItem(4).getName());
assertEquals("test.jpg", catalog.getItem(5).getName());
assertEquals("test.png", catalog.getItem(6).getName());
assertEquals("test.tif", catalog.getItem(7).getName());
assertEquals("test.wmf", catalog.getItem(8).getName());
}
}
}