Icon extracter/dumper for Eclipse launcher
diff --git a/bundles/org.eclipse.swt.tools/Icon Exe/org/eclipse/swt/tools/internal/IconExe.java b/bundles/org.eclipse.swt.tools/Icon Exe/org/eclipse/swt/tools/internal/IconExe.java
new file mode 100644
index 0000000..f2692be
--- /dev/null
+++ b/bundles/org.eclipse.swt.tools/Icon Exe/org/eclipse/swt/tools/internal/IconExe.java
@@ -0,0 +1,772 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.tools.internal;
+
+import java.io.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.*;
+
+/**
+ * Customize the icon of a Windows exe
+ *
+ * WARNING! This class is not part of SWT API. It is NOT API. It is an internal
+ * tool that may be changed or removed at anytime.
+ *
+ * Based on MSDN "An In-Depth Look into the Win32 Portable Executable File Format"
+ * http://msdn.microsoft.com/msdnmag/issues/02/03/PE2/default.aspx
+ */
+public class IconExe {
+
+ /**
+ * Retrieve the Desktop icons provided in the Windows executable program.
+ * These icons are typically shown in various places of the Windows desktop.
+ *
+ * Note. The Eclipse 3.1 launcher returns the following 6 images
+ * 1. 32x32, 4 bit (16 colors)
+ * 2. 16x16, 4 bit (16 colors)
+ * 3. 16x16, 8 bit (256 colors)
+ * 4. 32x32, 8 bit (256 colors)
+ * 5. 48x48, 4 bit (16 colors)
+ * 6. 48x48, 8 bit (256 colors)
+ *
+ * @param program the Windows executable e.g c:/eclipse/eclipse.exe
+ */
+ public static ImageData[] loadIcons(String program) throws FileNotFoundException, IOException {
+ RandomAccessFile raf = new RandomAccessFile(program, "r");
+ IconExe iconExe = new IconExe();
+ IconResInfo[] iconInfo = iconExe.getIcons(raf);
+ ImageData[] data = new ImageData[iconInfo.length];
+ for (int i = 0; i < data.length; i++) data[i] = iconInfo[i].data;
+ return data;
+ }
+
+ /**
+ * Replace the Desktop icons provided in the Windows executable program
+ * with icons provided by the user.
+ *
+ * Note 1. Write access to the executable program is required. As a result, that
+ * program must not be currently running or edited elsewhere.
+ *
+ * Note 2. Use loadIcons to determine which set of icons (width, height, depth)
+ * is required to replace the icons in the executable program. A user icon
+ * matching exactly the width/height/depth of an executable icon will be written
+ * to the executable and will replace that executable icon. If an executable icon
+ * does not match a user icon, it is left as is. Verify the return value matches
+ * the number of icons to write. Finally, use loadIcons after this operation
+ * to verify the icons have changed as expected.
+ *
+ * Note 3. The Eclipse 3.1 launcher requires the following 6 images (in any order).
+ * 1. 32x32, 4 bit (16 colors)
+ * 2. 16x16, 4 bit (16 colors)
+ * 3. 16x16, 8 bit (256 colors)
+ * 4. 32x32, 8 bit (256 colors)
+ * 5. 48x48, 4 bit (16 colors)
+ * 6. 48x48, 8 bit (256 colors)
+ *
+ * Note 4. This function modifies the content of the executable program and may cause
+ * its corruption.
+ *
+ * @param program the Windows executable e.g c:/eclipse/eclipse.exe
+ * @return the number of icons written to the program
+ */
+ public static int unloadIcons(String program, ImageData[] icons) throws FileNotFoundException, IOException {
+ RandomAccessFile raf = new RandomAccessFile(program, "rw");
+ IconExe iconExe = new IconExe();
+ IconResInfo[] iconInfo = iconExe.getIcons(raf);
+ int cnt = 0;
+ for (int i = 0; i < iconInfo.length; i++) {
+ for (int j = 0; j < icons.length; j++)
+ if (iconInfo[i].data.width == icons[j].width &&
+ iconInfo[i].data.height == icons[j].height &&
+ iconInfo[i].data.depth == icons[j].depth) {
+ raf.seek(iconInfo[i].offset);
+ unloadIcon(raf, icons[j]);
+ cnt++;
+ }
+ }
+ raf.close();
+ return cnt;
+ }
+
+ /* Implementation */
+
+ static final boolean DEBUG = true;
+ public static class IconResInfo {
+ ImageData data;
+ int offset;
+ int size;
+ IconResInfo next;
+ }
+
+ IconResInfo[] iconInfo = null;
+ int iconCnt;
+
+ IconResInfo[] getIcons(RandomAccessFile raf) throws IOException {
+ iconInfo = new IconResInfo[4];
+ iconCnt = 0;
+ IMAGE_DOS_HEADER imageDosHeader = new IMAGE_DOS_HEADER();
+ read(raf, imageDosHeader);
+ if (imageDosHeader.e_magic != IMAGE_DOS_SIGNATURE) return null;
+ int imageNtHeadersOffset = imageDosHeader.e_lfanew;
+ raf.seek(imageNtHeadersOffset);
+ IMAGE_NT_HEADERS imageNtHeaders = new IMAGE_NT_HEADERS();
+ read(raf, imageNtHeaders);
+ if (imageNtHeaders.Signature != IMAGE_NT_SIGNATURE) return null;
+
+ // DumpResources
+ int resourcesRVA = imageNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
+ if (resourcesRVA == 0) return null;
+ if (DEBUG) System.out.println("* Resources (RVA= "+resourcesRVA+")");
+ IMAGE_SECTION_HEADER imageSectionHeader = new IMAGE_SECTION_HEADER();
+ int firstSectionOffset = imageNtHeadersOffset + IMAGE_NT_HEADERS.FIELD_OFFSET_OptionalHeader + imageNtHeaders.FileHeader.SizeOfOptionalHeader;
+ raf.seek(firstSectionOffset);
+ boolean found = false;
+ for (int i = 0; i < imageNtHeaders.FileHeader.NumberOfSections; i++) {
+ read(raf, imageSectionHeader);
+ if (resourcesRVA >= imageSectionHeader.VirtualAddress && resourcesRVA < imageSectionHeader.VirtualAddress + imageSectionHeader.Misc_VirtualSize) {
+ // could check the imageSectionHeader name is .rsrc
+ found = true;
+ break;
+ }
+ }
+ if (!found) return null;
+ int delta = imageSectionHeader.VirtualAddress - imageSectionHeader.PointerToRawData;
+ int imageResourceDirectoryOffset = resourcesRVA - delta;
+ dumpResourceDirectory(raf, imageResourceDirectoryOffset, imageResourceDirectoryOffset, delta, 0, 0, false);
+ if (iconCnt < iconInfo.length) {
+ IconResInfo[] newArray = new IconResInfo[iconCnt];
+ System.arraycopy(iconInfo, 0, newArray, 0, iconCnt);
+ iconInfo = newArray;
+ }
+ return iconInfo;
+ }
+
+void dumpResourceDirectory(RandomAccessFile raf, int imageResourceDirectoryOffset, int resourceBase, int delta, int type, int level, boolean rt_icon_root) throws IOException {
+ if (DEBUG) System.out.println("** LEVEL "+level);
+
+ IMAGE_RESOURCE_DIRECTORY imageResourceDirectory = new IMAGE_RESOURCE_DIRECTORY();
+ raf.seek(imageResourceDirectoryOffset);
+ read(raf, imageResourceDirectory);
+
+ if (DEBUG) {
+ String sType = ""+type;
+ // level 1 resources are resource types
+ if (level == 1) {
+ System.out.println("___________________________");
+ if (type == RT_ICON) sType = "RT_ICON";
+ if (type == RT_GROUP_ICON) sType = "RT_GROUP_ICON";
+ }
+ System.out.println("Resource Directory ["+sType+"]"+" (Named "+imageResourceDirectory.NumberOfNamedEntries+", ID "+imageResourceDirectory.NumberOfIdEntries+")");
+ }
+ int IRDE_StartOffset = imageResourceDirectoryOffset + IMAGE_RESOURCE_DIRECTORY.SIZEOF;
+ IMAGE_RESOURCE_DIRECTORY_ENTRY[] imageResourceDirectoryEntries = new IMAGE_RESOURCE_DIRECTORY_ENTRY[imageResourceDirectory.NumberOfIdEntries];
+ for (int i = 0; i < imageResourceDirectoryEntries.length; i++) {
+ imageResourceDirectoryEntries[i] = new IMAGE_RESOURCE_DIRECTORY_ENTRY();
+ read(raf, imageResourceDirectoryEntries[i]);
+ }
+ for (int i = 0; i < imageResourceDirectoryEntries.length; i++) {
+ if (imageResourceDirectoryEntries[i].DataIsDirectory) {
+ dumpResourceDirectory(raf, imageResourceDirectoryEntries[i].OffsetToDirectory + resourceBase, resourceBase, delta, imageResourceDirectoryEntries[i].Id, level + 1, rt_icon_root ? true : type == RT_ICON);
+ } else {
+ // Resource found
+ /// pResDirEntry->Name
+ IMAGE_RESOURCE_DIRECTORY_ENTRY irde = imageResourceDirectoryEntries[i];
+ IMAGE_RESOURCE_DATA_ENTRY data = new IMAGE_RESOURCE_DATA_ENTRY();
+ raf.seek(imageResourceDirectoryEntries[i].OffsetToData + resourceBase);
+ read(raf, data);
+ if (DEBUG) System.out.println("Resource Id "+irde.Id+" Data Offset RVA "+data.OffsetToData+", Size "+data.Size);
+ if (rt_icon_root) {
+ if (DEBUG) System.out.println("iconcnt "+iconCnt+" |"+iconInfo.length);
+ iconInfo[iconCnt] = new IconResInfo();
+ iconInfo[iconCnt].data = parseIcon(raf, data.OffsetToData - delta, data.Size);
+ iconInfo[iconCnt].offset = data.OffsetToData - delta;
+ iconInfo[iconCnt].size = data.Size;
+ iconCnt++;
+ if (iconCnt == iconInfo.length) {
+ IconResInfo[] newArray = new IconResInfo[iconInfo.length + 4];
+ System.arraycopy(iconInfo, 0, newArray, 0, iconInfo.length);
+ iconInfo = newArray;
+ }
+ }
+ }
+ }
+}
+
+static ImageData parseIcon(RandomAccessFile raf, int offset, int size) throws IOException {
+ raf.seek(offset);
+ BITMAPINFO bitmapInfo = new BITMAPINFO();
+ read(raf, bitmapInfo);
+ bitmapInfo.bmiHeader.biHeight /= 2;
+ int width = bitmapInfo.bmiHeader.biWidth;
+ int height = bitmapInfo.bmiHeader.biHeight;
+ int depth = bitmapInfo.bmiHeader.biBitCount;
+
+ PaletteData palette = loadPalette(bitmapInfo.bmiHeader, raf);
+ byte[] shapeData = loadData(bitmapInfo.bmiHeader, raf);
+ bitmapInfo.bmiHeader.biBitCount = 1;
+ byte[] maskData = loadData(bitmapInfo.bmiHeader, raf);
+ maskData = convertPad(maskData, width, height, 1, 4, 2);
+ bitInvertData(maskData, 0, maskData.length);
+ return ImageData.internal_new(
+ width,
+ height,
+ depth,
+ palette,
+ 4,
+ shapeData,
+ 2,
+ maskData,
+ null,
+ -1,
+ -1,
+ SWT.IMAGE_ICO,
+ 0,
+ 0,
+ 0,
+ 0);
+}
+
+static byte[] bitInvertData(byte[] data, int startIndex, int endIndex) {
+ // Destructively bit invert data in the given byte array.
+ for (int i = startIndex; i < endIndex; i++) {
+ data[i] = (byte)(255 - data[i - startIndex]);
+ }
+ return data;
+}
+
+static final byte[] convertPad(byte[] data, int width, int height, int depth, int pad, int newPad) {
+ if (pad == newPad) return data;
+ int stride = (width * depth + 7) / 8;
+ int bpl = (stride + (pad - 1)) / pad * pad;
+ int newBpl = (stride + (newPad - 1)) / newPad * newPad;
+ byte[] newData = new byte[height * newBpl];
+ int srcIndex = 0, destIndex = 0;
+ for (int y = 0; y < height; y++) {
+ System.arraycopy(data, srcIndex, newData, destIndex, newBpl);
+ srcIndex += bpl;
+ destIndex += newBpl;
+ }
+ return newData;
+}
+static PaletteData loadPalette(BITMAPINFOHEADER bih, RandomAccessFile raf) throws IOException {
+ int depth = bih.biBitCount;
+ if (depth <= 8) {
+ int numColors = bih.biClrUsed;
+ if (numColors == 0) {
+ numColors = 1 << depth;
+ } else {
+ if (numColors > 256)
+ numColors = 256;
+ }
+ byte[] buf = new byte[numColors * 4];
+ raf.read(buf);
+ return paletteFromBytes(buf, numColors);
+ }
+ if (depth == 16) return new PaletteData(0x7C00, 0x3E0, 0x1F);
+ if (depth == 24) return new PaletteData(0xFF, 0xFF00, 0xFF0000);
+ return new PaletteData(0xFF00, 0xFF0000, 0xFF000000);
+}
+static PaletteData paletteFromBytes(byte[] bytes, int numColors) {
+ int bytesOffset = 0;
+ RGB[] colors = new RGB[numColors];
+ for (int i = 0; i < numColors; i++) {
+ colors[i] = new RGB(bytes[bytesOffset + 2] & 0xFF,
+ bytes[bytesOffset + 1] & 0xFF,
+ bytes[bytesOffset] & 0xFF);
+ bytesOffset += 4;
+ }
+ return new PaletteData(colors);
+}
+static byte[] loadData(BITMAPINFOHEADER bih, RandomAccessFile raf) throws IOException {
+ int stride = (bih.biWidth * bih.biBitCount + 7) / 8;
+ stride = (stride + 3) / 4 * 4; // Round up to 4 byte multiple
+ byte[] data = loadData(bih, raf, stride);
+ flipScanLines(data, stride, bih.biHeight);
+ return data;
+}
+static void flipScanLines(byte[] data, int stride, int height) {
+ int i1 = 0;
+ int i2 = (height - 1) * stride;
+ for (int i = 0; i < height / 2; i++) {
+ for (int index = 0; index < stride; index++) {
+ byte b = data[index + i1];
+ data[index + i1] = data[index + i2];
+ data[index + i2] = b;
+ }
+ i1 += stride;
+ i2 -= stride;
+ }
+}
+static byte[] loadData(BITMAPINFOHEADER bih, RandomAccessFile raf, int stride) throws IOException {
+ int dataSize = bih.biHeight * stride;
+ byte[] data = new byte[dataSize];
+ int cmp = bih.biCompression;
+ if (cmp == 0) { // BMP_NO_COMPRESSION
+ raf.read(data);
+ } else {
+ if (DEBUG) System.out.println("ICO cannot be compressed?");
+ }
+ return data;
+}
+
+static void unloadIcon(RandomAccessFile raf, ImageData icon) throws IOException {
+ int sizeImage = (((icon.width * icon.depth + 31) / 32 * 4) +
+ ((icon.width + 31) / 32 * 4)) * icon.height;
+ write4(raf, BMPHeaderFixedSize);
+ write4(raf, icon.width);
+ write4(raf, icon.height * 2);
+ writeU2(raf, 1);
+ writeU2(raf, icon.depth);
+ write4(raf, 0);
+ write4(raf, sizeImage);
+ write4(raf, 0);
+ write4(raf, 0);
+ write4(raf, icon.palette.colors != null ? icon.palette.colors.length : 0);
+ write4(raf, 0);
+
+ byte[] rgbs = paletteToBytes(icon.palette);
+ raf.write(rgbs);
+ unloadShapeData(raf, icon);
+ unloadMaskData(raf, icon);
+}
+static byte[] paletteToBytes(PaletteData pal) {
+ int n = pal.colors == null ? 0 : (pal.colors.length < 256 ? pal.colors.length : 256);
+ byte[] bytes = new byte[n * 4];
+ int offset = 0;
+ for (int i = 0; i < n; i++) {
+ RGB col = pal.colors[i];
+ bytes[offset] = (byte)col.blue;
+ bytes[offset + 1] = (byte)col.green;
+ bytes[offset + 2] = (byte)col.red;
+ offset += 4;
+ }
+ return bytes;
+}
+static void unloadMaskData(RandomAccessFile raf, ImageData icon) {
+ ImageData mask = icon.getTransparencyMask();
+ int bpl = (icon.width + 7) / 8;
+ int pad = mask.scanlinePad;
+ int srcBpl = (bpl + pad - 1) / pad * pad;
+ int destBpl = (bpl + 3) / 4 * 4;
+ byte[] buf = new byte[destBpl];
+ int offset = (icon.height - 1) * srcBpl;
+ byte[] data = mask.data;
+ try {
+ for (int i = 0; i < icon.height; i++) {
+ System.arraycopy(data, offset, buf, 0, bpl);
+ bitInvertData(buf, 0, bpl);
+ raf.write(buf, 0, destBpl);
+ offset -= srcBpl;
+ }
+ } catch (IOException e) {
+ SWT.error(SWT.ERROR_IO, e);
+ }
+}
+static void unloadShapeData(RandomAccessFile raf, ImageData icon) {
+ int bpl = (icon.width * icon.depth + 7) / 8;
+ int pad = icon.scanlinePad;
+ int srcBpl = (bpl + pad - 1) / pad * pad;
+ int destBpl = (bpl + 3) / 4 * 4;
+ byte[] buf = new byte[destBpl];
+ int offset = (icon.height - 1) * srcBpl;
+ byte[] data = icon.data;
+ try {
+ for (int i = 0; i < icon.height; i++) {
+ System.arraycopy(data, offset, buf, 0, bpl);
+ raf.write(buf, 0, destBpl);
+ offset -= srcBpl;
+ }
+ } catch (IOException e) {
+ SWT.error(SWT.ERROR_IO, e);
+ }
+}
+static boolean readIconGroup(RandomAccessFile raf, int offset, int size) throws IOException {
+ raf.seek(offset);
+ NEWHEADER newHeader = new NEWHEADER();
+ read(raf, newHeader);
+ if (newHeader.ResType != RES_ICON) return false;
+ RESDIR[] resDir = new RESDIR[newHeader.ResCount];
+ for (int i = 0; i < newHeader.ResCount; i++) {
+ resDir[i] = new RESDIR();
+ read(raf, resDir[i]);
+ }
+ return true;
+}
+
+static void copyFile(String src, String dst) throws FileNotFoundException, IOException {
+ File srcFile = new File(src);
+ File dstFile = new File(dst);
+ FileInputStream in = new FileInputStream(srcFile);
+ FileOutputStream out = new FileOutputStream(dstFile);
+ int c;
+ while ((c = in.read()) != -1) out.write(c);
+ in.close();
+ out.close();
+}
+
+/* IO utilities to parse Windows executable */
+static final int IMAGE_DOS_SIGNATURE = 0x5a4d;
+static final int IMAGE_NT_SIGNATURE = 0x00004550;
+static final int IMAGE_DIRECTORY_ENTRY_RESOURCE = 2;
+static final int RES_ICON = 1;
+static final int RT_ICON = 3;
+static final int RT_GROUP_ICON = 14;
+static final int BMPHeaderFixedSize = 40;
+
+public static class IMAGE_DOS_HEADER {
+ int e_magic; // WORD
+ int e_cblp; // WORD
+ int e_cp; // WORD
+ int e_crlc; // WORD
+ int e_cparhdr; // WORD
+ int e_minalloc; // WORD
+ int e_maxalloc; // WORD
+ int e_ss; // WORD
+ int e_sp; // WORD
+ int e_csum; // WORD
+ int e_ip; // WORD
+ int e_cs; // WORD
+ int e_lfarlc; // WORD
+ int e_ovno; // WORD
+ int[] e_res = new int[4]; // WORD[4]
+ int e_oemid; // WORD
+ int e_oeminfo; // WORD
+ int[] e_res2 = new int[10]; // WORD[10]
+ int e_lfanew; // LONG
+}
+
+public static class IMAGE_FILE_HEADER {
+ int Machine; // WORD
+ int NumberOfSections; // WORD
+ int TimeDateStamp; // DWORD
+ int PointerToSymbolTable; // DWORD
+ int NumberOfSymbols; // DWORD
+ int SizeOfOptionalHeader; // WORD
+ int Characteristics; // WORD
+};
+
+public static class IMAGE_DATA_DIRECTORY {
+ int VirtualAddress; // DWORD
+ int Size; // DWORD
+}
+
+public static class IMAGE_OPTIONAL_HEADER {
+ int Magic; // WORD
+ int MajorLinkerVersion; // BYTE
+ int MinorLinkerVersion; // BYTE
+ int SizeOfCode; // DWORD
+ int SizeOfInitializedData; // DWORD
+ int SizeOfUninitializedData; // DWORD
+ int AddressOfEntryPoint; // DWORD
+ int BaseOfCode; // DWORD
+ int BaseOfData; // DWORD
+ int ImageBase; // DWORD
+ int SectionAlignment; // DWORD
+ int FileAlignment; // DWORD
+ int MajorOperatingSystemVersion; // WORD
+ int MinorOperatingSystemVersion; // WORD
+ int MajorImageVersion; // WORD
+ int MinorImageVersion; // WORD
+ int MajorSubsystemVersion; // WORD
+ int MinorSubsystemVersion; // WORD
+ int Win32VersionValue; // DWORD
+ int SizeOfImage; // DWORD
+ int SizeOfHeaders; // DWORD
+ int CheckSum; // DWORD
+ int Subsystem; // WORD
+ int DllCharacteristics; // WORD
+ int SizeOfStackReserve; // DWORD
+ int SizeOfStackCommit; // DWORD
+ int SizeOfHeapReserve; // DWORD
+ int SizeOfHeapCommit; // DWORD
+ int LoaderFlags; // DWORD
+ int NumberOfRvaAndSizes; // DWORD
+ IMAGE_DATA_DIRECTORY[] DataDirectory = new IMAGE_DATA_DIRECTORY[16];
+}
+public static class IMAGE_NT_HEADERS {
+ int Signature; // DWORD
+ IMAGE_FILE_HEADER FileHeader = new IMAGE_FILE_HEADER();
+ IMAGE_OPTIONAL_HEADER OptionalHeader = new IMAGE_OPTIONAL_HEADER();
+ final static int FIELD_OFFSET_OptionalHeader = 24;
+}
+
+public static class IMAGE_SECTION_HEADER {
+ int[] Name = new int[8]; // BYTE[8]
+ int Misc_VirtualSize; // DWORD (union Misc { DWORD PhysicalAddress; DWORD VirtualSize }
+ int VirtualAddress; // DWORD
+ int SizeOfRawData; // DWORD
+ int PointerToRawData; // DWORD
+ int PointerToRelocations; // DWORD
+ int PointerToLinenumbers; // DWORD
+ int NumberOfRelocations; // WORD
+ int NumberOfLinenumbers; // WORD
+ int Characteristics; // DWORD
+};
+
+public static class IMAGE_RESOURCE_DIRECTORY {
+ int Characteristics; // DWORD
+ int TimeDateStamp; // DWORD
+ int MajorVersion; // WORD
+ int MinorVersion; // WORD
+ int NumberOfNamedEntries; // WORD - used
+ int NumberOfIdEntries; // WORD - used
+ final static int SIZEOF = 16;
+}
+
+public static class IMAGE_RESOURCE_DIRECTORY_ENTRY {
+ // union
+ int NameOffset; // DWORD 31 bits
+ boolean NameIsString; // DWORD 1 bit
+ int Name; // DWORD
+ int Id; // WORD
+ // union
+ int OffsetToData; // DWORD
+ int OffsetToDirectory; // DWORD 31 bits
+ boolean DataIsDirectory; // DWORD 1 bit
+}
+
+public static class IMAGE_RESOURCE_DATA_ENTRY {
+ int OffsetToData; // DWORD
+ int Size; // DWORD
+ int CodePage; // DWORD
+ int Reserved; // DWORD
+}
+
+public static class NEWHEADER {
+ int Reserved; // WORD
+ int ResType; // WORD
+ int ResCount; // WORD
+}
+
+public static class ICONRESDIR {
+ int Width; // BYTE
+ int Height; // BYTE
+ int ColorCount; // BYTE
+ int reserved; // BYTE
+}
+
+public static class CURSORDIR {
+ int Width; // WORD
+ int Height; // WORD
+}
+
+public static class RESDIR {
+ // union
+ ICONRESDIR Icon = new ICONRESDIR();
+ CURSORDIR Cursor = new CURSORDIR();
+ int Planes; // WORD
+ int BitCount; // WORD
+ int BytesInRes; // DWORD
+ int IconCursorId; // WORD
+}
+
+public static class BITMAPINFOHEADER {
+ int biSize; // DWORD
+ int biWidth; // LONG
+ int biHeight; // LONG
+ int biPlanes; // WORD
+ int biBitCount; // WORD
+ int biCompression; // DWORD
+ int biSizeImage; // DWORD
+ int biXPelsPerMeter; // LONG
+ int biYPelsPerMeter; // LONG
+ int biClrUsed; // DWORD
+ int biClrImportant; // DWORD
+}
+
+public static class RGBQUAD {
+ int rgBlue; // BYTE
+ int rgbGreen; // BYTE
+ int rgbRed; // BYTE
+ int rgbReserved; // BYTE
+}
+public static class BITMAPINFO {
+ BITMAPINFOHEADER bmiHeader = new BITMAPINFOHEADER();
+ RGBQUAD[] bmiColors = null;
+}
+static void read(RandomAccessFile raf, BITMAPINFOHEADER bih) throws IOException {
+ bih.biSize = read4(raf);
+ bih.biWidth = read4(raf);
+ bih.biHeight = read4(raf);
+ bih.biPlanes = readU2(raf);
+ bih.biBitCount = readU2(raf);
+ bih.biCompression = read4(raf);
+ bih.biSizeImage = read4(raf);
+ bih.biXPelsPerMeter = read4(raf);
+ bih.biYPelsPerMeter = read4(raf);
+ bih.biClrUsed = read4(raf);
+ bih.biClrImportant = read4(raf);
+}
+static void read(RandomAccessFile raf, BITMAPINFO bi) throws IOException {
+ read(raf, bi.bmiHeader);
+ System.out.println("Reading BITMAPINFO");
+}
+/* Little Endian helpers */
+static int readU2(RandomAccessFile raf) throws IOException {
+ int b0 = raf.readByte() & 0xFF;
+ int b1 = raf.readByte() & 0xFF;
+ return (b1 << 8 | b0);
+}
+static int read4(RandomAccessFile raf) throws IOException {
+ int b0 = raf.readByte() & 0xFF;;
+ int b1 = raf.readByte() & 0xFF;;
+ int b2 = raf.readByte() & 0xFF;;
+ int b3 = raf.readByte() & 0xFF;;
+ return b3 << 24 | b2 << 16 | b1 << 8 | b0;
+}
+static void write4(RandomAccessFile raf, int value) throws IOException {
+ raf.write(value & 0xFF);
+ raf.write((value >> 8) & 0xFF);
+ raf.write((value >> 16) & 0xFF);
+ raf.write((value >> 24) & 0xFF);
+}
+static void writeU2(RandomAccessFile raf, int value) throws IOException {
+ raf.write(value & 0xFF);
+ raf.write((value >> 8) & 0xFF);
+}
+static void read(RandomAccessFile raf, IMAGE_DOS_HEADER idh) throws IOException {
+ idh.e_magic = readU2(raf);
+ idh.e_cblp = readU2(raf);
+ idh.e_cp = readU2(raf);
+ idh.e_crlc = readU2(raf);
+ idh.e_cparhdr = readU2(raf);
+ idh.e_minalloc = readU2(raf);
+ idh.e_maxalloc = readU2(raf);
+ idh.e_ss = readU2(raf);
+ idh.e_sp = readU2(raf);
+ idh.e_csum = readU2(raf);
+ idh.e_ip = readU2(raf);
+ idh.e_cs = readU2(raf);
+ idh.e_lfarlc = readU2(raf);
+ idh.e_ovno = readU2(raf);
+ for (int i = 0; i < idh.e_res.length; i++) idh.e_res[i] = readU2(raf);
+ idh.e_oemid = readU2(raf);
+ idh.e_oeminfo = readU2(raf);
+ for (int i = 0; i < idh.e_res2.length; i++) idh.e_res2[i] = readU2(raf);
+ idh.e_lfanew = read4(raf);
+}
+static void read(RandomAccessFile raf, IMAGE_FILE_HEADER ifh) throws IOException {
+ ifh.Machine = readU2(raf);
+ ifh.NumberOfSections = readU2(raf);
+ ifh.TimeDateStamp = read4(raf);
+ ifh.PointerToSymbolTable = read4(raf);
+ ifh.NumberOfSymbols = read4(raf);
+ ifh.SizeOfOptionalHeader = readU2(raf);
+ ifh.Characteristics = readU2(raf);
+}
+static void read(RandomAccessFile raf, IMAGE_DATA_DIRECTORY idd) throws IOException {
+ idd.VirtualAddress = read4(raf);
+ idd.Size = read4(raf);
+}
+static void read(RandomAccessFile raf, IMAGE_OPTIONAL_HEADER ioh) throws IOException {
+ ioh.Magic = readU2(raf);
+ ioh.MajorLinkerVersion = raf.read();
+ ioh.MinorLinkerVersion = raf.read();
+ ioh.SizeOfCode = read4(raf);
+ ioh.SizeOfInitializedData = read4(raf);
+ ioh.SizeOfUninitializedData = read4(raf);
+ ioh.AddressOfEntryPoint = read4(raf);
+ ioh.BaseOfCode = read4(raf);
+ ioh.BaseOfData = read4(raf);
+ ioh.ImageBase = read4(raf);
+ ioh.SectionAlignment = read4(raf);
+ ioh.FileAlignment = read4(raf);
+ ioh.MajorOperatingSystemVersion = readU2(raf);
+ ioh.MinorOperatingSystemVersion = readU2(raf);
+ ioh.MajorImageVersion = readU2(raf);
+ ioh.MinorImageVersion = readU2(raf);
+ ioh.MajorSubsystemVersion = readU2(raf);
+ ioh.MinorSubsystemVersion = readU2(raf);
+ ioh.Win32VersionValue = read4(raf);
+ ioh.SizeOfImage = read4(raf);
+ ioh.SizeOfHeaders = read4(raf);
+ ioh.CheckSum = read4(raf);
+ ioh.Subsystem = readU2(raf);
+ ioh.DllCharacteristics = readU2(raf);
+ ioh.SizeOfStackReserve = read4(raf);
+ ioh.SizeOfStackCommit = read4(raf);
+ ioh.SizeOfHeapReserve = read4(raf);
+ ioh.SizeOfHeapCommit = read4(raf);
+ ioh.LoaderFlags = read4(raf);
+ ioh.NumberOfRvaAndSizes = read4(raf);
+ for (int i = 0 ; i < ioh.DataDirectory.length; i++) {
+ ioh.DataDirectory[i] = new IMAGE_DATA_DIRECTORY();
+ read(raf, ioh.DataDirectory[i]);
+ }
+}
+static void read(RandomAccessFile raf, IMAGE_NT_HEADERS inh) throws IOException {
+ inh.Signature = read4(raf);
+ read(raf, inh.FileHeader);
+ read(raf, inh.OptionalHeader);
+}
+static void read(RandomAccessFile raf, IMAGE_SECTION_HEADER ish) throws IOException {
+ for (int i = 0 ; i < ish.Name.length; i++) ish.Name[i] = raf.read();
+ ish.Misc_VirtualSize = read4(raf);
+ ish.VirtualAddress = read4(raf);
+ ish.SizeOfRawData = read4(raf);
+ ish.PointerToRawData = read4(raf);
+ ish.PointerToRelocations = read4(raf);
+ ish.PointerToLinenumbers = read4(raf);
+ ish.NumberOfRelocations = readU2(raf);
+ ish.NumberOfLinenumbers = readU2(raf);
+ ish.Characteristics = read4(raf);
+}
+static void read(RandomAccessFile raf, IMAGE_RESOURCE_DIRECTORY ird) throws IOException {
+ ird.Characteristics = read4(raf);
+ ird.TimeDateStamp = read4(raf);
+ ird.MajorVersion = readU2(raf);
+ ird.MinorVersion = readU2(raf);
+ ird.NumberOfNamedEntries = readU2(raf);
+ ird.NumberOfIdEntries = readU2(raf);
+};
+static void read(RandomAccessFile raf, IMAGE_RESOURCE_DIRECTORY_ENTRY irde) throws IOException {
+ irde.Name = read4(raf);
+ irde.OffsetToData = read4(raf);
+ // construct other union members
+ irde.NameOffset = irde.Name & ~ (1 << 31);
+ irde.NameIsString = (irde.Name & (1 << 31)) != 0;
+ irde.Id = irde.Name & 0xFFFF;
+ irde.OffsetToDirectory = irde.OffsetToData & ~ (1 << 31);
+ irde.DataIsDirectory = (irde.OffsetToData & (1 << 31)) != 0;
+}
+static void read(RandomAccessFile raf, IMAGE_RESOURCE_DATA_ENTRY irde) throws IOException {
+ irde.OffsetToData = read4(raf);
+ irde.Size = read4(raf);
+ irde.CodePage = read4(raf);
+ irde.Reserved = read4(raf);
+}
+static void read(RandomAccessFile raf, NEWHEADER nh) throws IOException {
+ nh.Reserved = readU2(raf);
+ nh.ResType = readU2(raf);
+ nh.ResCount = readU2(raf);
+}
+static void read(RandomAccessFile raf, ICONRESDIR i) throws IOException {
+ i.Width = raf.read();
+ i.Height = raf.read();
+ i.ColorCount = raf.read();
+ i.reserved = raf.read();
+}
+static void read(RandomAccessFile raf, CURSORDIR c) throws IOException {
+ c.Width = readU2(raf);
+ c.Height = readU2(raf);
+}
+static void read(RandomAccessFile raf, RESDIR rs) throws IOException {
+ long start = raf.getFilePointer();
+ read(raf, rs.Icon);
+ raf.seek(start);
+ read(raf, rs.Cursor);
+ rs.Planes = readU2(raf);
+ rs.BitCount = readU2(raf);
+ rs.BytesInRes = read4(raf);
+ rs.IconCursorId = readU2(raf);
+}
+
+}