KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > swt > tools > internal > IconExe


1 /*******************************************************************************
2  * Copyright (c) 2000, 2006 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.swt.tools.internal;
12
13 import java.io.*;
14 import java.util.*;
15
16 /**
17  * Customize the icon of a Windows exe
18  *
19  * WARNING! This class is not part of SWT API. It is NOT API. It is an internal
20  * tool that may be changed or removed at anytime.
21  *
22  * Based on MSDN "An In-Depth Look into the Win32 Portable Executable File Format"
23  */

24 public class IconExe {
25     
26      /**
27      * Replace the Desktop icons provided in the Windows executable program
28      * with matching icons provided by the user.
29      *
30      * Takes 2 arguments
31      * argument 0: the Windows executable e.g c:/eclipse/eclipse.exe
32      * argument 1: The .ico file to write to the given executable e.g. c:/myApp.ico
33      *
34      * Note 1. Write access to the executable program is required. As a result, that
35      * program must not be currently running or edited elsewhere.
36      *
37      * Note 2. The Eclipse 3.1 launcher requires a .ico file with the following 6 images
38      * 1. 32x32, 4 bit (Windows 16 colors palette)
39      * 2. 16x16, 4 bit (Windows 16 colors palette)
40      * 3. 16x16, 8 bit (256 colors)
41      * 4. 32x32, 8 bit (256 colors)
42      * 5. 48x48, 4 bit (Windows 16 colors palette)
43      * 6. 48x48, 8 bit (256 colors)
44      * A user icon matching exactly the width/height/depth of an executable icon will be written
45      * to the executable and will replace that executable icon. If an executable icon
46      * does not match a user icon, it is silently left as is.
47      *
48      * Note 3. This function modifies the content of the executable program and may cause
49      * its corruption.
50      */

51     public static void main(String JavaDoc[] args) throws Exception JavaDoc {
52         if (args.length < 2) {
53             System.err.println("Usage: IconExe <windows executable> <ico file>");
54             return;
55         }
56         ImageLoader loader = new ImageLoader();
57
58         List images = new ArrayList();
59         for (int i = 1; i < args.length; i++) {
60             try {
61                 //An ICO should contain 7 images, a BMP will contain 1
62
ImageData[] current = loader.load(args[i]);
63                 for (int j = 0; j < current.length; j++) {
64                     images.add(current[j]);
65                 }
66             } catch (RuntimeException JavaDoc e) {
67                 //ignore so that we process the other images
68
}
69         }
70         ImageData[] data = new ImageData[images.size()];
71         data = (ImageData[]) images.toArray(data);
72         
73         int nMissing = unloadIcons(args[0], data);
74         if (nMissing != 0)
75             System.err.println("Error - " + nMissing + " icon(s) not replaced in " + args[0] + " using " + args[1]);
76     }
77     
78     /* Implementation */
79
80     /**
81      * Retrieve the Desktop icons provided in the Windows executable program.
82      * These icons are typically shown in various places of the Windows desktop.
83      *
84      * Note. The Eclipse 3.1 launcher returns the following 6 images
85      * 1. 32x32, 4 bit (Windows 16 colors palette)
86      * 2. 16x16, 4 bit (Windows 16 colors palette)
87      * 3. 16x16, 8 bit (256 colors)
88      * 4. 32x32, 8 bit (256 colors)
89      * 5. 48x48, 4 bit (Windows 16 colors palette)
90      * 6. 48x48, 8 bit (256 colors)
91      *
92      * @param program the Windows executable e.g c:/eclipse/eclipse.exe
93      */

94     static ImageData[] loadIcons(String JavaDoc program) throws FileNotFoundException, IOException {
95         RandomAccessFile raf = new RandomAccessFile(program, "r");
96         IconExe iconExe = new IconExe();
97         IconResInfo[] iconInfo = iconExe.getIcons(raf);
98         ImageData[] data = new ImageData[iconInfo.length];
99         for (int i = 0; i < data.length; i++) data[i] = iconInfo[i].data;
100         raf.close();
101         return data;
102     }
103     
104     /**
105      * Replace the Desktop icons provided in the Windows executable program
106      * with icons provided by the user.
107      *
108      * Note 1. Write access to the executable program is required. As a result, that
109      * program must not be currently running or edited elsewhere.
110      *
111      * Note 2. Use loadIcons to determine which set of icons (width, height, depth)
112      * is required to replace the icons in the executable program. A user icon
113      * matching exactly the width/height/depth of an executable icon will be written
114      * to the executable and will replace that executable icon. If an executable icon
115      * does not match a user icon, it is left as is. Verify the return value matches
116      * the number of icons to write. Finally, use loadIcons after this operation
117      * to verify the icons have changed as expected.
118      *
119      * Note 3. The Eclipse 3.1 launcher requires the following 6 images (in any order).
120      * 1. 32x32, 4 bit (Windows 16 colors palette)
121      * 2. 16x16, 4 bit (Windows 16 colors palette)
122      * 3. 16x16, 8 bit (256 colors)
123      * 4. 32x32, 8 bit (256 colors)
124      * 5. 48x48, 4 bit (Windows 16 colors palette)
125      * 6. 48x48, 8 bit (256 colors)
126      *
127      * Note 4. This function modifies the content of the executable program and may cause
128      * its corruption.
129      *
130      * @param program the Windows executable e.g c:/eclipse/eclipse.exe
131      * @param icons to write to the given executable
132      * @return the number of icons from the original program that were not successfully replaced (0 if success)
133      */

134     static int unloadIcons(String JavaDoc program, ImageData[] icons) throws FileNotFoundException, IOException {
135         RandomAccessFile raf = new RandomAccessFile(program, "rw");
136         IconExe iconExe = new IconExe();
137         IconResInfo[] iconInfo = iconExe.getIcons(raf);
138         int cnt = 0;
139         for (int i = 0; i < iconInfo.length; i++) {
140             for (int j = 0; j < icons.length; j++) {
141                 if (icons[j] == null)
142                     continue;
143                 if (iconInfo[i].data.width == icons[j].width && iconInfo[i].data.height == icons[j].height && iconInfo[i].data.depth == icons[j].depth) {
144                     raf.seek(iconInfo[i].offset);
145                     unloadIcon(raf, icons[j]);
146                     cnt++;
147                     break;
148                 }
149             }
150         }
151         raf.close();
152         return iconInfo.length - cnt;
153     }
154     
155     public static final String JavaDoc VERSION = "20050124";
156     
157     static final boolean DEBUG = false;
158     public static class IconResInfo {
159         ImageData data;
160         int offset;
161         int size;
162     }
163     
164     IconResInfo[] iconInfo = null;
165     int iconCnt;
166     
167     IconResInfo[] getIcons(RandomAccessFile raf) throws IOException {
168         iconInfo = new IconResInfo[4];
169         iconCnt = 0;
170         IMAGE_DOS_HEADER imageDosHeader = new IMAGE_DOS_HEADER();
171         read(raf, imageDosHeader);
172         if (imageDosHeader.e_magic != IMAGE_DOS_SIGNATURE) return null;
173         int imageNtHeadersOffset = imageDosHeader.e_lfanew;
174         raf.seek(imageNtHeadersOffset);
175         IMAGE_NT_HEADERS imageNtHeaders = new IMAGE_NT_HEADERS();
176         read(raf, imageNtHeaders);
177         if (imageNtHeaders.Signature != IMAGE_NT_SIGNATURE) return null;
178         
179         // DumpResources
180
int resourcesRVA = imageNtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
181         if (resourcesRVA == 0) return null;
182         if (DEBUG) System.out.println("* Resources (RVA= "+resourcesRVA+")");
183         IMAGE_SECTION_HEADER imageSectionHeader = new IMAGE_SECTION_HEADER();
184         int firstSectionOffset = imageNtHeadersOffset + IMAGE_NT_HEADERS.FIELD_OFFSET_OptionalHeader + imageNtHeaders.FileHeader.SizeOfOptionalHeader;
185         raf.seek(firstSectionOffset);
186         boolean found = false;
187         for (int i = 0; i < imageNtHeaders.FileHeader.NumberOfSections; i++) {
188             read(raf, imageSectionHeader);
189             if (resourcesRVA >= imageSectionHeader.VirtualAddress && resourcesRVA < imageSectionHeader.VirtualAddress + imageSectionHeader.Misc_VirtualSize) {
190                 // could check the imageSectionHeader name is .rsrc
191
found = true;
192                 break;
193             }
194         }
195         if (!found) return null;
196         int delta = imageSectionHeader.VirtualAddress - imageSectionHeader.PointerToRawData;
197         int imageResourceDirectoryOffset = resourcesRVA - delta;
198         dumpResourceDirectory(raf, imageResourceDirectoryOffset, imageResourceDirectoryOffset, delta, 0, 0, false);
199         if (iconCnt < iconInfo.length) {
200             IconResInfo[] newArray = new IconResInfo[iconCnt];
201             System.arraycopy(iconInfo, 0, newArray, 0, iconCnt);
202             iconInfo = newArray;
203         }
204         return iconInfo;
205     }
206
207 void dumpResourceDirectory(RandomAccessFile raf, int imageResourceDirectoryOffset, int resourceBase, int delta, int type, int level, boolean rt_icon_root) throws IOException {
208     if (DEBUG) System.out.println("** LEVEL "+level);
209
210     IMAGE_RESOURCE_DIRECTORY imageResourceDirectory = new IMAGE_RESOURCE_DIRECTORY();
211     raf.seek(imageResourceDirectoryOffset);
212     read(raf, imageResourceDirectory);
213
214     if (DEBUG) {
215         String JavaDoc sType = ""+type;
216         // level 1 resources are resource types
217
if (level == 1) {
218             System.out.println("___________________________");
219             if (type == RT_ICON) sType = "RT_ICON";
220             if (type == RT_GROUP_ICON) sType = "RT_GROUP_ICON";
221         }
222         System.out.println("Resource Directory ["+sType+"]"+" (Named "+imageResourceDirectory.NumberOfNamedEntries+", ID "+imageResourceDirectory.NumberOfIdEntries+")");
223     }
224     int IRDE_StartOffset = imageResourceDirectoryOffset + IMAGE_RESOURCE_DIRECTORY.SIZEOF;
225     IMAGE_RESOURCE_DIRECTORY_ENTRY[] imageResourceDirectoryEntries = new IMAGE_RESOURCE_DIRECTORY_ENTRY[imageResourceDirectory.NumberOfIdEntries];
226     for (int i = 0; i < imageResourceDirectoryEntries.length; i++) {
227         imageResourceDirectoryEntries[i] = new IMAGE_RESOURCE_DIRECTORY_ENTRY();
228         read(raf, imageResourceDirectoryEntries[i]);
229     }
230     for (int i = 0; i < imageResourceDirectoryEntries.length; i++) {
231         if (imageResourceDirectoryEntries[i].DataIsDirectory) {
232             dumpResourceDirectory(raf, imageResourceDirectoryEntries[i].OffsetToDirectory + resourceBase, resourceBase, delta, imageResourceDirectoryEntries[i].Id, level + 1, rt_icon_root ? true : type == RT_ICON);
233         } else {
234             // Resource found
235
/// pResDirEntry->Name
236
IMAGE_RESOURCE_DIRECTORY_ENTRY irde = imageResourceDirectoryEntries[i];
237             IMAGE_RESOURCE_DATA_ENTRY data = new IMAGE_RESOURCE_DATA_ENTRY();
238             raf.seek(imageResourceDirectoryEntries[i].OffsetToData + resourceBase);
239             read(raf, data);
240             if (DEBUG) System.out.println("Resource Id "+irde.Id+" Data Offset RVA "+data.OffsetToData+", Size "+data.Size);
241             if (rt_icon_root) {
242                 if (DEBUG) System.out.println("iconcnt "+iconCnt+" |"+iconInfo.length);
243                 iconInfo[iconCnt] = new IconResInfo();
244                 iconInfo[iconCnt].data = parseIcon(raf, data.OffsetToData - delta, data.Size);
245                 iconInfo[iconCnt].offset = data.OffsetToData - delta;
246                 iconInfo[iconCnt].size = data.Size;
247                 iconCnt++;
248                 if (iconCnt == iconInfo.length) {
249                     IconResInfo[] newArray = new IconResInfo[iconInfo.length + 4];
250                     System.arraycopy(iconInfo, 0, newArray, 0, iconInfo.length);
251                     iconInfo = newArray;
252                 }
253             }
254         }
255     }
256 }
257
258 static ImageData parseIcon(RandomAccessFile raf, int offset, int size) throws IOException {
259     raf.seek(offset);
260     BITMAPINFO bitmapInfo = new BITMAPINFO();
261     read(raf, bitmapInfo);
262     bitmapInfo.bmiHeader.biHeight /= 2;
263     int width = bitmapInfo.bmiHeader.biWidth;
264     int height = bitmapInfo.bmiHeader.biHeight;
265     int depth = bitmapInfo.bmiHeader.biBitCount;
266
267     PaletteData palette = loadPalette(bitmapInfo.bmiHeader, raf);
268     byte[] shapeData = loadData(bitmapInfo.bmiHeader, raf);
269     bitmapInfo.bmiHeader.biBitCount = 1;
270     byte[] maskData = loadData(bitmapInfo.bmiHeader, raf);
271     maskData = convertPad(maskData, width, height, 1, 4, 2);
272     bitInvertData(maskData, 0, maskData.length);
273     return ImageData.internal_new(
274         width,
275         height,
276         depth,
277         palette,
278         4,
279         shapeData,
280         2,
281         maskData,
282         null,
283         -1,
284         -1,
285         SWT.IMAGE_ICO,
286         0,
287         0,
288         0,
289         0);
290 }
291
292 static byte[] bitInvertData(byte[] data, int startIndex, int endIndex) {
293     // Destructively bit invert data in the given byte array.
294
for (int i = startIndex; i < endIndex; i++) {
295         data[i] = (byte)(255 - data[i - startIndex]);
296     }
297     return data;
298 }
299
300 static final byte[] convertPad(byte[] data, int width, int height, int depth, int pad, int newPad) {
301     if (pad == newPad) return data;
302     int stride = (width * depth + 7) / 8;
303     int bpl = (stride + (pad - 1)) / pad * pad;
304     int newBpl = (stride + (newPad - 1)) / newPad * newPad;
305     byte[] newData = new byte[height * newBpl];
306     int srcIndex = 0, destIndex = 0;
307     for (int y = 0; y < height; y++) {
308         System.arraycopy(data, srcIndex, newData, destIndex, newBpl);
309         srcIndex += bpl;
310         destIndex += newBpl;
311     }
312     return newData;
313 }
314 static PaletteData loadPalette(BITMAPINFOHEADER bih, RandomAccessFile raf) throws IOException {
315     int depth = bih.biBitCount;
316     if (depth <= 8) {
317         int numColors = bih.biClrUsed;
318         if (numColors == 0) {
319             numColors = 1 << depth;
320         } else {
321             if (numColors > 256)
322                 numColors = 256;
323         }
324         byte[] buf = new byte[numColors * 4];
325         raf.read(buf);
326         return paletteFromBytes(buf, numColors);
327     }
328     if (depth == 16) return new PaletteData(0x7C00, 0x3E0, 0x1F);
329     if (depth == 24) return new PaletteData(0xFF, 0xFF00, 0xFF0000);
330     return new PaletteData(0xFF00, 0xFF0000, 0xFF000000);
331 }
332 static PaletteData paletteFromBytes(byte[] bytes, int numColors) {
333     int bytesOffset = 0;
334     RGB[] colors = new RGB[numColors];
335     for (int i = 0; i < numColors; i++) {
336         colors[i] = new RGB(bytes[bytesOffset + 2] & 0xFF,
337             bytes[bytesOffset + 1] & 0xFF,
338             bytes[bytesOffset] & 0xFF);
339         bytesOffset += 4;
340     }
341     return new PaletteData(colors);
342 }
343 static byte[] loadData(BITMAPINFOHEADER bih, RandomAccessFile raf) throws IOException {
344     int stride = (bih.biWidth * bih.biBitCount + 7) / 8;
345     stride = (stride + 3) / 4 * 4; // Round up to 4 byte multiple
346
byte[] data = loadData(bih, raf, stride);
347     flipScanLines(data, stride, bih.biHeight);
348     return data;
349 }
350 static void flipScanLines(byte[] data, int stride, int height) {
351     int i1 = 0;
352     int i2 = (height - 1) * stride;
353     for (int i = 0; i < height / 2; i++) {
354         for (int index = 0; index < stride; index++) {
355             byte b = data[index + i1];
356             data[index + i1] = data[index + i2];
357             data[index + i2] = b;
358         }
359         i1 += stride;
360         i2 -= stride;
361     }
362 }
363 static byte[] loadData(BITMAPINFOHEADER bih, RandomAccessFile raf, int stride) throws IOException {
364     int dataSize = bih.biHeight * stride;
365     byte[] data = new byte[dataSize];
366     int cmp = bih.biCompression;
367     if (cmp == 0) { // BMP_NO_COMPRESSION
368
raf.read(data);
369     } else {
370         if (DEBUG) System.out.println("ICO cannot be compressed?");
371     }
372     return data;
373 }
374
375 static void unloadIcon(RandomAccessFile raf, ImageData icon) throws IOException {
376     int sizeImage = (((icon.width * icon.depth + 31) / 32 * 4) +
377         ((icon.width + 31) / 32 * 4)) * icon.height;
378     write4(raf, BMPHeaderFixedSize);
379     write4(raf, icon.width);
380     write4(raf, icon.height * 2);
381     writeU2(raf, 1);
382     writeU2(raf, icon.depth);
383     write4(raf, 0);
384     write4(raf, sizeImage);
385     write4(raf, 0);
386     write4(raf, 0);
387     write4(raf, icon.palette.colors != null ? icon.palette.colors.length : 0);
388     write4(raf, 0);
389     
390     byte[] rgbs = paletteToBytes(icon.palette);
391     raf.write(rgbs);
392     unloadShapeData(raf, icon);
393     unloadMaskData(raf, icon);
394 }
395 static byte[] paletteToBytes(PaletteData pal) {
396     int n = pal.colors == null ? 0 : (pal.colors.length < 256 ? pal.colors.length : 256);
397     byte[] bytes = new byte[n * 4];
398     int offset = 0;
399     for (int i = 0; i < n; i++) {
400         RGB col = pal.colors[i];
401         bytes[offset] = (byte)col.blue;
402         bytes[offset + 1] = (byte)col.green;
403         bytes[offset + 2] = (byte)col.red;
404         offset += 4;
405     }
406     return bytes;
407 }
408 static void unloadMaskData(RandomAccessFile raf, ImageData icon) {
409     ImageData mask = icon.getTransparencyMask();
410     int bpl = (icon.width + 7) / 8;
411     int pad = mask.scanlinePad;
412     int srcBpl = (bpl + pad - 1) / pad * pad;
413     int destBpl = (bpl + 3) / 4 * 4;
414     byte[] buf = new byte[destBpl];
415     int offset = (icon.height - 1) * srcBpl;
416     byte[] data = mask.data;
417     try {
418         for (int i = 0; i < icon.height; i++) {
419             System.arraycopy(data, offset, buf, 0, bpl);
420             bitInvertData(buf, 0, bpl);
421             raf.write(buf, 0, destBpl);
422             offset -= srcBpl;
423         }
424     } catch (IOException e) {
425         SWT.error(SWT.ERROR_IO, e);
426     }
427 }
428 static void unloadShapeData(RandomAccessFile raf, ImageData icon) {
429     int bpl = (icon.width * icon.depth + 7) / 8;
430     int pad = icon.scanlinePad;
431     int srcBpl = (bpl + pad - 1) / pad * pad;
432     int destBpl = (bpl + 3) / 4 * 4;
433     byte[] buf = new byte[destBpl];
434     int offset = (icon.height - 1) * srcBpl;
435     byte[] data = icon.data;
436     try {
437         for (int i = 0; i < icon.height; i++) {
438             System.arraycopy(data, offset, buf, 0, bpl);
439             raf.write(buf, 0, destBpl);
440             offset -= srcBpl;
441         }
442     } catch (IOException e) {
443         SWT.error(SWT.ERROR_IO, e);
444     }
445 }
446 static boolean readIconGroup(RandomAccessFile raf, int offset, int size) throws IOException {
447     raf.seek(offset);
448     NEWHEADER newHeader = new NEWHEADER();
449     read(raf, newHeader);
450     if (newHeader.ResType != RES_ICON) return false;
451     RESDIR[] resDir = new RESDIR[newHeader.ResCount];
452     for (int i = 0; i < newHeader.ResCount; i++) {
453         resDir[i] = new RESDIR();
454         read(raf, resDir[i]);
455     }
456     return true;
457 }
458
459 static void copyFile(String JavaDoc src, String JavaDoc dst) throws FileNotFoundException, IOException {
460     File srcFile = new File(src);
461     File dstFile = new File(dst);
462     FileInputStream in = new FileInputStream(srcFile);
463     FileOutputStream out = new FileOutputStream(dstFile);
464     int c;
465     while ((c = in.read()) != -1) out.write(c);
466     in.close();
467     out.close();
468 }
469
470 /* IO utilities to parse Windows executable */
471 static final int IMAGE_DOS_SIGNATURE = 0x5a4d;
472 static final int IMAGE_NT_SIGNATURE = 0x00004550;
473 static final int IMAGE_DIRECTORY_ENTRY_RESOURCE = 2;
474 static final int RES_ICON = 1;
475 static final int RT_ICON = 3;
476 static final int RT_GROUP_ICON = 14;
477 static final int BMPHeaderFixedSize = 40;
478     
479 public static class IMAGE_DOS_HEADER {
480     int e_magic; // WORD
481
int e_cblp; // WORD
482
int e_cp; // WORD
483
int e_crlc; // WORD
484
int e_cparhdr; // WORD
485
int e_minalloc; // WORD
486
int e_maxalloc; // WORD
487
int e_ss; // WORD
488
int e_sp; // WORD
489
int e_csum; // WORD
490
int e_ip; // WORD
491
int e_cs; // WORD
492
int e_lfarlc; // WORD
493
int e_ovno; // WORD
494
int[] e_res = new int[4]; // WORD[4]
495
int e_oemid; // WORD
496
int e_oeminfo; // WORD
497
int[] e_res2 = new int[10]; // WORD[10]
498
int e_lfanew; // LONG
499
}
500
501 public static class IMAGE_FILE_HEADER {
502     int Machine; // WORD
503
int NumberOfSections; // WORD
504
int TimeDateStamp; // DWORD
505
int PointerToSymbolTable; // DWORD
506
int NumberOfSymbols; // DWORD
507
int SizeOfOptionalHeader; // WORD
508
int Characteristics; // WORD
509
}
510
511 public static class IMAGE_DATA_DIRECTORY {
512     int VirtualAddress; // DWORD
513
int Size; // DWORD
514
}
515
516 public static class IMAGE_OPTIONAL_HEADER {
517     int Magic; // WORD
518
int MajorLinkerVersion; // BYTE
519
int MinorLinkerVersion; // BYTE
520
int SizeOfCode; // DWORD
521
int SizeOfInitializedData; // DWORD
522
int SizeOfUninitializedData; // DWORD
523
int AddressOfEntryPoint; // DWORD
524
int BaseOfCode; // DWORD
525
int BaseOfData; // DWORD
526
int ImageBase; // DWORD
527
int SectionAlignment; // DWORD
528
int FileAlignment; // DWORD
529
int MajorOperatingSystemVersion; // WORD
530
int MinorOperatingSystemVersion; // WORD
531
int MajorImageVersion; // WORD
532
int MinorImageVersion; // WORD
533
int MajorSubsystemVersion; // WORD
534
int MinorSubsystemVersion; // WORD
535
int Win32VersionValue; // DWORD
536
int SizeOfImage; // DWORD
537
int SizeOfHeaders; // DWORD
538
int CheckSum; // DWORD
539
int Subsystem; // WORD
540
int DllCharacteristics; // WORD
541
int SizeOfStackReserve; // DWORD
542
int SizeOfStackCommit; // DWORD
543
int SizeOfHeapReserve; // DWORD
544
int SizeOfHeapCommit; // DWORD
545
int LoaderFlags; // DWORD
546
int NumberOfRvaAndSizes; // DWORD
547
IMAGE_DATA_DIRECTORY[] DataDirectory = new IMAGE_DATA_DIRECTORY[16];
548 }
549 public static class IMAGE_NT_HEADERS {
550     int Signature; // DWORD
551
IMAGE_FILE_HEADER FileHeader = new IMAGE_FILE_HEADER();
552     IMAGE_OPTIONAL_HEADER OptionalHeader = new IMAGE_OPTIONAL_HEADER();
553     final static int FIELD_OFFSET_OptionalHeader = 24;
554 }
555     
556 public static class IMAGE_SECTION_HEADER {
557     int[] Name = new int[8]; // BYTE[8]
558
int Misc_VirtualSize; // DWORD (union Misc { DWORD PhysicalAddress; DWORD VirtualSize }
559
int VirtualAddress; // DWORD
560
int SizeOfRawData; // DWORD
561
int PointerToRawData; // DWORD
562
int PointerToRelocations; // DWORD
563
int PointerToLinenumbers; // DWORD
564
int NumberOfRelocations; // WORD
565
int NumberOfLinenumbers; // WORD
566
int Characteristics; // DWORD
567
}
568
569 public static class IMAGE_RESOURCE_DIRECTORY {
570     int Characteristics; // DWORD
571
int TimeDateStamp; // DWORD
572
int MajorVersion; // WORD
573
int MinorVersion; // WORD
574
int NumberOfNamedEntries; // WORD - used
575
int NumberOfIdEntries; // WORD - used
576
final static int SIZEOF = 16;
577 }
578
579 public static class IMAGE_RESOURCE_DIRECTORY_ENTRY {
580     // union
581
int NameOffset; // DWORD 31 bits
582
boolean NameIsString; // DWORD 1 bit
583
int Name; // DWORD
584
int Id; // WORD
585
// union
586
int OffsetToData; // DWORD
587
int OffsetToDirectory; // DWORD 31 bits
588
boolean DataIsDirectory; // DWORD 1 bit
589
}
590
591 public static class IMAGE_RESOURCE_DATA_ENTRY {
592     int OffsetToData; // DWORD
593
int Size; // DWORD
594
int CodePage; // DWORD
595
int Reserved; // DWORD
596
}
597
598 public static class NEWHEADER {
599     int Reserved; // WORD
600
int ResType; // WORD
601
int ResCount; // WORD
602
}
603
604 public static class ICONRESDIR {
605     int Width; // BYTE
606
int Height; // BYTE
607
int ColorCount; // BYTE
608
int reserved; // BYTE
609
}
610
611 public static class CURSORDIR {
612     int Width; // WORD
613
int Height; // WORD
614
}
615
616 public static class RESDIR {
617     // union
618
ICONRESDIR Icon = new ICONRESDIR();
619     CURSORDIR Cursor = new CURSORDIR();
620     int Planes; // WORD
621
int BitCount; // WORD
622
int BytesInRes; // DWORD
623
int IconCursorId; // WORD
624
}
625
626 public static class BITMAPINFOHEADER {
627     int biSize; // DWORD
628
int biWidth; // LONG
629
int biHeight; // LONG
630
int biPlanes; // WORD
631
int biBitCount; // WORD
632
int biCompression; // DWORD
633
int biSizeImage; // DWORD
634
int biXPelsPerMeter; // LONG
635
int biYPelsPerMeter; // LONG
636
int biClrUsed; // DWORD
637
int biClrImportant; // DWORD
638
}
639
640 static class RGBQUAD {
641     int rgBlue; // BYTE
642
int rgbGreen; // BYTE
643
int rgbRed; // BYTE
644
int rgbReserved; // BYTE
645
}
646 static class BITMAPINFO {
647     BITMAPINFOHEADER bmiHeader = new BITMAPINFOHEADER();
648     RGBQUAD[] bmiColors = null;
649 }
650 static void read(RandomAccessFile raf, BITMAPINFOHEADER bih) throws IOException {
651     bih.biSize = read4(raf);
652     bih.biWidth = read4(raf);
653     bih.biHeight = read4(raf);
654     bih.biPlanes = readU2(raf);
655     bih.biBitCount = readU2(raf);
656     bih.biCompression = read4(raf);
657     bih.biSizeImage = read4(raf);
658     bih.biXPelsPerMeter = read4(raf);
659     bih.biYPelsPerMeter = read4(raf);
660     bih.biClrUsed = read4(raf);
661     bih.biClrImportant = read4(raf);
662 }
663 static void read(RandomAccessFile raf, BITMAPINFO bi) throws IOException {
664     read(raf, bi.bmiHeader);
665 }
666 /* Little Endian helpers */
667 static int readU2(RandomAccessFile raf) throws IOException {
668     int b0 = raf.readByte() & 0xFF;
669     int b1 = raf.readByte() & 0xFF;
670     return (b1 << 8 | b0);
671 }
672 static int read4(RandomAccessFile raf) throws IOException {
673     int b0 = raf.readByte() & 0xFF;
674     int b1 = raf.readByte() & 0xFF;
675     int b2 = raf.readByte() & 0xFF;
676     int b3 = raf.readByte() & 0xFF;
677     return b3 << 24 | b2 << 16 | b1 << 8 | b0;
678 }
679 static void write4(RandomAccessFile raf, int value) throws IOException {
680     raf.write(value & 0xFF);
681     raf.write((value >> 8) & 0xFF);
682     raf.write((value >> 16) & 0xFF);
683     raf.write((value >> 24) & 0xFF);
684 }
685 static void writeU2(RandomAccessFile raf, int value) throws IOException {
686     raf.write(value & 0xFF);
687     raf.write((value >> 8) & 0xFF);
688 }
689 static void read(RandomAccessFile raf, IMAGE_DOS_HEADER idh) throws IOException {
690     idh.e_magic = readU2(raf);
691     idh.e_cblp = readU2(raf);
692     idh.e_cp = readU2(raf);
693     idh.e_crlc = readU2(raf);
694     idh.e_cparhdr = readU2(raf);
695     idh.e_minalloc = readU2(raf);
696     idh.e_maxalloc = readU2(raf);
697     idh.e_ss = readU2(raf);
698     idh.e_sp = readU2(raf);
699     idh.e_csum = readU2(raf);
700     idh.e_ip = readU2(raf);
701     idh.e_cs = readU2(raf);
702     idh.e_lfarlc = readU2(raf);
703     idh.e_ovno = readU2(raf);
704     for (int i = 0; i < idh.e_res.length; i++) idh.e_res[i] = readU2(raf);
705     idh.e_oemid = readU2(raf);
706     idh.e_oeminfo = readU2(raf);
707     for (int i = 0; i < idh.e_res2.length; i++) idh.e_res2[i] = readU2(raf);
708     idh.e_lfanew = read4(raf);
709 }
710 static void read(RandomAccessFile raf, IMAGE_FILE_HEADER ifh) throws IOException {
711     ifh.Machine = readU2(raf);
712     ifh.NumberOfSections = readU2(raf);
713     ifh.TimeDateStamp = read4(raf);
714     ifh.PointerToSymbolTable = read4(raf);
715     ifh.NumberOfSymbols = read4(raf);
716     ifh.SizeOfOptionalHeader = readU2(raf);
717     ifh.Characteristics = readU2(raf);
718 }
719 static void read(RandomAccessFile raf, IMAGE_DATA_DIRECTORY idd) throws IOException {
720     idd.VirtualAddress = read4(raf);
721     idd.Size = read4(raf);
722 }
723 static void read(RandomAccessFile raf, IMAGE_OPTIONAL_HEADER ioh) throws IOException {
724     ioh.Magic = readU2(raf);
725     ioh.MajorLinkerVersion = raf.read();
726     ioh.MinorLinkerVersion = raf.read();
727     ioh.SizeOfCode = read4(raf);
728     ioh.SizeOfInitializedData = read4(raf);
729     ioh.SizeOfUninitializedData = read4(raf);
730     ioh.AddressOfEntryPoint = read4(raf);
731     ioh.BaseOfCode = read4(raf);
732     ioh.BaseOfData = read4(raf);
733     ioh.ImageBase = read4(raf);
734     ioh.SectionAlignment = read4(raf);
735     ioh.FileAlignment = read4(raf);
736     ioh.MajorOperatingSystemVersion = readU2(raf);
737     ioh.MinorOperatingSystemVersion = readU2(raf);
738     ioh.MajorImageVersion = readU2(raf);
739     ioh.MinorImageVersion = readU2(raf);
740     ioh.MajorSubsystemVersion = readU2(raf);
741     ioh.MinorSubsystemVersion = readU2(raf);
742     ioh.Win32VersionValue = read4(raf);
743     ioh.SizeOfImage = read4(raf);
744     ioh.SizeOfHeaders = read4(raf);
745     ioh.CheckSum = read4(raf);
746     ioh.Subsystem = readU2(raf);
747     ioh.DllCharacteristics = readU2(raf);
748     ioh.SizeOfStackReserve = read4(raf);
749     ioh.SizeOfStackCommit = read4(raf);
750     ioh.SizeOfHeapReserve = read4(raf);
751     ioh.SizeOfHeapCommit = read4(raf);
752     ioh.LoaderFlags = read4(raf);
753     ioh.NumberOfRvaAndSizes = read4(raf);
754     for (int i = 0 ; i < ioh.DataDirectory.length; i++) {
755         ioh.DataDirectory[i] = new IMAGE_DATA_DIRECTORY();
756         read(raf, ioh.DataDirectory[i]);
757     }
758 }
759 static void read(RandomAccessFile raf, IMAGE_NT_HEADERS inh) throws IOException {
760     inh.Signature = read4(raf);
761     read(raf, inh.FileHeader);
762     read(raf, inh.OptionalHeader);
763 }
764 static void read(RandomAccessFile raf, IMAGE_SECTION_HEADER ish) throws IOException {
765     for (int i = 0 ; i < ish.Name.length; i++) ish.Name[i] = raf.read();
766     ish.Misc_VirtualSize = read4(raf);
767     ish.VirtualAddress = read4(raf);
768     ish.SizeOfRawData = read4(raf);
769     ish.PointerToRawData = read4(raf);
770     ish.PointerToRelocations = read4(raf);
771     ish.PointerToLinenumbers = read4(raf);
772     ish.NumberOfRelocations = readU2(raf);
773     ish.NumberOfLinenumbers = readU2(raf);
774     ish.Characteristics = read4(raf);
775 }
776 static void read(RandomAccessFile raf, IMAGE_RESOURCE_DIRECTORY ird) throws IOException {
777     ird.Characteristics = read4(raf);
778     ird.TimeDateStamp = read4(raf);
779     ird.MajorVersion = readU2(raf);
780     ird.MinorVersion = readU2(raf);
781     ird.NumberOfNamedEntries = readU2(raf);
782     ird.NumberOfIdEntries = readU2(raf);
783 }
784 static void read(RandomAccessFile raf, IMAGE_RESOURCE_DIRECTORY_ENTRY irde) throws IOException {
785     irde.Name = read4(raf);
786     irde.OffsetToData = read4(raf);
787     // construct other union members
788
irde.NameOffset = irde.Name & ~ (1 << 31);
789     irde.NameIsString = (irde.Name & (1 << 31)) != 0;
790     irde.Id = irde.Name & 0xFFFF;
791     irde.OffsetToDirectory = irde.OffsetToData & ~ (1 << 31);
792     irde.DataIsDirectory = (irde.OffsetToData & (1 << 31)) != 0;
793 }
794 static void read(RandomAccessFile raf, IMAGE_RESOURCE_DATA_ENTRY irde) throws IOException {
795     irde.OffsetToData = read4(raf);
796     irde.Size = read4(raf);
797     irde.CodePage = read4(raf);
798     irde.Reserved = read4(raf);
799 }
800 static void read(RandomAccessFile raf, NEWHEADER nh) throws IOException {
801     nh.Reserved = readU2(raf);
802     nh.ResType = readU2(raf);
803     nh.ResCount = readU2(raf);
804 }
805 static void read(RandomAccessFile raf, ICONRESDIR i) throws IOException {
806     i.Width = raf.read();
807     i.Height = raf.read();
808     i.ColorCount = raf.read();
809     i.reserved = raf.read();
810 }
811 static void read(RandomAccessFile raf, CURSORDIR c) throws IOException {
812     c.Width = readU2(raf);
813     c.Height = readU2(raf);
814 }
815 static void read(RandomAccessFile raf, RESDIR rs) throws IOException {
816     long start = raf.getFilePointer();
817     read(raf, rs.Icon);
818     raf.seek(start);
819     read(raf, rs.Cursor);
820     rs.Planes = readU2(raf);
821     rs.BitCount = readU2(raf);
822     rs.BytesInRes = read4(raf);
823     rs.IconCursorId = readU2(raf);
824 }
825
826 /* ImageData and Image Decoder inlining to avoid dependency on SWT
827  * The following section can be entirely removed if SWT can be used.
828  */

829
830 static class RGB {
831     
832     /**
833      * the red component of the RGB
834      */

835     public int red;
836     
837     /**
838      * the green component of the RGB
839      */

840     public int green;
841     
842     /**
843      * the blue component of the RGB
844      */

845     public int blue;
846     
847     static final long serialVersionUID = 3258415023461249074L;
848     
849 /**
850  * Constructs an instance of this class with the given
851  * red, green and blue values.
852  *
853  * @param red the red component of the new instance
854  * @param green the green component of the new instance
855  * @param blue the blue component of the new instance
856  *
857  * @exception IllegalArgumentException <ul>
858  * <li>ERROR_INVALID_ARGUMENT - if the red, green or blue argument is not between 0 and 255</li>
859  * </ul>
860  */

861 public RGB(int red, int green, int blue) {
862     if ((red > 255) || (red < 0) ||
863         (green > 255) || (green < 0) ||
864         (blue > 255) || (blue < 0))
865             SWT.error(SWT.ERROR_INVALID_ARGUMENT);
866     this.red = red;
867     this.green = green;
868     this.blue = blue;
869 }
870
871 /**
872  * Compares the argument to the receiver, and returns true
873  * if they represent the <em>same</em> object using a class
874  * specific comparison.
875  *
876  * @param object the object to compare with this object
877  * @return <code>true</code> if the object is the same as this object and <code>false</code> otherwise
878  *
879  * @see #hashCode()
880  */

881 public boolean equals (Object JavaDoc object) {
882     if (object == this) return true;
883     if (!(object instanceof RGB)) return false;
884     RGB rgb = (RGB)object;
885     return (rgb.red == this.red) && (rgb.green == this.green) && (rgb.blue == this.blue);
886 }
887
888 /**
889  * Returns an integer hash code for the receiver. Any two
890  * objects which return <code>true</code> when passed to
891  * <code>equals</code> must return the same value for this
892  * method.
893  *
894  * @return the receiver's hash
895  *
896  * @see #equals(Object)
897  */

898 public int hashCode () {
899     return (blue << 16) | (green << 8) | red;
900 }
901
902 /**
903  * Returns a string containing a concise, human-readable
904  * description of the receiver.
905  *
906  * @return a string representation of the <code>RGB</code>
907  */

908 public String JavaDoc toString () {
909     return "RGB {" + red + ", " + green + ", " + blue + "}"; //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
910

911 //$NON-NLS-4$
912
}
913
914 }
915 static class PaletteData {
916     
917     /**
918      * true if the receiver is a direct palette,
919      * and false otherwise
920      */

921     public boolean isDirect;
922     
923     /**
924      * the RGB values for an indexed palette, where the
925      * indices of the array correspond to pixel values
926      */

927     public RGB[] colors;
928     
929     /**
930      * the red mask for a direct palette
931      */

932     public int redMask;
933     
934     /**
935      * the green mask for a direct palette
936      */

937     public int greenMask;
938     
939     /**
940      * the blue mask for a direct palette
941      */

942     public int blueMask;
943     
944     /**
945      * the red shift for a direct palette
946      */

947     public int redShift;
948     
949     /**
950      * the green shift for a direct palette
951      */

952     public int greenShift;
953     
954     /**
955      * the blue shift for a direct palette
956      */

957     public int blueShift;
958
959 /**
960  * Constructs a new indexed palette given an array of RGB values.
961  *
962  * @param colors the array of <code>RGB</code>s for the palette
963  *
964  * @exception IllegalArgumentException <ul>
965  * <li>ERROR_NULL_ARGUMENT - if the argument is null</li>
966  * </ul>
967  */

968 public PaletteData(RGB[] colors) {
969     if (colors == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
970     this.colors = colors;
971     this.isDirect = false;
972 }
973
974 /**
975  * Constructs a new direct palette given the red, green and blue masks.
976  *
977  * @param redMask the red mask
978  * @param greenMask the green mask
979  * @param blueMask the blue mask
980  */

981 public PaletteData(int redMask, int greenMask, int blueMask) {
982     this.redMask = redMask;
983     this.greenMask = greenMask;
984     this.blueMask = blueMask;
985     this.isDirect = true;
986     this.redShift = shiftForMask(redMask);
987     this.greenShift = shiftForMask(greenMask);
988     this.blueShift = shiftForMask(blueMask);
989 }
990
991 /**
992  * Returns the pixel value corresponding to the given <code>RBG</code>.
993  *
994  * @param rgb the RGB to get the pixel value for
995  * @return the pixel value for the given RGB
996  *
997  * @exception IllegalArgumentException <ul>
998  * <li>ERROR_NULL_ARGUMENT - if the argument is null</li>
999  * <li>ERROR_INVALID_ARGUMENT - if the RGB is not found in the palette</li>
1000 * </ul>
1001 */

1002public int getPixel(RGB rgb) {
1003    if (rgb == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
1004    if (isDirect) {
1005        int pixel = 0;
1006        pixel |= (redShift < 0 ? rgb.red << -redShift : rgb.red >>> redShift) & redMask;
1007        pixel |= (greenShift < 0 ? rgb.green << -greenShift : rgb.green >>> greenShift) & greenMask;
1008        pixel |= (blueShift < 0 ? rgb.blue << -blueShift : rgb.blue >>> blueShift) & blueMask;
1009        return pixel;
1010    } else {
1011        for (int i = 0; i < colors.length; i++) {
1012            if (colors[i].equals(rgb)) return i;
1013        }
1014        /* The RGB did not exist in the palette */
1015        SWT.error(SWT.ERROR_INVALID_ARGUMENT);
1016        return 0;
1017    }
1018}
1019
1020/**
1021 * Returns an <code>RGB</code> corresponding to the given pixel value.
1022 *
1023 * @param pixel the pixel to get the RGB value for
1024 * @return the RGB value for the given pixel
1025 *
1026 * @exception IllegalArgumentException <ul>
1027 * <li>ERROR_NULL_ARGUMENT - if the argument is null</li>
1028 * <li>ERROR_INVALID_ARGUMENT - if the pixel does not exist in the palette</li>
1029 * </ul>
1030 */

1031public RGB getRGB(int pixel) {
1032    if (isDirect) {
1033        int r = pixel & redMask;
1034        r = (redShift < 0) ? r >>> -redShift : r << redShift;
1035        int g = pixel & greenMask;
1036        g = (greenShift < 0) ? g >>> -greenShift : g << greenShift;
1037        int b = pixel & blueMask;
1038        b = (blueShift < 0) ? b >>> -blueShift : b << blueShift;
1039        return new RGB(r, g, b);
1040    } else {
1041        if (pixel < 0 || pixel >= colors.length) {
1042            SWT.error(SWT.ERROR_INVALID_ARGUMENT);
1043        }
1044        return colors[pixel];
1045    }
1046}
1047
1048/**
1049 * Returns all the RGB values in the receiver if it is an
1050 * indexed palette, or null if it is a direct palette.
1051 *
1052 * @return the <code>RGB</code>s for the receiver or null
1053 */

1054public RGB[] getRGBs() {
1055    return colors;
1056}
1057
1058/**
1059 * Computes the shift value for a given mask.
1060 *
1061 * @param mask the mask to compute the shift for
1062 * @return the shift amount
1063 *
1064 * @see PaletteData
1065 */

1066int shiftForMask(int mask) {
1067    for (int i = 31; i >= 0; i--) {
1068        if (((mask >> i) & 0x1) != 0) return 7 - i;
1069    }
1070    return 32;
1071}
1072
1073}
1074static class ImageLoader {
1075    
1076    /**
1077     * the array of ImageData objects in this ImageLoader.
1078     * This array is read in when the load method is called,
1079     * and it is written out when the save method is called
1080     */

1081    public ImageData[] data;
1082    
1083    /**
1084     * the width of the logical screen on which the images
1085     * reside, in pixels (this corresponds to the GIF89a
1086     * Logical Screen Width value)
1087     */

1088    public int logicalScreenWidth;
1089
1090    /**
1091     * the height of the logical screen on which the images
1092     * reside, in pixels (this corresponds to the GIF89a
1093     * Logical Screen Height value)
1094     */

1095    public int logicalScreenHeight;
1096
1097    /**
1098     * the background pixel for the logical screen (this
1099     * corresponds to the GIF89a Background Color Index value).
1100     * The default is -1 which means 'unspecified background'
1101     *
1102     */

1103    public int backgroundPixel;
1104
1105    /**
1106     * the number of times to repeat the display of a sequence
1107     * of animated images (this corresponds to the commonly-used
1108     * GIF application extension for "NETSCAPE 2.0 01")
1109     */

1110    public int repeatCount;
1111        
1112    /*
1113     * the set of ImageLoader event listeners, created on demand
1114     */

1115    Vector imageLoaderListeners;
1116
1117/**
1118 * Construct a new empty ImageLoader.
1119 */

1120public ImageLoader() {
1121    reset();
1122}
1123
1124/**
1125 * Resets the fields of the ImageLoader, except for the
1126 * <code>imageLoaderListeners</code> field.
1127 */

1128void reset() {
1129    data = null;
1130    logicalScreenWidth = 0;
1131    logicalScreenHeight = 0;
1132    backgroundPixel = -1;
1133    repeatCount = 1;
1134}
1135
1136/**
1137 * Loads an array of <code>ImageData</code> objects from the
1138 * specified input stream. Throws an error if either an error
1139 * occurs while loading the images, or if the images are not
1140 * of a supported type. Returns the loaded image data array.
1141 *
1142 * @param stream the input stream to load the images from
1143 * @return an array of <code>ImageData</code> objects loaded from the specified input stream
1144 *
1145 * @exception IllegalArgumentException <ul>
1146 * <li>ERROR_NULL_ARGUMENT - if the stream is null</li>
1147 * </ul>
1148 * @exception SWTException <ul>
1149 * <li>ERROR_INVALID_IMAGE - if the image file contains invalid data</li>
1150 * <li>ERROR_IO - if an input/output error occurs while reading data</li>
1151 * <li>ERROR_UNSUPPORTED_FORMAT - if the image file contains an unrecognized format</li>
1152 * </ul>
1153 */

1154public ImageData[] load(InputStream stream) {
1155    if (stream == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
1156    reset();
1157    data = FileFormat.load(stream, this);
1158    return data;
1159}
1160
1161/**
1162 * Loads an array of <code>ImageData</code> objects from the
1163 * file with the specified name. Throws an error if either
1164 * an error occurs while loading the images, or if the images are
1165 * not of a supported type. Returns the loaded image data array.
1166 *
1167 * @param filename the name of the file to load the images from
1168 * @return an array of <code>ImageData</code> objects loaded from the specified file
1169 *
1170 * @exception IllegalArgumentException <ul>
1171 * <li>ERROR_NULL_ARGUMENT - if the file name is null</li>
1172 * </ul>
1173 * @exception SWTException <ul>
1174 * <li>ERROR_INVALID_IMAGE - if the image file contains invalid data</li>
1175 * <li>ERROR_IO - if an IO error occurs while reading data</li>
1176 * <li>ERROR_UNSUPPORTED_FORMAT - if the image file contains an unrecognized format</li>
1177 * </ul>
1178 */

1179public ImageData[] load(String JavaDoc filename) {
1180    if (filename == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
1181    InputStream stream = null;
1182    try {
1183        stream = new FileInputStream(filename);
1184        return load(stream);
1185    } catch (IOException e) {
1186        SWT.error(SWT.ERROR_IO, e);
1187    } finally {
1188        try {
1189            if (stream != null) stream.close();
1190        } catch (IOException e) {
1191            // Ignore error
1192
}
1193    }
1194    return null;
1195}
1196}
1197static class ImageData {
1198    
1199    /**
1200     * The width of the image, in pixels.
1201     */

1202    public int width;
1203
1204    /**
1205     * The height of the image, in pixels.
1206     */

1207    public int height;
1208
1209    /**
1210     * The color depth of the image, in bits per pixel.
1211     * <p>
1212     * Note that a depth of 8 or less does not necessarily
1213     * mean that the image is palette indexed, or
1214     * conversely that a depth greater than 8 means that
1215     * the image is direct color. Check the associated
1216     * PaletteData's isDirect field for such determinations.
1217     */

1218    public int depth;
1219
1220    /**
1221     * The scanline padding.
1222     * <p>
1223     * If one scanline of the image is not a multiple of
1224     * this number, it will be padded with zeros until it is.
1225     * </p>
1226     */

1227    public int scanlinePad;
1228
1229    /**
1230     * The number of bytes per scanline.
1231     * <p>
1232     * This is a multiple of the scanline padding.
1233     * </p>
1234     */

1235    public int bytesPerLine;
1236
1237    /**
1238     * The pixel data of the image.
1239     * <p>
1240     * Note that for 16 bit depth images the pixel data is stored
1241     * in least significant byte order; however, for 24bit and
1242     * 32bit depth images the pixel data is stored in most
1243     * significant byte order.
1244     * </p>
1245     */

1246    public byte[] data;
1247
1248    /**
1249     * The color table for the image.
1250     */

1251    public PaletteData palette;
1252
1253    /**
1254     * The transparent pixel.
1255     * <p>
1256     * Pixels with this value are transparent.
1257     * </p><p>
1258     * The default is -1 which means 'no transparent pixel'.
1259     * </p>
1260     */

1261    public int transparentPixel;
1262
1263    /**
1264     * An icon-specific field containing the data from the icon mask.
1265     * <p>
1266     * This is a 1 bit bitmap stored with the most significant
1267     * bit first. The number of bytes per scanline is
1268     * '((width + 7) / 8 + (maskPad - 1)) / maskPad * maskPad'.
1269     * </p><p>
1270     * The default is null which means 'no transparency mask'.
1271     * </p>
1272     */

1273    public byte[] maskData;
1274
1275    /**
1276     * An icon-specific field containing the scanline pad of the mask.
1277     * <p>
1278     * If one scanline of the transparency mask is not a
1279     * multiple of this number, it will be padded with zeros until
1280     * it is.
1281     * </p>
1282     */

1283    public int maskPad;
1284    
1285    /**
1286     * The alpha data of the image.
1287     * <p>
1288     * Every pixel can have an <em>alpha blending</em> value that
1289     * varies from 0, meaning fully transparent, to 255 meaning
1290     * fully opaque. The number of bytes per scanline is
1291     * 'width'.
1292     * </p>
1293     */

1294    public byte[] alphaData;
1295    
1296    /**
1297     * The global alpha value to be used for every pixel.
1298     * <p>
1299     * If this value is set, the <code>alphaData</code> field
1300     * is ignored and when the image is rendered each pixel
1301     * will be blended with the background an amount
1302     * proportional to this value.
1303     * </p><p>
1304     * The default is -1 which means 'no global alpha value'
1305     * </p>
1306     */

1307    public int alpha;
1308
1309    /**
1310     * The type of file from which the image was read.
1311     *
1312     * It is expressed as one of the following values:
1313     * <dl>
1314     * <dt><code>IMAGE_BMP</code></dt>
1315     * <dd>Windows BMP file format, no compression</dd>
1316     * <dt><code>IMAGE_BMP_RLE</code></dt>
1317     * <dd>Windows BMP file format, RLE compression if appropriate</dd>
1318     * <dt><code>IMAGE_GIF</code></dt>
1319     * <dd>GIF file format</dd>
1320     * <dt><code>IMAGE_ICO</code></dt>
1321     * <dd>Windows ICO file format</dd>
1322     * <dt><code>IMAGE_JPEG</code></dt>
1323     * <dd>JPEG file format</dd>
1324     * <dt><code>IMAGE_PNG</code></dt>
1325     * <dd>PNG file format</dd>
1326     * </dl>
1327     */

1328    public int type;
1329
1330    /**
1331     * The x coordinate of the top left corner of the image
1332     * within the logical screen (this field corresponds to
1333     * the GIF89a Image Left Position value).
1334     */

1335    public int x;
1336
1337    /**
1338     * The y coordinate of the top left corner of the image
1339     * within the logical screen (this field corresponds to
1340     * the GIF89a Image Top Position value).
1341     */

1342    public int y;
1343
1344    /**
1345     * A description of how to dispose of the current image
1346     * before displaying the next.
1347     *
1348     * It is expressed as one of the following values:
1349     * <dl>
1350     * <dt><code>DM_UNSPECIFIED</code></dt>
1351     * <dd>disposal method not specified</dd>
1352     * <dt><code>DM_FILL_NONE</code></dt>
1353     * <dd>do nothing - leave the image in place</dd>
1354     * <dt><code>DM_FILL_BACKGROUND</code></dt>
1355     * <dd>fill with the background color</dd>
1356     * <dt><code>DM_FILL_PREVIOUS</code></dt>
1357     * <dd>restore the previous picture</dd>
1358     * </dl>
1359     * (this field corresponds to the GIF89a Disposal Method value)
1360     */

1361    public int disposalMethod;
1362
1363    /**
1364     * The time to delay before displaying the next image
1365     * in an animation (this field corresponds to the GIF89a
1366     * Delay Time value).
1367     */

1368    public int delayTime;
1369
1370    /**
1371     * Arbitrary channel width data to 8-bit conversion table.
1372     */

1373    static final byte[][] ANY_TO_EIGHT = new byte[9][];
1374    static {
1375        for (int b = 0; b < 9; ++b) {
1376            byte[] data = ANY_TO_EIGHT[b] = new byte[1 << b];
1377            if (b == 0) continue;
1378            int inc = 0;
1379            for (int bit = 0x10000; (bit >>= b) != 0;) inc |= bit;
1380            for (int v = 0, p = 0; v < 0x10000; v+= inc) data[p++] = (byte)(v >> 8);
1381        }
1382    }
1383    static final byte[] ONE_TO_ONE_MAPPING = ANY_TO_EIGHT[8];
1384
1385    /**
1386     * Scaled 8x8 Bayer dither matrix.
1387     */

1388    static final int[][] DITHER_MATRIX = {
1389        { 0xfc0000, 0x7c0000, 0xdc0000, 0x5c0000, 0xf40000, 0x740000, 0xd40000, 0x540000 },
1390        { 0x3c0000, 0xbc0000, 0x1c0000, 0x9c0000, 0x340000, 0xb40000, 0x140000, 0x940000 },
1391        { 0xcc0000, 0x4c0000, 0xec0000, 0x6c0000, 0xc40000, 0x440000, 0xe40000, 0x640000 },
1392        { 0x0c0000, 0x8c0000, 0x2c0000, 0xac0000, 0x040000, 0x840000, 0x240000, 0xa40000 },
1393        { 0xf00000, 0x700000, 0xd00000, 0x500000, 0xf80000, 0x780000, 0xd80000, 0x580000 },
1394        { 0x300000, 0xb00000, 0x100000, 0x900000, 0x380000, 0xb80000, 0x180000, 0x980000 },
1395        { 0xc00000, 0x400000, 0xe00000, 0x600000, 0xc80000, 0x480000, 0xe80000, 0x680000 },
1396        { 0x000000, 0x800000, 0x200000, 0xa00000, 0x080000, 0x880000, 0x280000, 0xa80000 }
1397    };
1398
1399/**
1400 * Constructs a new, empty ImageData with the given width, height,
1401 * depth and palette. The data will be initialized to an (all zero)
1402 * array of the appropriate size.
1403 *
1404 * @param width the width of the image
1405 * @param height the height of the image
1406 * @param depth the depth of the image
1407 * @param palette the palette of the image (must not be null)
1408 *
1409 * @exception IllegalArgumentException <ul>
1410 * <li>ERROR_INVALID_ARGUMENT - if the width or height is negative, or if the depth is not
1411 * one of 1, 2, 4, 8, 16, 24 or 32</li>
1412 * <li>ERROR_NULL_ARGUMENT - if the palette is null</li>
1413 * </ul>
1414 */

1415public ImageData(int width, int height, int depth, PaletteData palette) {
1416    this(width, height, depth, palette,
1417        4, null, 0, null,
1418        null, -1, -1, SWT.IMAGE_UNDEFINED,
1419        0, 0, 0, 0);
1420}
1421
1422/**
1423 * Constructs a new, empty ImageData with the given width, height,
1424 * depth, palette, scanlinePad and data.
1425 *
1426 * @param width the width of the image
1427 * @param height the height of the image
1428 * @param depth the depth of the image
1429 * @param palette the palette of the image
1430 * @param scanlinePad the padding of each line, in bytes
1431 * @param data the data of the image
1432 *
1433 * @exception IllegalArgumentException <ul>
1434 * <li>ERROR_INVALID_ARGUMENT - if the width or height is negative, or if the depth is not
1435 * one of 1, 2, 4, 8, 16, 24 or 32</li>
1436 * <li>ERROR_NULL_ARGUMENT - if the palette or data is null</li>
1437 * <li>ERROR_CANNOT_BE_ZERO - if the scanlinePad is zero</li>
1438 * </ul>
1439 */

1440public ImageData(int width, int height, int depth, PaletteData palette, int scanlinePad, byte[] data) {
1441    this(width, height, depth, palette,
1442        scanlinePad, checkData(data), 0, null,
1443        null, -1, -1, SWT.IMAGE_UNDEFINED,
1444        0, 0, 0, 0);
1445}
1446
1447/**
1448 * Constructs an <code>ImageData</code> loaded from a file with the
1449 * specified name. Throws an error if an error occurs loading the
1450 * image, or if the image has an unsupported type.
1451 * <p>
1452 * This constructor is provided for convenience when loading a single
1453 * image only. If the file contains multiple images, only the first
1454 * one will be loaded. To load multiple images, use
1455 * <code>ImageLoader.load()</code>.
1456 * </p>
1457 *
1458 * @param filename the name of the file to load the image from (must not be null)
1459 *
1460 * @exception IllegalArgumentException <ul>
1461 * <li>ERROR_NULL_ARGUMENT - if the file name is null</li>
1462 * </ul>
1463 * @exception SWTException <ul>
1464 * <li>ERROR_INVALID_IMAGE - if the image file contains invalid data</li>
1465 * <li>ERROR_IO if an IO error occurs while reading data</li>
1466 * <li>ERROR_UNSUPPORTED_FORMAT - if the image file contains an unrecognized format</li>
1467 * </ul>
1468 */

1469public ImageData(String JavaDoc filename) {
1470    ImageData[] data = new ImageLoader().load(filename);
1471    if (data.length < 1) SWT.error(SWT.ERROR_INVALID_IMAGE);
1472    ImageData i = data[0];
1473    setAllFields(
1474        i.width,
1475        i.height,
1476        i.depth,
1477        i.scanlinePad,
1478        i.bytesPerLine,
1479        i.data,
1480        i.palette,
1481        i.transparentPixel,
1482        i.maskData,
1483        i.maskPad,
1484        i.alphaData,
1485        i.alpha,
1486        i.type,
1487        i.x,
1488        i.y,
1489        i.disposalMethod,
1490        i.delayTime);
1491}
1492
1493/**
1494 * Prevents uninitialized instances from being created outside the package.
1495 */

1496ImageData() {
1497}
1498
1499/**
1500 * Constructs an image data by giving values for all non-computable fields.
1501 * <p>
1502 * This method is for internal use, and is not described further.
1503 * </p>
1504 */

1505ImageData(
1506    int width, int height, int depth, PaletteData palette,
1507    int scanlinePad, byte[] data, int maskPad, byte[] maskData,
1508    byte[] alphaData, int alpha, int transparentPixel, int type,
1509    int x, int y, int disposalMethod, int delayTime)
1510{
1511
1512    if (palette == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
1513    if (!(depth == 1 || depth == 2 || depth == 4 || depth == 8
1514        || depth == 16 || depth == 24 || depth == 32)) {
1515        SWT.error(SWT.ERROR_INVALID_ARGUMENT);
1516    }
1517    if (width <= 0 || height <= 0) {
1518        SWT.error(SWT.ERROR_INVALID_ARGUMENT);
1519    }
1520    if (scanlinePad == 0) SWT.error (SWT.ERROR_CANNOT_BE_ZERO);
1521
1522    int bytesPerLine = (((width * depth + 7) / 8) + (scanlinePad - 1))
1523        / scanlinePad * scanlinePad;
1524    setAllFields(
1525        width,
1526        height,
1527        depth,
1528        scanlinePad,
1529        bytesPerLine,
1530        data != null ? data : new byte[bytesPerLine * height],
1531        palette,
1532        transparentPixel,
1533        maskData,
1534        maskPad,
1535        alphaData,
1536        alpha,
1537        type,
1538        x,
1539        y,
1540        disposalMethod,
1541        delayTime);
1542}
1543
1544/**
1545 * Initializes all fields in the receiver. This method must be called
1546 * by all public constructors to ensure that all fields are initialized
1547 * for a new ImageData object. If a new field is added to the class,
1548 * then it must be added to this method.
1549 * <p>
1550 * This method is for internal use, and is not described further.
1551 * </p>
1552 */

1553void setAllFields(int width, int height, int depth, int scanlinePad,
1554    int bytesPerLine, byte[] data, PaletteData palette, int transparentPixel,
1555    byte[] maskData, int maskPad, byte[] alphaData, int alpha,
1556    int type, int x, int y, int disposalMethod, int delayTime) {
1557
1558    this.width = width;
1559    this.height = height;
1560    this.depth = depth;
1561    this.scanlinePad = scanlinePad;
1562    this.bytesPerLine = bytesPerLine;
1563    this.data = data;
1564    this.palette = palette;
1565    this.transparentPixel = transparentPixel;
1566    this.maskData = maskData;
1567    this.maskPad = maskPad;
1568    this.alphaData = alphaData;
1569    this.alpha = alpha;
1570    this.type = type;
1571    this.x = x;
1572    this.y = y;
1573    this.disposalMethod = disposalMethod;
1574    this.delayTime = delayTime;
1575}
1576
1577/**
1578 * Invokes internal SWT functionality to create a new instance of
1579 * this class.
1580 * <p>
1581 * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
1582 * API for <code>ImageData</code>. It is marked public only so that it
1583 * can be shared within the packages provided by SWT. It is subject
1584 * to change without notice, and should never be called from
1585 * application code.
1586 * </p>
1587 * <p>
1588 * This method is for internal use, and is not described further.
1589 * </p>
1590 */

1591public static ImageData internal_new(
1592    int width, int height, int depth, PaletteData palette,
1593    int scanlinePad, byte[] data, int maskPad, byte[] maskData,
1594    byte[] alphaData, int alpha, int transparentPixel, int type,
1595    int x, int y, int disposalMethod, int delayTime)
1596{
1597    return new ImageData(
1598        width, height, depth, palette, scanlinePad, data, maskPad, maskData,
1599        alphaData, alpha, transparentPixel, type, x, y, disposalMethod, delayTime);
1600}
1601
1602ImageData colorMaskImage(int pixel) {
1603    ImageData mask = new ImageData(width, height, 1, bwPalette(),
1604        2, null, 0, null, null, -1, -1, SWT.IMAGE_UNDEFINED,
1605        0, 0, 0, 0);
1606    int[] row = new int[width];
1607    for (int y = 0; y < height; y++) {
1608        getPixels(0, y, width, row, 0);
1609        for (int i = 0; i < width; i++) {
1610            if (pixel != -1 && row[i] == pixel) {
1611                row[i] = 0;
1612            } else {
1613                row[i] = 1;
1614            }
1615        }
1616        mask.setPixels(0, y, width, row, 0);
1617    }
1618    return mask;
1619}
1620
1621static byte[] checkData(byte [] data) {
1622    if (data == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
1623    return data;
1624}
1625
1626/**
1627 * Returns <code>getWidth</code> pixel values starting at offset
1628 * <code>x</code> in scanline <code>y</code> in the receiver's
1629 * data starting at <code>startIndex</code>.
1630 *
1631 * @param x the x position of the first pixel to get
1632 * @param y the y position of the first pixel to get
1633 * @param getWidth the width of the data to get
1634 * @param pixels the buffer in which to put the pixels
1635 * @param startIndex the offset into the byte array to begin storing pixels
1636 *
1637 * @exception IndexOutOfBoundsException if getWidth is too large
1638 * @exception IllegalArgumentException <ul>
1639 * <li>ERROR_NULL_ARGUMENT - if pixels is null</li>
1640 * <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li>
1641 * <li>ERROR_INVALID_ARGUMENT - if getWidth is negative</li>
1642 * </ul>
1643 * @exception SWTException <ul>
1644 * <li>ERROR_UNSUPPORTED_DEPTH - if the depth is not one of 1, 2, 4 or 8
1645 * (For higher depths, use the int[] version of this method.)</li>
1646 * </ul>
1647 */

1648public void getPixels(int x, int y, int getWidth, byte[] pixels, int startIndex) {
1649    if (pixels == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
1650    if (getWidth < 0 || x >= width || y >= height || x < 0 || y < 0) SWT.error
1651
1652(SWT.ERROR_INVALID_ARGUMENT);
1653    if (getWidth == 0) return;
1654    int index;
1655    int theByte;
1656    int mask = 0;
1657    int n = getWidth;
1658    int i = startIndex;
1659    int srcX = x, srcY = y;
1660    if (depth == 1) {
1661        index = (y * bytesPerLine) + (x >> 3);
1662        theByte = data[index] & 0xFF;
1663        while (n > 0) {
1664            mask = 1 << (7 - (srcX & 0x7));
1665            if ((theByte & mask) == 0) {
1666                pixels[i] = 0;
1667            } else {
1668                pixels[i] = 1;
1669            }
1670            i++;
1671            n--;
1672            srcX++;
1673            if (srcX >= width) {
1674                srcY++;
1675                index = srcY * bytesPerLine;
1676                if (n > 0) theByte = data[index] & 0xFF;
1677                srcX = 0;
1678            } else {
1679                if (mask == 1) {
1680                    index++;
1681                    if (n > 0) theByte = data[index] & 0xFF;
1682                }
1683            }
1684        }
1685        return;
1686    }
1687    if (depth == 2) {
1688        index = (y * bytesPerLine) + (x >> 2);
1689        theByte = data[index] & 0xFF;
1690        int offset;
1691        while (n > 0) {
1692            offset = 3 - (srcX % 4);
1693            mask = 3 << (offset * 2);
1694            pixels[i] = (byte)((theByte & mask) >> (offset * 2));
1695            i++;
1696            n--;
1697            srcX++;
1698            if (srcX >= width) {
1699                srcY++;
1700                index = srcY * bytesPerLine;
1701                if (n > 0) theByte = data[index] & 0xFF;
1702                srcX = 0;
1703            } else {
1704                if (offset == 0) {
1705                    index++;
1706                    theByte = data[index] & 0xFF;
1707                }
1708            }
1709        }
1710        return;
1711    }
1712    if (depth == 4) {
1713        index = (y * bytesPerLine) + (x >> 1);
1714        if ((x & 0x1) == 1) {
1715            theByte = data[index] & 0xFF;
1716            pixels[i] = (byte)(theByte & 0x0F);
1717            i++;
1718            n--;
1719            srcX++;
1720            if (srcX >= width) {
1721                srcY++;
1722                index = srcY * bytesPerLine;
1723                srcX = 0;
1724            } else {
1725                index++;
1726            }
1727        }
1728        while (n > 1) {
1729            theByte = data[index] & 0xFF;
1730            pixels[i] = (byte)(theByte >> 4);
1731            i++;
1732            n--;
1733            srcX++;
1734            if (srcX >= width) {
1735                srcY++;
1736                index = srcY * bytesPerLine;
1737                srcX = 0;
1738            } else {
1739                pixels[i] = (byte)(theByte & 0x0F);
1740                i++;
1741                n--;
1742                srcX++;
1743                if (srcX >= width) {
1744                    srcY++;
1745                    index = srcY * bytesPerLine;
1746                    srcX = 0;
1747                } else {
1748                    index++;
1749                }
1750            }
1751        }
1752        if (n > 0) {
1753            theByte = data[index] & 0xFF;
1754            pixels[i] = (byte)(theByte >> 4);
1755        }
1756        return;
1757    }
1758    if (depth == 8) {
1759        index = (y * bytesPerLine) + x;
1760        for (int j = 0; j < getWidth; j++) {
1761            pixels[i] = data[index];
1762            i++;
1763            srcX++;
1764            if (srcX >= width) {
1765                srcY++;
1766                index = srcY * bytesPerLine;
1767                srcX = 0;
1768            } else {
1769                index++;
1770            }
1771        }
1772        return;
1773    }
1774    SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH);
1775}
1776
1777/**
1778 * Returns <code>getWidth</code> pixel values starting at offset
1779 * <code>x</code> in scanline <code>y</code> in the receiver's
1780 * data starting at <code>startIndex</code>.
1781 *
1782 * @param x the x position of the first pixel to get
1783 * @param y the y position of the first pixel to get
1784 * @param getWidth the width of the data to get
1785 * @param pixels the buffer in which to put the pixels
1786 * @param startIndex the offset into the buffer to begin storing pixels
1787 *
1788 * @exception IndexOutOfBoundsException if getWidth is too large
1789 * @exception IllegalArgumentException <ul>
1790 * <li>ERROR_NULL_ARGUMENT - if pixels is null</li>
1791 * <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li>
1792 * <li>ERROR_INVALID_ARGUMENT - if getWidth is negative</li>
1793 * </ul>
1794 * @exception SWTException <ul>
1795 * <li>ERROR_UNSUPPORTED_DEPTH - if the depth is not one of 1, 2, 4, 8, 16, 24 or 32</li>
1796 * </ul>
1797 */

1798public void getPixels(int x, int y, int getWidth, int[] pixels, int startIndex) {
1799    if (pixels == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
1800    if (getWidth < 0 || x >= width || y >= height || x < 0 || y < 0) SWT.error
1801
1802(SWT.ERROR_INVALID_ARGUMENT);
1803    if (getWidth == 0) return;
1804    int index;
1805    int theByte;
1806    int mask;
1807    int n = getWidth;
1808    int i = startIndex;
1809    int srcX = x, srcY = y;
1810    if (depth == 1) {
1811        index = (y * bytesPerLine) + (x >> 3);
1812        theByte = data[index] & 0xFF;
1813        while (n > 0) {
1814            mask = 1 << (7 - (srcX & 0x7));
1815            if ((theByte & mask) == 0) {
1816                pixels[i] = 0;
1817            } else {
1818                pixels[i] = 1;
1819            }
1820            i++;
1821            n--;
1822            srcX++;
1823            if (srcX >= width) {
1824                srcY++;
1825                index = srcY * bytesPerLine;
1826                if (n > 0) theByte = data[index] & 0xFF;
1827                srcX = 0;
1828            } else {
1829                if (mask == 1) {
1830                    index++;
1831                    if (n > 0) theByte = data[index] & 0xFF;
1832                }
1833            }
1834        }
1835        return;
1836    }
1837    if (depth == 2) {
1838        index = (y * bytesPerLine) + (x >> 2);
1839        theByte = data[index] & 0xFF;
1840        int offset;
1841        while (n > 0) {
1842            offset = 3 - (srcX % 4);
1843            mask = 3 << (offset * 2);
1844            pixels[i] = (byte)((theByte & mask) >> (offset * 2));
1845            i++;
1846            n--;
1847            srcX++;
1848            if (srcX >= width) {
1849                srcY++;
1850                index = srcY * bytesPerLine;
1851                if (n > 0) theByte = data[index] & 0xFF;
1852                srcX = 0;
1853            } else {
1854                if (offset == 0) {
1855                    index++;
1856                    theByte = data[index] & 0xFF;
1857                }
1858            }
1859        }
1860        return;
1861    }
1862    if (depth == 4) {
1863        index = (y * bytesPerLine) + (x >> 1);
1864        if ((x & 0x1) == 1) {
1865            theByte = data[index] & 0xFF;
1866            pixels[i] = theByte & 0x0F;
1867            i++;
1868            n--;
1869            srcX++;
1870            if (srcX >= width) {
1871                srcY++;
1872                index = srcY * bytesPerLine;
1873                srcX = 0;
1874            } else {
1875                index++;
1876            }
1877        }
1878        while (n > 1) {
1879            theByte = data[index] & 0xFF;
1880            pixels[i] = theByte >> 4;
1881            i++;
1882            n--;
1883            srcX++;
1884            if (srcX >= width) {
1885                srcY++;
1886                index = srcY * bytesPerLine;
1887                srcX = 0;
1888            } else {
1889                pixels[i] = theByte & 0x0F;
1890                i++;
1891                n--;
1892                srcX++;
1893                if (srcX >= width) {
1894                    srcY++;
1895                    index = srcY * bytesPerLine;
1896                    srcX = 0;
1897                } else {
1898                    index++;
1899                }
1900            }
1901        }
1902        if (n > 0) {
1903            theByte = data[index] & 0xFF;
1904            pixels[i] = theByte >> 4;
1905        }
1906        return;
1907    }
1908    if (depth == 8) {
1909        index = (y * bytesPerLine) + x;
1910        for (int j = 0; j < getWidth; j++) {
1911            pixels[i] = data[index] & 0xFF;
1912            i++;
1913            srcX++;
1914            if (srcX >= width) {
1915                srcY++;
1916                index = srcY * bytesPerLine;
1917                srcX = 0;
1918            } else {
1919                index++;
1920            }
1921        }
1922        return;
1923    }
1924    if (depth == 16) {
1925        index = (y * bytesPerLine) + (x * 2);
1926        for (int j = 0; j < getWidth; j++) {
1927            pixels[i] = ((data[index+1] & 0xFF) << 8) + (data[index] & 0xFF);
1928            i++;
1929            srcX++;
1930            if (srcX >= width) {
1931                srcY++;
1932                index = srcY * bytesPerLine;
1933                srcX = 0;
1934            } else {
1935                index += 2;
1936            }
1937        }
1938        return;
1939    }
1940    if (depth == 24) {
1941        index = (y * bytesPerLine) + (x * 3);
1942        for (int j = 0; j < getWidth; j++) {
1943            pixels[i] = ((data[index] & 0xFF) << 16) | ((data[index+1] & 0xFF) << 8)
1944                | (data[index+2] & 0xFF);
1945            i++;
1946            srcX++;
1947            if (srcX >= width) {
1948                srcY++;
1949                index = srcY * bytesPerLine;
1950                srcX = 0;
1951            } else {
1952                index += 3;
1953            }
1954        }
1955        return;
1956    }
1957    if (depth == 32) {
1958        index = (y * bytesPerLine) + (x * 4);
1959        i = startIndex;
1960        for (int j = 0; j < getWidth; j++) {
1961            pixels[i] = ((data[index] & 0xFF) << 24) | ((data[index+1] & 0xFF) << 16)
1962                | ((data[index+2] & 0xFF) << 8) | (data[index+3] & 0xFF);
1963            i++;
1964            srcX++;
1965            if (srcX >= width) {
1966                srcY++;
1967                index = srcY * bytesPerLine;
1968                srcX = 0;
1969            } else {
1970                index += 4;
1971            }
1972        }
1973        return;
1974    }
1975    SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH);
1976}
1977
1978/**
1979 * Returns an array of <code>RGB</code>s which comprise the
1980 * indexed color table of the receiver, or null if the receiver
1981 * has a direct color model.
1982 *
1983 * @return the RGB values for the image or null if direct color
1984 *
1985 * @see PaletteData#getRGBs()
1986 */

1987public RGB[] getRGBs() {
1988    return palette.getRGBs();
1989}
1990
1991/**
1992 * Returns an <code>ImageData</code> which specifies the
1993 * transparency mask information for the receiver, or null if the
1994 * receiver has no transparency and is not an icon.
1995 *
1996 * @return the transparency mask or null if none exists
1997 */

1998public ImageData getTransparencyMask() {
1999    if (getTransparencyType() == SWT.TRANSPARENCY_MASK) {
2000        return new ImageData(width, height, 1, bwPalette(), maskPad, maskData);
2001    } else {
2002        return colorMaskImage(transparentPixel);
2003    }
2004}
2005
2006/**
2007 * Returns the image transparency type.
2008 *
2009 * @return the receiver's transparency type
2010 */

2011public int getTransparencyType() {
2012    if (maskData != null) return SWT.TRANSPARENCY_MASK;
2013    if (transparentPixel != -1) return SWT.TRANSPARENCY_PIXEL;
2014    if (alphaData != null) return SWT.TRANSPARENCY_ALPHA;
2015    return SWT.TRANSPARENCY_NONE;
2016}
2017
2018/**
2019 * Returns the byte order of the receiver.
2020 *
2021 * @return MSB_FIRST or LSB_FIRST
2022 */

2023int getByteOrder() {
2024    return depth != 16 ? MSB_FIRST : LSB_FIRST;
2025}
2026
2027/**
2028 * Sets the pixel values starting at offset <code>x</code> in
2029 * scanline <code>y</code> in the receiver's data to the
2030 * values from the array <code>pixels</code> starting at
2031 * <code>startIndex</code>.
2032 *
2033 * @param x the x position of the pixel to set
2034 * @param y the y position of the pixel to set
2035 * @param putWidth the width of the pixels to set
2036 * @param pixels the pixels to set
2037 * @param startIndex the index at which to begin setting
2038 *
2039 * @exception IndexOutOfBoundsException if putWidth is too large
2040 * @exception IllegalArgumentException <ul>
2041 * <li>ERROR_NULL_ARGUMENT - if pixels is null</li>
2042 * <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li>
2043 * <li>ERROR_INVALID_ARGUMENT - if putWidth is negative</li>
2044 * </ul>
2045 * @exception SWTException <ul>
2046 * <li>ERROR_UNSUPPORTED_DEPTH if the depth is not one of 1, 2, 4, 8
2047 * (For higher depths, use the int[] version of this method.)</li>
2048 * </ul>
2049 */

2050public void setPixels(int x, int y, int putWidth, byte[] pixels, int startIndex) {
2051    if (pixels == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
2052    if (putWidth < 0 || x >= width || y >= height || x < 0 || y < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
2053    if (putWidth == 0) return;
2054    int index;
2055    int theByte;
2056    int mask;
2057    int n = putWidth;
2058    int i = startIndex;
2059    int srcX = x, srcY = y;
2060    if (depth == 1) {
2061        index = (y * bytesPerLine) + (x >> 3);
2062        while (n > 0) {
2063            mask = 1 << (7 - (srcX & 0x7));
2064            if ((pixels[i] & 0x1) == 1) {
2065                data[index] = (byte)((data[index] & 0xFF) | mask);
2066            } else {
2067                data[index] = (byte)((data[index] & 0xFF) & (mask ^ -1));
2068            }
2069            i++;
2070            n--;
2071            srcX++;
2072            if (srcX >= width) {
2073                srcY++;
2074                index = srcY * bytesPerLine;
2075                srcX = 0;
2076            } else {
2077                if (mask == 1) {
2078                    index++;
2079                }
2080            }
2081        }
2082        return;
2083    }
2084    if (depth == 2) {
2085        byte [] masks = { (byte)0xFC, (byte)0xF3, (byte)0xCF, (byte)0x3F };
2086        index = (y * bytesPerLine) + (x >> 2);
2087        int offset = 3 - (x % 4);
2088        while (n > 0) {
2089            theByte = pixels[i] & 0x3;
2090            data[index] = (byte)((data[index] & masks[offset]) | (theByte << (offset * 2)));
2091            i++;
2092            n--;
2093            srcX++;
2094            if (srcX >= width) {
2095                srcY++;
2096                index = srcY * bytesPerLine;
2097                offset = 0;
2098                srcX = 0;
2099            } else {
2100                if (offset == 0) {
2101                    index++;
2102                    offset = 3;
2103                } else {
2104                    offset--;
2105                }
2106            }
2107        }
2108        return;
2109    }
2110    if (depth == 4) {
2111        index = (y * bytesPerLine) + (x >> 1);
2112        boolean high = (x & 0x1) == 0;
2113        while (n > 0) {
2114            theByte = pixels[i] & 0x0F;
2115            if (high) {
2116                data[index] = (byte)((data[index] & 0x0F) | (theByte << 4));
2117            } else {
2118                data[index] = (byte)((data[index] & 0xF0) | theByte);
2119            }
2120            i++;
2121            n--;
2122            srcX++;
2123            if (srcX >= width) {
2124                srcY++;
2125                index = srcY * bytesPerLine;
2126                high = true;
2127                srcX = 0;
2128            } else {
2129                if (!high) index++;
2130                high = !high;
2131            }
2132        }
2133        return;
2134    }
2135    if (depth == 8) {
2136        index = (y * bytesPerLine) + x;
2137        for (int j = 0; j < putWidth; j++) {
2138            data[index] = (byte)(pixels[i] & 0xFF);
2139            i++;
2140            srcX++;
2141            if (srcX >= width) {
2142                srcY++;
2143                index = srcY * bytesPerLine;
2144                srcX = 0;
2145            } else {
2146                index++;
2147            }
2148        }
2149        return;
2150    }
2151    SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH);
2152}
2153
2154/**
2155 * Sets the pixel values starting at offset <code>x</code> in
2156 * scanline <code>y</code> in the receiver's data to the
2157 * values from the array <code>pixels</code> starting at
2158 * <code>startIndex</code>.
2159 *
2160 * @param x the x position of the pixel to set
2161 * @param y the y position of the pixel to set
2162 * @param putWidth the width of the pixels to set
2163 * @param pixels the pixels to set
2164 * @param startIndex the index at which to begin setting
2165 *
2166 * @exception IndexOutOfBoundsException if putWidth is too large
2167 * @exception IllegalArgumentException <ul>
2168 * <li>ERROR_NULL_ARGUMENT - if pixels is null</li>
2169 * <li>ERROR_INVALID_ARGUMENT - if x or y is out of bounds</li>
2170 * <li>ERROR_INVALID_ARGUMENT - if putWidth is negative</li>
2171 * </ul>
2172 * @exception SWTException <ul>
2173 * <li>ERROR_UNSUPPORTED_DEPTH if the depth is not one of 1, 2, 4, 8, 16, 24 or 32</li>
2174 * </ul>
2175 */

2176public void setPixels(int x, int y, int putWidth, int[] pixels, int startIndex) {
2177    if (pixels == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
2178    if (putWidth < 0 || x >= width || y >= height || x < 0 || y < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
2179    if (putWidth == 0) return;
2180    int index;
2181    int theByte;
2182    int mask;
2183    int n = putWidth;
2184    int i = startIndex;
2185    int pixel;
2186    int srcX = x, srcY = y;
2187    if (depth == 1) {
2188        index = (y * bytesPerLine) + (x >> 3);
2189        while (n > 0) {
2190            mask = 1 << (7 - (srcX & 0x7));
2191            if ((pixels[i] & 0x1) == 1) {
2192                data[index] = (byte)((data[index] & 0xFF) | mask);
2193            } else {
2194                data[index] = (byte)((data[index] & 0xFF) & (mask ^ -1));
2195            }
2196            i++;
2197            n--;
2198            srcX++;
2199            if (srcX >= width) {
2200                srcY++;
2201                index = srcY * bytesPerLine;
2202                srcX = 0;
2203            } else {
2204                if (mask == 1) {
2205                    index++;
2206                }
2207            }
2208        }
2209        return;
2210    }
2211    if (depth == 2) {
2212        byte [] masks = { (byte)0xFC, (byte)0xF3, (byte)0xCF, (byte)0x3F };
2213        index = (y * bytesPerLine) + (x >> 2);
2214        int offset = 3 - (x % 4);
2215        while (n > 0) {
2216            theByte = pixels[i] & 0x3;
2217            data[index] = (byte)((data[index] & masks[offset]) | (theByte << (offset * 2)));
2218            i++;
2219            n--;
2220            srcX++;
2221            if (srcX >= width) {
2222                srcY++;
2223                index = srcY * bytesPerLine;
2224                offset = 3;
2225                srcX = 0;
2226            } else {
2227                if (offset == 0) {
2228                    index++;
2229                    offset = 3;
2230                } else {
2231                    offset--;
2232                }
2233            }
2234        }
2235        return;
2236    }
2237    if (depth == 4) {
2238        index = (y * bytesPerLine) + (x >> 1);
2239        boolean high = (x & 0x1) == 0;
2240        while (n > 0) {
2241            theByte = pixels[i] & 0x0F;
2242            if (high) {
2243                data[index] = (byte)((data[index] & 0x0F) | (theByte << 4));
2244            } else {
2245                data[index] = (byte)((data[index] & 0xF0) | theByte);
2246            }
2247            i++;
2248            n--;
2249            srcX++;
2250            if (srcX >= width) {
2251                srcY++;
2252                index = srcY * bytesPerLine;
2253                high = true;
2254                srcX = 0;
2255            } else {
2256                if (!high) index++;
2257                high = !high;
2258            }
2259        }
2260        return;
2261    }
2262    if (depth == 8) {
2263        index = (y * bytesPerLine) + x;
2264        for (int j = 0; j < putWidth; j++) {
2265            data[index] = (byte)(pixels[i] & 0xFF);
2266            i++;
2267            srcX++;
2268            if (srcX >= width) {
2269                srcY++;
2270                index = srcY * bytesPerLine;
2271                srcX = 0;
2272            } else {
2273                index++;
2274            }
2275        }
2276        return;
2277
2278    }
2279    if (depth == 16) {
2280        index = (y * bytesPerLine) + (x * 2);
2281        for (int j = 0; j < putWidth; j++) {
2282            pixel = pixels[i];
2283            data[index] = (byte)(pixel & 0xFF);
2284            data[index + 1] = (byte)((pixel >> 8) & 0xFF);
2285            i++;
2286            srcX++;
2287            if (srcX >= width) {
2288                srcY++;
2289                index = srcY * bytesPerLine;
2290                srcX = 0;
2291            } else {
2292                index += 2;
2293            }
2294        }
2295        return;
2296    }
2297    if (depth == 24) {
2298        index = (y * bytesPerLine) + (x * 3);
2299        for (int j = 0; j < putWidth; j++) {
2300            pixel = pixels[i];
2301            data[index] = (byte)((pixel >> 16) & 0xFF);
2302            data[index + 1] = (byte)((pixel >> 8) & 0xFF);
2303            data[index + 2] = (byte)(pixel & 0xFF);
2304            i++;
2305            srcX++;
2306            if (srcX >= width) {
2307                srcY++;
2308                index = srcY * bytesPerLine;
2309                srcX = 0;
2310            } else {
2311                index += 3;
2312            }
2313        }
2314        return;
2315    }
2316    if (depth == 32) {
2317        index = (y * bytesPerLine) + (x * 4);
2318        for (int j = 0; j < putWidth; j++) {
2319            pixel = pixels[i];
2320            data[index] = (byte)((pixel >> 24) & 0xFF);
2321            data[index + 1] = (byte)((pixel >> 16) & 0xFF);
2322            data[index + 2] = (byte)((pixel >> 8) & 0xFF);
2323            data[index + 3] = (byte)(pixel & 0xFF);
2324            i++;
2325            srcX++;
2326            if (srcX >= width) {
2327                srcY++;
2328                index = srcY * bytesPerLine;
2329                srcX = 0;
2330            } else {
2331                index += 4;
2332            }
2333        }
2334        return;
2335    }
2336    SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH);
2337}
2338
2339/**
2340 * Returns a palette with 2 colors: black & white.
2341 */

2342static PaletteData bwPalette() {
2343    return new PaletteData(new RGB[] {new RGB(0, 0, 0), new RGB(255, 255, 255)});
2344}
2345
2346/**
2347 * Gets the offset of the most significant bit for
2348 * the given mask.
2349 */

2350static int getMSBOffset(int mask) {
2351    for (int i = 31; i >= 0; i--) {
2352        if (((mask >> i) & 0x1) != 0) return i + 1;
2353    }
2354    return 0;
2355}
2356
2357/**
2358 * Finds the closest match.
2359 */

2360static int closestMatch(int depth, byte red, byte green, byte blue, int redMask, int greenMask, int blueMask, byte[] reds, byte[] greens, byte[] blues) {
2361    if (depth > 8) {
2362        int rshift = 32 - getMSBOffset(redMask);
2363        int gshift = 32 - getMSBOffset(greenMask);
2364        int bshift = 32 - getMSBOffset(blueMask);
2365        return (((red << 24) >>> rshift) & redMask) |
2366            (((green << 24) >>> gshift) & greenMask) |
2367            (((blue << 24) >>> bshift) & blueMask);
2368    }
2369    int r, g, b;
2370    int minDistance = 0x7fffffff;
2371    int nearestPixel = 0;
2372    int n = reds.length;
2373    for (int j = 0; j < n; j++) {
2374        r = (reds[j] & 0xFF) - (red & 0xFF);
2375        g = (greens[j] & 0xFF) - (green & 0xFF);
2376        b = (blues[j] & 0xFF) - (blue & 0xFF);
2377        int distance = r*r + g*g + b*b;
2378        if (distance < minDistance) {
2379            nearestPixel = j;
2380            if (distance == 0) break;
2381            minDistance = distance;
2382        }
2383    }
2384    return nearestPixel;
2385}
2386
2387static final ImageData convertMask(ImageData mask) {
2388    if (mask.depth == 1) return mask;
2389    PaletteData palette = new PaletteData(new RGB[] {new RGB(0, 0, 0), new RGB(255,255,255)});
2390    ImageData newMask = new ImageData(mask.width, mask.height, 1, palette);
2391    /* Find index of black in mask palette */
2392    int blackIndex = 0;
2393    RGB[] rgbs = mask.getRGBs();
2394    if (rgbs != null) {
2395        while (blackIndex < rgbs.length) {
2396            if (rgbs[blackIndex].equals(palette.colors[0])) break;
2397            blackIndex++;
2398        }
2399    }
2400    int[] pixels = new int[mask.width];
2401    for (int y = 0; y < mask.height; y++) {
2402        mask.getPixels(0, y, mask.width, pixels, 0);
2403        for (int i = 0; i < pixels.length; i++) {
2404            if (pixels[i] == blackIndex) {
2405                pixels[i] = 0;
2406            } else {
2407                pixels[i] = 1;
2408            }
2409        }
2410        newMask.setPixels(0, y, mask.width, pixels, 0);
2411    }
2412    return newMask;
2413}
2414
2415static final byte[] convertPad(byte[] data, int width, int height, int depth, int pad, int newPad) {
2416    if (pad == newPad) return data;
2417    int stride = (width * depth + 7) / 8;
2418    int bpl = (stride + (pad - 1)) / pad * pad;
2419    int newBpl = (stride + (newPad - 1)) / newPad * newPad;
2420    byte[] newData = new byte[height * newBpl];
2421    int srcIndex = 0, destIndex = 0;
2422    for (int y = 0; y < height; y++) {
2423        System.arraycopy(data, srcIndex, newData, destIndex, stride);
2424        srcIndex += bpl;
2425        destIndex += newBpl;
2426    }
2427    return newData;
2428}
2429
2430/**
2431 * Blit operation bits to be OR'ed together to specify the desired operation.
2432 */

2433static final int
2434    BLIT_SRC = 1, // copy source directly, else applies logic operations
2435
BLIT_ALPHA = 2, // enable alpha blending
2436
BLIT_DITHER = 4; // enable dithering in low color modes
2437

2438/**
2439 * Alpha mode, values 0 - 255 specify global alpha level
2440 */

2441static final int
2442    ALPHA_OPAQUE = 255, // Fully opaque (ignores any alpha data)
2443
ALPHA_TRANSPARENT = 0, // Fully transparent (ignores any alpha data)
2444
ALPHA_CHANNEL_SEPARATE = -1, // Use alpha channel from separate alphaData
2445
ALPHA_CHANNEL_SOURCE = -2, // Use alpha channel embedded in sourceData
2446
ALPHA_MASK_UNPACKED = -3, // Use transparency mask formed by bytes in alphaData (non-zero is opaque)
2447
ALPHA_MASK_PACKED = -4, // Use transparency mask formed by packed bits in alphaData
2448
ALPHA_MASK_INDEX = -5, // Consider source palette indices transparent if in alphaData array
2449
ALPHA_MASK_RGB = -6; // Consider source RGBs transparent if in RGB888 format alphaData array
2450

2451/**
2452 * Byte and bit order constants.
2453 */

2454static final int LSB_FIRST = 0;
2455static final int MSB_FIRST = 1;
2456
2457/**
2458 * Data types (internal)
2459 */

2460private static final int
2461    // direct / true color formats with arbitrary masks & shifts
2462
TYPE_GENERIC_8 = 0,
2463    TYPE_GENERIC_16_MSB = 1,
2464    TYPE_GENERIC_16_LSB = 2,
2465    TYPE_GENERIC_24 = 3,
2466    TYPE_GENERIC_32_MSB = 4,
2467    TYPE_GENERIC_32_LSB = 5,
2468    // palette indexed color formats
2469
TYPE_INDEX_8 = 6,
2470    TYPE_INDEX_4 = 7,
2471    TYPE_INDEX_2 = 8,
2472    TYPE_INDEX_1_MSB = 9,
2473    TYPE_INDEX_1_LSB = 10;
2474
2475/**
2476 * Computes the required channel shift from a mask.
2477 */

2478static int getChannelShift(int mask) {
2479    if (mask == 0) return 0;
2480    int i;
2481    for (i = 0; ((mask & 1) == 0) && (i < 32); ++i) {
2482        mask >>>= 1;
2483    }
2484    return i;
2485}
2486
2487/**
2488 * Computes the required channel width (depth) from a mask.
2489 */

2490static int getChannelWidth(int mask, int shift) {
2491    if (mask == 0) return 0;
2492    int i;
2493    mask >>>= shift;
2494    for (i = shift; ((mask & 1) != 0) && (i < 32); ++i) {
2495        mask >>>= 1;
2496    }
2497    return i - shift;
2498}
2499
2500/**
2501 * Extracts a field from packed RGB data given a mask for that field.
2502 */

2503static byte getChannelField(int data, int mask) {
2504    final int shift = getChannelShift(mask);
2505    return ANY_TO_EIGHT[getChannelWidth(mask, shift)][(data & mask) >>> shift];
2506}
2507
2508/*
2509 * Fill in dithered gradated values for a color channel
2510 */

2511static final void buildDitheredGradientChannel(int from, int to, int steps,
2512    int bandWidth, int bandHeight, boolean vertical,
2513    byte[] bitmapData, int dp, int bytesPerLine, int bits) {
2514    final int mask = 0xff00 >>> bits;
2515    int val = from << 16;
2516    final int inc = ((to << 16) - val) / steps + 1;
2517    if (vertical) {
2518        for (int dy = 0; dy < bandHeight; ++dy, dp += bytesPerLine) {
2519            for (int dx = 0, dptr = dp; dx < bandWidth; ++dx, dptr += 4) {
2520                final int thresh = DITHER_MATRIX[dy & 7][dx] >>> bits;
2521                int temp = val + thresh;
2522                if (temp > 0xffffff) bitmapData[dptr] = -1;
2523                else bitmapData[dptr] = (byte)((temp >>> 16) & mask);
2524            }
2525            val += inc;
2526        }
2527    } else {
2528        for (int dx = 0; dx < bandWidth; ++dx, dp += 4) {
2529            for (int dy = 0, dptr = dp; dy < bandHeight; ++dy, dptr += bytesPerLine) {
2530                final int thresh = DITHER_MATRIX[dy][dx & 7] >>> bits;
2531                int temp = val + thresh;
2532                if (temp > 0xffffff) bitmapData[dptr] = -1;
2533                else bitmapData[dptr] = (byte)((temp >>> 16) & mask);
2534            }
2535            val += inc;
2536        }
2537    }
2538}
2539}
2540
2541static class LEDataInputStream extends InputStream {
2542    int position;
2543    InputStream in;
2544
2545    /**
2546     * The byte array containing the bytes to read.
2547     */

2548    protected byte[] buf;
2549    
2550    /**
2551     * The current position within the byte array <code>buf</code>. A value
2552     * equal to buf.length indicates no bytes available. A value of
2553     * 0 indicates the buffer is full.
2554     */

2555    protected int pos;
2556    
2557
2558    public LEDataInputStream(InputStream input) {
2559        this(input, 512);
2560    }
2561    
2562    public LEDataInputStream(InputStream input, int bufferSize) {
2563        this.in = input;
2564        if (bufferSize > 0) {
2565            buf = new byte[bufferSize];
2566            pos = bufferSize;
2567        }
2568        else throw new IllegalArgumentException JavaDoc();
2569    }
2570    
2571    public void close() throws IOException {
2572        buf = null;
2573        if (in != null) {
2574            in.close();
2575            in = null;
2576        }
2577    }
2578    
2579    /**
2580     * Answer how many bytes were read.
2581     */

2582    public int getPosition() {
2583        return position;
2584    }
2585    
2586    /**
2587     * Answers how many bytes are available for reading without blocking
2588     */

2589    public int available() throws IOException {
2590        if (buf == null) throw new IOException();
2591        return (buf.length - pos) + in.available();
2592    }
2593    
2594    /**
2595     * Answer the next byte of the input stream.
2596     */

2597    public int read() throws IOException {
2598        if (buf == null) throw new IOException();
2599        position++;
2600        if (pos < buf.length) return (buf[pos++] & 0xFF);
2601        return in.read();
2602    }
2603    
2604    /**
2605     * Don't imitate the JDK behaviour of reading a random number
2606     * of bytes when you can actually read them all.
2607     */

2608    public int read(byte b[], int off, int len) throws IOException {
2609        int result;
2610        int left = len;
2611        result = readData(b, off, len);
2612        while (true) {
2613            if (result == -1) return -1;
2614            position += result;
2615            if (result == left) return len;
2616            left -= result;
2617            off += result;
2618            result = readData(b, off, left);
2619        }
2620    }
2621    
2622    /**
2623     * Reads at most <code>length</code> bytes from this LEDataInputStream and
2624     * stores them in byte array <code>buffer</code> starting at <code>offset</code>.
2625     * <p>
2626     * Answer the number of bytes actually read or -1 if no bytes were read and
2627     * end of stream was encountered. This implementation reads bytes from
2628     * the pushback buffer first, then the target stream if more bytes are required
2629     * to satisfy <code>count</code>.
2630     * </p>
2631     * @param buffer the byte array in which to store the read bytes.
2632     * @param offset the offset in <code>buffer</code> to store the read bytes.
2633     * @param length the maximum number of bytes to store in <code>buffer</code>.
2634     *
2635     * @return int the number of bytes actually read or -1 if end of stream.
2636     *
2637     * @exception java.io.IOException if an IOException occurs.
2638     */

2639    private int readData(byte[] buffer, int offset, int length) throws IOException {
2640        if (buf == null) throw new IOException();
2641        if (offset < 0 || offset > buffer.length ||
2642            length < 0 || (length > buffer.length - offset)) {
2643            throw new ArrayIndexOutOfBoundsException JavaDoc();
2644            }
2645                
2646        int cacheCopied = 0;
2647        int newOffset = offset;
2648    
2649        // Are there pushback bytes available?
2650
int available = buf.length - pos;
2651        if (available > 0) {
2652            cacheCopied = (available >= length) ? length : available;
2653            System.arraycopy(buf, pos, buffer, newOffset, cacheCopied);
2654            newOffset += cacheCopied;
2655            pos += cacheCopied;
2656        }
2657    
2658        // Have we copied enough?
2659
if (cacheCopied == length) return length;
2660
2661        int inCopied = in.read(buffer, newOffset, length - cacheCopied);
2662
2663        if (inCopied > 0) return inCopied + cacheCopied;
2664        if (cacheCopied == 0) return inCopied;
2665        return cacheCopied;
2666    }
2667    
2668    /**
2669     * Answer an integer comprised of the next
2670     * four bytes of the input stream.
2671     */

2672    public int readInt() throws IOException {
2673        byte[] buf = new byte[4];
2674        read(buf);
2675        return ((((((buf[3] & 0xFF) << 8) |
2676            (buf[2] & 0xFF)) << 8) |
2677            (buf[1] & 0xFF)) << 8) |
2678            (buf[0] & 0xFF);
2679    }
2680    
2681    /**
2682     * Answer a short comprised of the next
2683     * two bytes of the input stream.
2684     */

2685    public short readShort() throws IOException {
2686        byte[] buf = new byte[2];
2687        read(buf);
2688        return (short)(((buf[1] & 0xFF) << 8) | (buf[0] & 0xFF));
2689    }
2690    
2691    /**
2692     * Push back the entire content of the given buffer <code>b</code>.
2693     * <p>
2694     * The bytes are pushed so that they would be read back b[0], b[1], etc.
2695     * If the push back buffer cannot handle the bytes copied from <code>b</code>,
2696     * an IOException will be thrown and no byte will be pushed back.
2697     * </p>
2698     *
2699     * @param b the byte array containing bytes to push back into the stream
2700     *
2701     * @exception java.io.IOException if the pushback buffer is too small
2702     */

2703    public void unread(byte[] b) throws IOException {
2704        int length = b.length;
2705        if (length > pos) throw new IOException();
2706        position -= length;
2707        pos -= length;
2708        System.arraycopy(b, 0, buf, pos, length);
2709    }
2710}
2711public static abstract class FileFormat {
2712    LEDataInputStream inputStream;
2713    ImageLoader loader;
2714    int compression;
2715
2716byte[] bitInvertData(byte[] data, int startIndex, int endIndex) {
2717    // Destructively bit invert data in the given byte array.
2718
for (int i = startIndex; i < endIndex; i++) {
2719        data[i] = (byte)(255 - data[i - startIndex]);
2720    }
2721    return data;
2722}
2723
2724/**
2725 * Return whether or not the specified input stream
2726 * represents a supported file format.
2727 */

2728abstract boolean isFileFormat(LEDataInputStream stream);
2729
2730abstract ImageData[] loadFromByteStream();
2731
2732public ImageData[] loadFromStream(LEDataInputStream stream) {
2733    try {
2734        inputStream = stream;
2735        return loadFromByteStream();
2736    } catch (Exception JavaDoc e) {
2737        SWT.error(SWT.ERROR_IO, e);
2738        return null;
2739    }
2740}
2741
2742public static ImageData[] load(InputStream is, ImageLoader loader) {
2743    LEDataInputStream stream = new LEDataInputStream(is);
2744    boolean isSupported = false;
2745    FileFormat fileFormat = new WinICOFileFormat();
2746    if (fileFormat.isFileFormat(stream)) isSupported = true;
2747    else {
2748        fileFormat = new WinBMPFileFormat();
2749        if (fileFormat.isFileFormat(stream)) isSupported = true;
2750    }
2751    if (!isSupported) SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT);
2752    fileFormat.loader = loader;
2753    return fileFormat.loadFromStream(stream);
2754}
2755}
2756static class WinBMPFileFormat extends FileFormat {
2757    static final int BMPFileHeaderSize = 14;
2758    static final int BMPHeaderFixedSize = 40;
2759    int importantColors;
2760
2761void decompressData(byte[] src, byte[] dest, int stride, int cmp) {
2762    if (cmp == 1) { // BMP_RLE8_COMPRESSION
2763
if (decompressRLE8Data(src, src.length, stride, dest, dest.length) <= 0)
2764            SWT.error(SWT.ERROR_INVALID_IMAGE);
2765        return;
2766    }
2767    if (cmp == 2) { // BMP_RLE4_COMPRESSION
2768
if (decompressRLE4Data(src, src.length, stride, dest, dest.length) <= 0)
2769            SWT.error(SWT.ERROR_INVALID_IMAGE);
2770        return;
2771    }
2772    SWT.error(SWT.ERROR_INVALID_IMAGE);
2773}
2774int decompressRLE4Data(byte[] src, int numBytes, int stride, byte[] dest, int destSize) {
2775    int sp = 0;
2776    int se = numBytes;
2777    int dp = 0;
2778    int de = destSize;
2779    int x = 0, y = 0;
2780    while (sp < se) {
2781        int len = src[sp] & 0xFF;
2782        sp++;
2783        if (len == 0) {
2784            len = src[sp] & 0xFF;
2785            sp++;
2786            switch (len) {
2787                case 0: /* end of line */
2788                    y++;
2789                    x = 0;
2790                    dp = y * stride;
2791                    if (dp >= de)
2792                        return -1;
2793                    break;
2794                case 1: /* end of bitmap */
2795                    return 1;
2796                case 2: /* delta */
2797                    x += src[sp] & 0xFF;
2798                    sp++;
2799                    y += src[sp] & 0xFF;
2800                    sp++;
2801                    dp = y * stride + x / 2;
2802                    if (dp >= de)
2803                        return -1;
2804                    break;
2805                default: /* absolute mode run */
2806                    if ((len & 1) != 0) /* odd run lengths not currently supported */
2807                        return -1;
2808                    x += len;
2809                    len = len / 2;
2810                    if (len > (se - sp))
2811                        return -1;
2812                    if (len > (de - dp))
2813                        return -1;
2814                    for (int i = 0; i < len; i++) {
2815                        dest[dp] = src[sp];
2816                        dp++;
2817                        sp++;
2818                    }
2819                    if ((sp & 1) != 0)
2820                        sp++; /* word align sp? */
2821                    break;
2822            }
2823        } else {
2824            if ((len & 1) != 0)
2825                return -1;
2826            x += len;
2827            len = len / 2;
2828            byte theByte = src[sp];
2829            sp++;
2830            if (len > (de - dp))
2831                return -1;
2832            for (int i = 0; i < len; i++) {
2833                dest[dp] = theByte;
2834                dp++;
2835            }
2836        }
2837    }
2838    return 1;
2839}
2840int decompressRLE8Data(byte[] src, int numBytes, int stride, byte[] dest, int destSize) {
2841    int sp = 0;
2842    int se = numBytes;
2843    int dp = 0;
2844    int de = destSize;
2845    int x = 0, y = 0;
2846    while (sp < se) {
2847        int len = src[sp] & 0xFF;
2848        sp++;
2849        if (len == 0) {
2850            len = src[sp] & 0xFF;
2851            sp++;
2852            switch (len) {
2853                case 0: /* end of line */
2854                    y++;
2855                    x = 0;
2856                    dp = y * stride;
2857                    if (dp >= de)
2858                        return -1;
2859                    break;
2860                case 1: /* end of bitmap */
2861                    return 1;
2862                case 2: /* delta */
2863                    x += src[sp] & 0xFF;
2864                    sp++;
2865                    y += src[sp] & 0xFF;
2866                    sp++;
2867                    dp = y * stride + x;
2868                    if (dp >= de)
2869                        return -1;
2870                    break;
2871                default: /* absolute mode run */
2872                    if (len > (se - sp))
2873                        return -1;
2874                    if (len > (de - dp))
2875                        return -1;
2876                    for (int i = 0; i < len; i++) {
2877                        dest[dp] = src[sp];
2878                        dp++;
2879                        sp++;
2880                    }
2881                    if ((sp & 1) != 0)
2882                        sp++; /* word align sp? */
2883                    x += len;
2884                    break;
2885            }
2886        } else {
2887            byte theByte = src[sp];
2888            sp++;
2889            if (len > (de - dp))
2890                return -1;
2891            for (int i = 0; i < len; i++) {
2892                dest[dp] = theByte;
2893                dp++;
2894            }
2895            x += len;
2896        }
2897    }
2898    return 1;
2899}
2900boolean isFileFormat(LEDataInputStream stream) {
2901    try {
2902        byte[] header = new byte[18];
2903        stream.read(header);
2904        stream.unread(header);
2905        int infoHeaderSize = (header[14] & 0xFF) | ((header[15] & 0xFF) << 8) | ((header[16] & 0xFF) << 16) | ((header[17] & 0xFF) << 24);
2906        return header[0] == 0x42 && header[1] == 0x4D && infoHeaderSize >= BMPHeaderFixedSize;
2907    } catch (Exception JavaDoc e) {
2908        return false;
2909    }
2910}
2911byte[] loadData(byte[] infoHeader) {
2912    int width = (infoHeader[4] & 0xFF) | ((infoHeader[5] & 0xFF) << 8) | ((infoHeader[6] & 0xFF) << 16) | ((infoHeader[7] & 0xFF) << 24);
2913    int height = (infoHeader[8] & 0xFF) | ((infoHeader[9] & 0xFF) << 8) | ((infoHeader[10] & 0xFF) << 16) | ((infoHeader[11] & 0xFF) << 24);
2914    int bitCount = (infoHeader[14] & 0xFF) | ((infoHeader[15] & 0xFF) << 8);
2915    int stride = (width * bitCount + 7) / 8;
2916    stride = (stride + 3) / 4 * 4; // Round up to 4 byte multiple
2917
byte[] data = loadData(infoHeader, stride);
2918    flipScanLines(data, stride, height);
2919    return data;
2920}
2921byte[] loadData(byte[] infoHeader, int stride) {
2922    int height = (infoHeader[8] & 0xFF) | ((infoHeader[9] & 0xFF) << 8) | ((infoHeader[10] & 0xFF) << 16) | ((infoHeader[11] & 0xFF) << 24);
2923    int dataSize = height * stride;
2924    byte[] data = new byte[dataSize];
2925    int cmp = (infoHeader[16] & 0xFF) | ((infoHeader[17] & 0xFF) << 8) | ((infoHeader[18] & 0xFF) << 16) | ((infoHeader[19] & 0xFF) << 24);
2926    if (cmp == 0) { // BMP_NO_COMPRESSION
2927
try {
2928            if (inputStream.read(data) != dataSize)
2929                SWT.error(SWT.ERROR_INVALID_IMAGE);
2930        } catch (IOException e) {
2931            SWT.error(SWT.ERROR_IO, e);
2932        }
2933    } else {
2934        int compressedSize = (infoHeader[20] & 0xFF) | ((infoHeader[21] & 0xFF) << 8) | ((infoHeader[22] & 0xFF) << 16) | ((infoHeader[23] & 0xFF) << 24);
2935        byte[] compressed = new byte[compressedSize];
2936        try {
2937            if (inputStream.read(compressed) != compressedSize)
2938                SWT.error(SWT.ERROR_INVALID_IMAGE);
2939        } catch (IOException e) {
2940            SWT.error(SWT.ERROR_IO, e);
2941        }
2942        decompressData(compressed, data, stride, cmp);
2943    }
2944    return data;
2945}
2946int[] loadFileHeader() {
2947    int[] header = new int[5];
2948    try {
2949        header[0] = inputStream.readShort();
2950        header[1] = inputStream.readInt();
2951        header[2] = inputStream.readShort();
2952        header[3] = inputStream.readShort();
2953        header[4] = inputStream.readInt();
2954    } catch (IOException e) {
2955        SWT.error(SWT.ERROR_IO, e);
2956    }
2957    if (header[0] != 0x4D42)
2958        SWT.error(SWT.ERROR_INVALID_IMAGE);
2959    return header;
2960}
2961ImageData[] loadFromByteStream() {
2962    int[] fileHeader = loadFileHeader();
2963    byte[] infoHeader = new byte[BMPHeaderFixedSize];
2964    try {
2965        inputStream.read(infoHeader);
2966    } catch (Exception JavaDoc e) {
2967        SWT.error(SWT.ERROR_IO, e);
2968    }
2969    int width = (infoHeader[4] & 0xFF) | ((infoHeader[5] & 0xFF) << 8) | ((infoHeader[6] & 0xFF) << 16) | ((infoHeader[7] & 0xFF) << 24);
2970    int height = (infoHeader[8] & 0xFF) | ((infoHeader[9] & 0xFF) << 8) | ((infoHeader[10] & 0xFF) << 16) | ((infoHeader[11] & 0xFF) << 24);
2971    int bitCount = (infoHeader[14] & 0xFF) | ((infoHeader[15] & 0xFF) << 8);
2972    PaletteData palette = loadPalette(infoHeader);
2973    if (inputStream.getPosition() < fileHeader[4]) {
2974        // Seek to the specified offset
2975
try {
2976            inputStream.skip(fileHeader[4] - inputStream.getPosition());
2977        } catch (IOException e) {
2978            SWT.error(SWT.ERROR_IO, e);
2979        }
2980    }
2981    byte[] data = loadData(infoHeader);
2982    this.compression = (infoHeader[16] & 0xFF) | ((infoHeader[17] & 0xFF) << 8) | ((infoHeader[18] & 0xFF) << 16) | ((infoHeader[19] & 0xFF) << 24);
2983    this.importantColors = (infoHeader[36] & 0xFF) | ((infoHeader[37] & 0xFF) << 8) | ((infoHeader[38] & 0xFF) << 16) | ((infoHeader[39] & 0xFF) << 24);
2984    int xPelsPerMeter = (infoHeader[24] & 0xFF) | ((infoHeader[25] & 0xFF) << 8) | ((infoHeader[26] & 0xFF) << 16) | ((infoHeader[27] & 0xFF) << 24);
2985    int yPelsPerMeter = (infoHeader[28] & 0xFF) | ((infoHeader[29] & 0xFF) << 8) | ((infoHeader[30] & 0xFF) << 16) | ((infoHeader[31] & 0xFF) << 24);
2986    int type = (this.compression == 1 /*BMP_RLE8_COMPRESSION*/) || (this.compression == 2
2987
2988/*BMP_RLE4_COMPRESSION*/) ? SWT.IMAGE_BMP_RLE : SWT.IMAGE_BMP;
2989    return new ImageData[] {
2990        ImageData.internal_new(
2991            width,
2992            height,
2993            bitCount,
2994            palette,
2995            4,
2996            data,
2997            0,
2998            null,
2999            null,
3000            -1,
3001            -1,
3002            type,
3003            0,
3004            0,
3005            0,
3006            0)
3007    };
3008}
3009PaletteData loadPalette(byte[] infoHeader) {
3010    int depth = (infoHeader[14] & 0xFF) | ((infoHeader[15] & 0xFF) << 8);
3011    if (depth <= 8) {
3012        int numColors = (infoHeader[32] & 0xFF) | ((infoHeader[33] & 0xFF) << 8) | ((infoHeader[34] & 0xFF) << 16) | ((infoHeader[35] & 0xFF) << 24);
3013        if (numColors == 0) {
3014            numColors = 1 << depth;
3015        } else {
3016            if (numColors > 256)
3017                numColors = 256;
3018        }
3019        byte[] buf = new byte[numColors * 4];
3020        try {
3021            if (inputStream.read(buf) != buf.length)
3022                SWT.error(SWT.ERROR_INVALID_IMAGE);
3023        } catch (IOException e) {
3024            SWT.error(SWT.ERROR_IO, e);
3025        }
3026        return paletteFromBytes(buf, numColors);
3027    }
3028    if (depth == 16) return new PaletteData(0x7C00, 0x3E0, 0x1F);
3029    if (depth == 24) return new PaletteData(0xFF, 0xFF00, 0xFF0000);
3030    return new PaletteData(0xFF00, 0xFF0000, 0xFF000000);
3031}
3032PaletteData paletteFromBytes(byte[] bytes, int numColors) {
3033    int bytesOffset = 0;
3034    RGB[] colors = new RGB[numColors];
3035    for (int i = 0; i < numColors; i++) {
3036        colors[i] = new RGB(bytes[bytesOffset + 2] & 0xFF,
3037            bytes[bytesOffset + 1] & 0xFF,
3038            bytes[bytesOffset] & 0xFF);
3039        bytesOffset += 4;
3040    }
3041    return new PaletteData(colors);
3042}
3043/**
3044 * Answer a byte array containing the BMP representation of
3045 * the given device independent palette.
3046 */

3047static byte[] paletteToBytes(PaletteData pal) {
3048    int n = pal.colors == null ? 0 : (pal.colors.length < 256 ? pal.colors.length : 256);
3049    byte[] bytes = new byte[n * 4];
3050    int offset = 0;
3051    for (int i = 0; i < n; i++) {
3052        RGB col = pal.colors[i];
3053        bytes[offset] = (byte)col.blue;
3054        bytes[offset + 1] = (byte)col.green;
3055        bytes[offset + 2] = (byte)col.red;
3056        offset += 4;
3057    }
3058    return bytes;
3059}
3060
3061void flipScanLines(byte[] data, int stride, int height) {
3062    int i1 = 0;
3063    int i2 = (height - 1) * stride;
3064    for (int i = 0; i < height / 2; i++) {
3065        for (int index = 0; index < stride; index++) {
3066            byte b = data[index + i1];
3067            data[index + i1] = data[index + i2];
3068            data[index + i2] = b;
3069        }
3070        i1 += stride;
3071        i2 -= stride;
3072    }
3073}
3074
3075}
3076
3077static class WinICOFileFormat extends FileFormat {
3078    
3079static final byte[] convertPad(byte[] data, int width, int height, int depth, int pad, int newPad) {
3080    if (pad == newPad) return data;
3081    int stride = (width * depth + 7) / 8;
3082    int bpl = (stride + (pad - 1)) / pad * pad;
3083    int newBpl = (stride + (newPad - 1)) / newPad * newPad;
3084    byte[] newData = new byte[height * newBpl];
3085    int srcIndex = 0, destIndex = 0;
3086    for (int y = 0; y < height; y++) {
3087        System.arraycopy(data, srcIndex, newData, destIndex, newBpl);
3088        srcIndex += bpl;
3089        destIndex += newBpl;
3090    }
3091    return newData;
3092}
3093/**
3094 * Answer the size in bytes of the file representation of the given
3095 * icon
3096 */

3097int iconSize(ImageData i) {
3098    int shapeDataStride = (i.width * i.depth + 31) / 32 * 4;
3099    int maskDataStride = (i.width + 31) / 32 * 4;
3100    int dataSize = (shapeDataStride + maskDataStride) * i.height;
3101    int paletteSize = i.palette.colors != null ? i.palette.colors.length * 4 : 0;
3102    return WinBMPFileFormat.BMPHeaderFixedSize + paletteSize + dataSize;
3103}
3104boolean isFileFormat(LEDataInputStream stream) {
3105    try {
3106        byte[] header = new byte[4];
3107        stream.read(header);
3108        stream.unread(header);
3109        return header[0] == 0 && header[1] == 0 && header[2] == 1 && header[3] == 0;
3110    } catch (Exception JavaDoc e) {
3111        return false;
3112    }
3113}
3114boolean isValidIcon(ImageData i) {
3115    switch (i.depth) {
3116        case 1:
3117        case 4:
3118        case 8:
3119            if (i.palette.isDirect) return false;
3120            int size = i.palette.colors.length;
3121            return size == 2 || size == 16 || size == 32 || size == 256;
3122        case 24:
3123        case 32:
3124            return i.palette.isDirect;
3125    }
3126    return false;
3127}
3128int loadFileHeader(LEDataInputStream byteStream) {
3129    int[] fileHeader = new int[3];
3130    try {
3131        fileHeader[0] = byteStream.readShort();
3132        fileHeader[1] = byteStream.readShort();
3133        fileHeader[2] = byteStream.readShort();
3134    } catch (IOException e) {
3135        SWT.error(SWT.ERROR_IO, e);
3136    }
3137    if ((fileHeader[0] != 0) || (fileHeader[1] != 1))
3138        SWT.error(SWT.ERROR_INVALID_IMAGE);
3139    int numIcons = fileHeader[2];
3140    if (numIcons <= 0)
3141        SWT.error(SWT.ERROR_INVALID_IMAGE);
3142    return numIcons;
3143}
3144int loadFileHeader(LEDataInputStream byteStream, boolean hasHeader) {
3145    int[] fileHeader = new int[3];
3146    try {
3147        if (hasHeader) {
3148            fileHeader[0] = byteStream.readShort();
3149            fileHeader[1] = byteStream.readShort();
3150        } else {
3151            fileHeader[0] = 0;
3152            fileHeader[1] = 1;
3153        }
3154        fileHeader[2] = byteStream.readShort();
3155    } catch (IOException e) {
3156        SWT.error(SWT.ERROR_IO, e);
3157    }
3158    if ((fileHeader[0] != 0) || (fileHeader[1] != 1))
3159        SWT.error(SWT.ERROR_INVALID_IMAGE);
3160    int numIcons = fileHeader[2];
3161    if (numIcons <= 0)
3162        SWT.error(SWT.ERROR_INVALID_IMAGE);
3163    return numIcons;
3164}
3165ImageData[] loadFromByteStream() {
3166    int numIcons = loadFileHeader(inputStream);
3167    int[][] headers = loadIconHeaders(numIcons);
3168    ImageData[] icons = new ImageData[headers.length];
3169    for (int i = 0; i < icons.length; i++) {
3170        icons[i] = loadIcon(headers[i]);
3171    }
3172    return icons;
3173}
3174/**
3175 * Load one icon from the byte stream.
3176 */

3177ImageData loadIcon(int[] iconHeader) {
3178    byte[] infoHeader = loadInfoHeader(iconHeader);
3179    WinBMPFileFormat bmpFormat = new WinBMPFileFormat();
3180    bmpFormat.inputStream = inputStream;
3181    PaletteData palette = bmpFormat.loadPalette(infoHeader);
3182    byte[] shapeData = bmpFormat.loadData(infoHeader);
3183    int width = (infoHeader[4] & 0xFF) | ((infoHeader[5] & 0xFF) << 8) | ((infoHeader[6] & 0xFF) << 16) | ((infoHeader[7] & 0xFF) << 24);
3184    int height = (infoHeader[8] & 0xFF) | ((infoHeader[9] & 0xFF) << 8) | ((infoHeader[10] & 0xFF) << 16) | ((infoHeader[11] & 0xFF) << 24);
3185    int depth = (infoHeader[14] & 0xFF) | ((infoHeader[15] & 0xFF) << 8);
3186    infoHeader[14] = 1;
3187    infoHeader[15] = 0;
3188    byte[] maskData = bmpFormat.loadData(infoHeader);
3189    maskData = convertPad(maskData, width, height, 1, 4, 2);
3190    bitInvertData(maskData, 0, maskData.length);
3191    return ImageData.internal_new(
3192        width,
3193        height,
3194        depth,
3195        palette,
3196        4,
3197        shapeData,
3198        2,
3199        maskData,
3200        null,
3201        -1,
3202        -1,
3203        SWT.IMAGE_ICO,
3204        0,
3205        0,
3206        0,
3207        0);
3208}
3209int[][] loadIconHeaders(int numIcons) {
3210    int[][] headers = new int[numIcons][7];
3211    try {
3212        for (int i = 0; i < numIcons; i++) {
3213            headers[i][0] = inputStream.read();
3214            headers[i][1] = inputStream.read();
3215            headers[i][2] = inputStream.readShort();
3216            headers[i][3] = inputStream.readShort();
3217            headers[i][4] = inputStream.readShort();
3218            headers[i][5] = inputStream.readInt();
3219            headers[i][6] = inputStream.readInt();
3220        }
3221    } catch (IOException e) {
3222        SWT.error(SWT.ERROR_IO, e);
3223    }
3224    return headers;
3225}
3226byte[] loadInfoHeader(int[] iconHeader) {
3227    int width = iconHeader[0];
3228    int height = iconHeader[1];
3229    int numColors = iconHeader[2]; // the number of colors is in the low byte, but the high byte must be 0
3230
if (numColors == 0) numColors = 256; // this is specified: '00' represents '256' (0x100) colors
3231
if ((numColors != 2) && (numColors != 8) && (numColors != 16) &&
3232        (numColors != 32) && (numColors != 256))
3233        SWT.error(SWT.ERROR_INVALID_IMAGE);
3234    if (inputStream.getPosition() < iconHeader[6]) {
3235        // Seek to the specified offset
3236
try {
3237            inputStream.skip(iconHeader[6] - inputStream.getPosition());
3238        } catch (IOException e) {
3239            SWT.error(SWT.ERROR_IO, e);
3240            return null;
3241        }
3242    }
3243    byte[] infoHeader = new byte[WinBMPFileFormat.BMPHeaderFixedSize];
3244    try {
3245        inputStream.read(infoHeader);
3246    } catch (IOException e) {
3247        SWT.error(SWT.ERROR_IO, e);
3248    }
3249    if (((infoHeader[12] & 0xFF) | ((infoHeader[13] & 0xFF) << 8)) != 1)
3250        SWT.error(SWT.ERROR_INVALID_IMAGE);
3251    int infoWidth = (infoHeader[4] & 0xFF) | ((infoHeader[5] & 0xFF) << 8) | ((infoHeader[6] & 0xFF) << 16) | ((infoHeader[7] & 0xFF) << 24);
3252    int infoHeight = (infoHeader[8] & 0xFF) | ((infoHeader[9] & 0xFF) << 8) | ((infoHeader[10] & 0xFF) << 16) | ((infoHeader[11] & 0xFF) << 24);
3253    int bitCount = (infoHeader[14] & 0xFF) | ((infoHeader[15] & 0xFF) << 8);
3254    if (height == infoHeight && bitCount == 1) height /= 2;
3255    if (!((width == infoWidth) && (height * 2 == infoHeight) &&
3256        (bitCount == 1 || bitCount == 4 || bitCount == 8 || bitCount == 24 || bitCount == 32)))
3257            SWT.error(SWT.ERROR_INVALID_IMAGE);
3258    infoHeader[8] = (byte)(height & 0xFF);
3259    infoHeader[9] = (byte)((height >> 8) & 0xFF);
3260    infoHeader[10] = (byte)((height >> 16) & 0xFF);
3261    infoHeader[11] = (byte)((height >> 24) & 0xFF);
3262    return infoHeader;
3263}
3264}
3265static class SWT {
3266    public static final int IMAGE_ICO = 3;
3267    public static final int ERROR_IO = 39;
3268    public static final int ERROR_INVALID_IMAGE = 40;
3269    public static final int ERROR_NULL_ARGUMENT = 4;
3270    public static final int ERROR_INVALID_ARGUMENT = 5;
3271    public static final int ERROR_CANNOT_BE_ZERO = 7;
3272    public static final int IMAGE_UNDEFINED = -1;
3273    public static final int ERROR_UNSUPPORTED_DEPTH = 38;
3274    public static final int TRANSPARENCY_MASK = 1 << 1;
3275    public static final int ERROR_UNSUPPORTED_FORMAT = 42;
3276    public static final int TRANSPARENCY_ALPHA = 1 << 0;
3277    public static final int TRANSPARENCY_NONE = 0x0;
3278    public static final int TRANSPARENCY_PIXEL = 1 << 2;
3279    public static final int IMAGE_BMP = 0;
3280    public static final int IMAGE_BMP_RLE = 1;
3281    
3282    public static void error(int code) {
3283        throw new RuntimeException JavaDoc("Error "+code);
3284    }
3285    public static void error(int code, Throwable JavaDoc t) {
3286        throw new RuntimeException JavaDoc(t);
3287    }
3288}
3289}
3290
Popular Tags