0

I'm trying to load an ICO file but I seem to get weird values in the image data size and image data offset value causing an ArrayOutOfBoundsException. Any help is appreciated. I tried Little/Big endian but no success. I found the info for the ICO structure here.

Code:

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Arrays;

public class IcoFileReader {

    public static void main(String[] args) {
        URL url = null;
        try {
            url = new URL("https://www.google.be/favicon.ico");
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }

        if(url == null) {
            System.err.println("Url is null");
            System.exit(-1);
        }

        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

        try {
            final byte[] chunk = new byte[4096];
            final InputStream stream = url.openStream();
            int bytesRead;

            while ((bytesRead = stream.read(chunk)) > 0) {
                outputStream.write(chunk, 0, bytesRead);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }

        final byte[] icoBytes = outputStream.toByteArray();
        System.out.println("Ico bytes: " + Arrays.toString(icoBytes));

        System.out.println("-- HEADER --");
        System.out.println("Reserved: " + Arrays.toString(Arrays.copyOfRange(icoBytes, 0, 2)));
        System.out.println("Image type: " + Arrays.toString(Arrays.copyOfRange(icoBytes, 2, 4)));
        System.out.println("Num images: " + Arrays.toString(Arrays.copyOfRange(icoBytes, 4, 6)));
        System.out.println("");
        System.out.println("-- BODY --");
        System.out.println("Width: " + icoBytes[6]);
        System.out.println("Height: " + icoBytes[7]);
        System.out.println("Color Palette: " + icoBytes[8]);
        System.out.println("Reserved: " + icoBytes[9]);
        System.out.println("Color planes: " + Arrays.toString(Arrays.copyOfRange(icoBytes, 10, 11)));
        System.out.println("Bits per pixel: " + Arrays.toString(Arrays.copyOfRange(icoBytes, 12, 13)));
        System.out.println("Img data size: " + Arrays.toString(Arrays.copyOfRange(icoBytes, 13, 17)) + " - " + ByteBuffer.wrap(Arrays.copyOfRange(icoBytes, 13, 17)).order(ByteOrder.LITTLE_ENDIAN).getInt());
        System.out.println("Offset beginning data: " + Arrays.toString(Arrays.copyOfRange(icoBytes, 17, 21)) + " - " + ByteBuffer.wrap(Arrays.copyOfRange(icoBytes, 17, 21)).order(ByteOrder.LITTLE_ENDIAN).getInt());

        final int imgSize = ByteBuffer.wrap(Arrays.copyOfRange(icoBytes, 13, 17)).order(ByteOrder.LITTLE_ENDIAN).getInt();
        final int offset = ByteBuffer.wrap(Arrays.copyOfRange(icoBytes, 17, 21)).order(ByteOrder.LITTLE_ENDIAN).getInt();
        System.out.println("Bytes length: " + icoBytes.length);
        System.out.println("Image data: " + Arrays.toString(Arrays.copyOfRange(icoBytes, offset, offset + imgSize)));
       /* for(int i = 0; i < icoBytes[4]; i ++) {
            final int start = (i * offset);
            System.out.println("Image data: " + Arrays.toString(Arrays.copyOfRange(icoBytes, start, start + imgSize)));
        }*/
    }
}

And the output:

-- HEADER --

Reserved: [0, 0]

Image type: [1, 0]

Num images: [2, 0]

-- BODY --

Width: 16

Height: 16

Color Palette: 0

Reserved: 0

Color planes: 1

Bits per pixel: [32]

Img data size: [0, 104, 4, 0] - 288768

Offset beginning data: [0, 38, 0, 0] - 9728

Bytes length: 5430

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException

MicroHat11
  • 227
  • 3
  • 12

1 Answers1

0

You got tripped up.

System.out.println("Color planes: " + Arrays.toString(Arrays.copyOfRange(icoBytes, 10, 12)));
System.out.println("Bits per pixel: " + Arrays.toString(Arrays.copyOfRange(icoBytes, 12, 14)));
System.out.println("Img data size: " + Arrays.toString(Arrays.copyOfRange(icoBytes, 14, 18)) + " - " + ByteBuffer.wrap(Arrays.copyOfRange(icoBytes, 14, 18)).order(ByteOrder.LITTLE_ENDIAN).getInt());
System.out.println("Offset beginning data: " + Arrays.toString(Arrays.copyOfRange(icoBytes, 18, 22)) + " - " + ByteBuffer.wrap(Arrays.copyOfRange(icoBytes, 18, 22)).order(ByteOrder.LITTLE_ENDIAN).getInt());

final int imgSize = ByteBuffer.wrap(Arrays.copyOfRange(icoBytes, 14, 18)).order(ByteOrder.LITTLE_ENDIAN).getInt();
final int offset = ByteBuffer.wrap(Arrays.copyOfRange(icoBytes, 18, 22)).order(ByteOrder.LITTLE_ENDIAN).getInt();

(Using a ByteBuffer would have allowed sequential reading without explicit index; and only once setting the byte order.)

Joop Eggen
  • 107,315
  • 7
  • 83
  • 138