1 11 package org.eclipse.pde.internal.swt.tools; 12 13 import java.io.*; 14 import java.util.*; 15 16 24 public class IconExe { 25 26 51 public static void main(String [] args) throws Exception { 52 if (args.length < 2) { 53 System.err.println("Usage: IconExe <windows executable> <ico file>"); 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 ImageData[] current = loader.load(args[i]); 63 for (int j = 0; j < current.length; j++) { 64 images.add(current[j]); 65 } 66 } catch (RuntimeException e) { 67 } 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]); } 77 78 79 80 94 static ImageData[] loadIcons(String program) throws FileNotFoundException, IOException { 95 RandomAccessFile raf = new RandomAccessFile(program, "r"); 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 134 static int unloadIcons(String program, ImageData[] icons) throws FileNotFoundException, IOException { 135 RandomAccessFile raf = new RandomAccessFile(program, "rw"); 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 VERSION = "20050124"; 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 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+")"); 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 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); 210 IMAGE_RESOURCE_DIRECTORY imageResourceDirectory = new IMAGE_RESOURCE_DIRECTORY(); 211 raf.seek(imageResourceDirectoryOffset); 212 read(raf, imageResourceDirectory); 213 214 if (DEBUG) { 215 String sType = ""+type; if (level == 1) { 218 System.out.println("___________________________"); if (type == RT_ICON) sType = "RT_ICON"; if (type == RT_GROUP_ICON) sType = "RT_GROUP_ICON"; } 222 System.out.println("Resource Directory ["+sType+"]"+" (Named "+imageResourceDirectory.NumberOfNamedEntries+", ID "+imageResourceDirectory.NumberOfIdEntries+")"); } 224 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 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); if (rt_icon_root) { 242 if (DEBUG) System.out.println("iconcnt "+iconCnt+" |"+iconInfo.length); 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 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; 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) { raf.read(data); 369 } else { 370 if (DEBUG) System.out.println("ICO cannot be compressed?"); } 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 src, String dst) throws FileNotFoundException, IOException { 460 File srcFile = new File(src); 461 File dstFile = new File(dst); 462 InputStream in = new BufferedInputStream(new FileInputStream(srcFile)); 463 OutputStream out = new BufferedOutputStream(new FileOutputStream(dstFile)); 464 int c; 465 while ((c = in.read()) != -1) out.write(c); 466 in.close(); 467 out.close(); 468 } 469 470 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; int e_cblp; int e_cp; int e_crlc; int e_cparhdr; int e_minalloc; int e_maxalloc; int e_ss; int e_sp; int e_csum; int e_ip; int e_cs; int e_lfarlc; int e_ovno; int[] e_res = new int[4]; int e_oemid; int e_oeminfo; int[] e_res2 = new int[10]; int e_lfanew; } 500 501 public static class IMAGE_FILE_HEADER { 502 int Machine; int NumberOfSections; int TimeDateStamp; int PointerToSymbolTable; int NumberOfSymbols; int SizeOfOptionalHeader; int Characteristics; } 510 511 public static class IMAGE_DATA_DIRECTORY { 512 int VirtualAddress; int Size; } 515 516 public static class IMAGE_OPTIONAL_HEADER { 517 int Magic; int MajorLinkerVersion; int MinorLinkerVersion; int SizeOfCode; int SizeOfInitializedData; int SizeOfUninitializedData; int AddressOfEntryPoint; int BaseOfCode; int BaseOfData; int ImageBase; int SectionAlignment; int FileAlignment; int MajorOperatingSystemVersion; int MinorOperatingSystemVersion; int MajorImageVersion; int MinorImageVersion; int MajorSubsystemVersion; int MinorSubsystemVersion; int Win32VersionValue; int SizeOfImage; int SizeOfHeaders; int CheckSum; int Subsystem; int DllCharacteristics; int SizeOfStackReserve; int SizeOfStackCommit; int SizeOfHeapReserve; int SizeOfHeapCommit; int LoaderFlags; int NumberOfRvaAndSizes; IMAGE_DATA_DIRECTORY[] DataDirectory = new IMAGE_DATA_DIRECTORY[16]; 548 } 549 public static class IMAGE_NT_HEADERS { 550 int Signature; 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]; int Misc_VirtualSize; int VirtualAddress; int SizeOfRawData; int PointerToRawData; int PointerToRelocations; int PointerToLinenumbers; int NumberOfRelocations; int NumberOfLinenumbers; int Characteristics; } 568 569 public static class IMAGE_RESOURCE_DIRECTORY { 570 int Characteristics; int TimeDateStamp; int MajorVersion; int MinorVersion; int NumberOfNamedEntries; int NumberOfIdEntries; final static int SIZEOF = 16; 577 } 578 579 public static class IMAGE_RESOURCE_DIRECTORY_ENTRY { 580 int NameOffset; boolean NameIsString; int Name; int Id; int OffsetToData; int OffsetToDirectory; boolean DataIsDirectory; } 590 591 public static class IMAGE_RESOURCE_DATA_ENTRY { 592 int OffsetToData; int Size; int CodePage; int Reserved; } 597 598 public static class NEWHEADER { 599 int Reserved; int ResType; int ResCount; } 603 604 public static class ICONRESDIR { 605 int Width; int Height; int ColorCount; int reserved; } 610 611 public static class CURSORDIR { 612 int Width; int Height; } 615 616 public static class RESDIR { 617 ICONRESDIR Icon = new ICONRESDIR(); 619 CURSORDIR Cursor = new CURSORDIR(); 620 int Planes; int BitCount; int BytesInRes; int IconCursorId; } 625 626 public static class BITMAPINFOHEADER { 627 int biSize; int biWidth; int biHeight; int biPlanes; int biBitCount; int biCompression; int biSizeImage; int biXPelsPerMeter; int biYPelsPerMeter; int biClrUsed; int biClrImportant; } 639 640 static class RGBQUAD { 641 int rgBlue; int rgbGreen; int rgbRed; int rgbReserved; } 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 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 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 829 830 static class RGB { 831 832 835 public int red; 836 837 840 public int green; 841 842 845 public int blue; 846 847 static final long serialVersionUID = 3258415023461249074L; 848 849 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 881 public boolean equals (Object 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 898 public int hashCode () { 899 return (blue << 16) | (green << 8) | red; 900 } 901 902 908 public String toString () { 909 return "RGB {" + red + ", " + green + ", " + blue + "}"; 911 } 913 914 } 915 static class PaletteData { 916 917 921 public boolean isDirect; 922 923 927 public RGB[] colors; 928 929 932 public int redMask; 933 934 937 public int greenMask; 938 939 942 public int blueMask; 943 944 947 public int redShift; 948 949 952 public int greenShift; 953 954 957 public int blueShift; 958 959 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 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 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 } 1011 1012 for (int i = 0; i < colors.length; i++) { 1013 if (colors[i].equals(rgb)) return i; 1014 } 1015 1016 SWT.error(SWT.ERROR_INVALID_ARGUMENT); 1017 return 0; 1018} 1019 1020 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 } 1041 if (pixel < 0 || pixel >= colors.length) { 1042 SWT.error(SWT.ERROR_INVALID_ARGUMENT); 1043 } 1044 return colors[pixel]; 1045} 1046 1047 1053public RGB[] getRGBs() { 1054 return colors; 1055} 1056 1057 1065int shiftForMask(int mask) { 1066 for (int i = 31; i >= 0; i--) { 1067 if (((mask >> i) & 0x1) != 0) return 7 - i; 1068 } 1069 return 32; 1070} 1071 1072} 1073static class ImageLoader { 1074 1075 1080 public ImageData[] data; 1081 1082 1087 public int logicalScreenWidth; 1088 1089 1094 public int logicalScreenHeight; 1095 1096 1102 public int backgroundPixel; 1103 1104 1109 public int repeatCount; 1110 1111 1114 Vector imageLoaderListeners; 1115 1116 1119public ImageLoader() { 1120 reset(); 1121} 1122 1123 1127void reset() { 1128 data = null; 1129 logicalScreenWidth = 0; 1130 logicalScreenHeight = 0; 1131 backgroundPixel = -1; 1132 repeatCount = 1; 1133} 1134 1135 1153public ImageData[] load(InputStream stream) { 1154 if (stream == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); 1155 reset(); 1156 data = FileFormat.load(stream, this); 1157 return data; 1158} 1159 1160 1178public ImageData[] load(String filename) { 1179 if (filename == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); 1180 InputStream stream = null; 1181 try { 1182 stream = new BufferedInputStream(new FileInputStream(filename)); 1183 return load(stream); 1184 } catch (IOException e) { 1185 SWT.error(SWT.ERROR_IO, e); 1186 } finally { 1187 try { 1188 if (stream != null) stream.close(); 1189 } catch (IOException e) { 1190 } 1192 } 1193 return null; 1194} 1195} 1196static class ImageData { 1197 1198 1201 public int width; 1202 1203 1206 public int height; 1207 1208 1217 public int depth; 1218 1219 1226 public int scanlinePad; 1227 1228 1234 public int bytesPerLine; 1235 1236 1245 public byte[] data; 1246 1247 1250 public PaletteData palette; 1251 1252 1260 public int transparentPixel; 1261 1262 1272 public byte[] maskData; 1273 1274 1282 public int maskPad; 1283 1284 1293 public byte[] alphaData; 1294 1295 1306 public int alpha; 1307 1308 1327 public int type; 1328 1329 1334 public int x; 1335 1336 1341 public int y; 1342 1343 1360 public int disposalMethod; 1361 1362 1367 public int delayTime; 1368 1369 1372 static final byte[][] ANY_TO_EIGHT = new byte[9][]; 1373 static { 1374 for (int b = 0; b < 9; ++b) { 1375 byte[] data = ANY_TO_EIGHT[b] = new byte[1 << b]; 1376 if (b == 0) continue; 1377 int inc = 0; 1378 for (int bit = 0x10000; (bit >>= b) != 0;) inc |= bit; 1379 for (int v = 0, p = 0; v < 0x10000; v+= inc) data[p++] = (byte)(v >> 8); 1380 } 1381 } 1382 static final byte[] ONE_TO_ONE_MAPPING = ANY_TO_EIGHT[8]; 1383 1384 1387 static final int[][] DITHER_MATRIX = { 1388 { 0xfc0000, 0x7c0000, 0xdc0000, 0x5c0000, 0xf40000, 0x740000, 0xd40000, 0x540000 }, 1389 { 0x3c0000, 0xbc0000, 0x1c0000, 0x9c0000, 0x340000, 0xb40000, 0x140000, 0x940000 }, 1390 { 0xcc0000, 0x4c0000, 0xec0000, 0x6c0000, 0xc40000, 0x440000, 0xe40000, 0x640000 }, 1391 { 0x0c0000, 0x8c0000, 0x2c0000, 0xac0000, 0x040000, 0x840000, 0x240000, 0xa40000 }, 1392 { 0xf00000, 0x700000, 0xd00000, 0x500000, 0xf80000, 0x780000, 0xd80000, 0x580000 }, 1393 { 0x300000, 0xb00000, 0x100000, 0x900000, 0x380000, 0xb80000, 0x180000, 0x980000 }, 1394 { 0xc00000, 0x400000, 0xe00000, 0x600000, 0xc80000, 0x480000, 0xe80000, 0x680000 }, 1395 { 0x000000, 0x800000, 0x200000, 0xa00000, 0x080000, 0x880000, 0x280000, 0xa80000 } 1396 }; 1397 1398 1414public ImageData(int width, int height, int depth, PaletteData palette) { 1415 this(width, height, depth, palette, 1416 4, null, 0, null, 1417 null, -1, -1, SWT.IMAGE_UNDEFINED, 1418 0, 0, 0, 0); 1419} 1420 1421 1439public ImageData(int width, int height, int depth, PaletteData palette, int scanlinePad, byte[] data) { 1440 this(width, height, depth, palette, 1441 scanlinePad, checkData(data), 0, null, 1442 null, -1, -1, SWT.IMAGE_UNDEFINED, 1443 0, 0, 0, 0); 1444} 1445 1446 1468public ImageData(String filename) { 1469 ImageData[] data = new ImageLoader().load(filename); 1470 if (data.length < 1) SWT.error(SWT.ERROR_INVALID_IMAGE); 1471 ImageData i = data[0]; 1472 setAllFields( 1473 i.width, 1474 i.height, 1475 i.depth, 1476 i.scanlinePad, 1477 i.bytesPerLine, 1478 i.data, 1479 i.palette, 1480 i.transparentPixel, 1481 i.maskData, 1482 i.maskPad, 1483 i.alphaData, 1484 i.alpha, 1485 i.type, 1486 i.x, 1487 i.y, 1488 i.disposalMethod, 1489 i.delayTime); 1490} 1491 1492 1495ImageData() { 1496 } 1498 1499 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 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 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 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 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 1987public RGB[] getRGBs() { 1988 return palette.getRGBs(); 1989} 1990 1991 1998public ImageData getTransparencyMask() { 1999 if (getTransparencyType() == SWT.TRANSPARENCY_MASK) { 2000 return new ImageData(width, height, 1, bwPalette(), maskPad, maskData); 2001 } 2002 return colorMaskImage(transparentPixel); 2003} 2004 2005 2010public int getTransparencyType() { 2011 if (maskData != null) return SWT.TRANSPARENCY_MASK; 2012 if (transparentPixel != -1) return SWT.TRANSPARENCY_PIXEL; 2013 if (alphaData != null) return SWT.TRANSPARENCY_ALPHA; 2014 return SWT.TRANSPARENCY_NONE; 2015} 2016 2017 2022int getByteOrder() { 2023 return depth != 16 ? MSB_FIRST : LSB_FIRST; 2024} 2025 2026 2049public void setPixels(int x, int y, int putWidth, byte[] pixels, int startIndex) { 2050 if (pixels == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); 2051 if (putWidth < 0 || x >= width || y >= height || x < 0 || y < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT); 2052 if (putWidth == 0) return; 2053 int index; 2054 int theByte; 2055 int mask; 2056 int n = putWidth; 2057 int i = startIndex; 2058 int srcX = x, srcY = y; 2059 if (depth == 1) { 2060 index = (y * bytesPerLine) + (x >> 3); 2061 while (n > 0) { 2062 mask = 1 << (7 - (srcX & 0x7)); 2063 if ((pixels[i] & 0x1) == 1) { 2064 data[index] = (byte)((data[index] & 0xFF) | mask); 2065 } else { 2066 data[index] = (byte)((data[index] & 0xFF) & (mask ^ -1)); 2067 } 2068 i++; 2069 n--; 2070 srcX++; 2071 if (srcX >= width) { 2072 srcY++; 2073 index = srcY * bytesPerLine; 2074 srcX = 0; 2075 } else { 2076 if (mask == 1) { 2077 index++; 2078 } 2079 } 2080 } 2081 return; 2082 } 2083 if (depth == 2) { 2084 byte [] masks = { (byte)0xFC, (byte)0xF3, (byte)0xCF, (byte)0x3F }; 2085 index = (y * bytesPerLine) + (x >> 2); 2086 int offset = 3 - (x % 4); 2087 while (n > 0) { 2088 theByte = pixels[i] & 0x3; 2089 data[index] = (byte)((data[index] & masks[offset]) | (theByte << (offset * 2))); 2090 i++; 2091 n--; 2092 srcX++; 2093 if (srcX >= width) { 2094 srcY++; 2095 index = srcY * bytesPerLine; 2096 offset = 0; 2097 srcX = 0; 2098 } else { 2099 if (offset == 0) { 2100 index++; 2101 offset = 3; 2102 } else { 2103 offset--; 2104 } 2105 } 2106 } 2107 return; 2108 } 2109 if (depth == 4) { 2110 index = (y * bytesPerLine) + (x >> 1); 2111 boolean high = (x & 0x1) == 0; 2112 while (n > 0) { 2113 theByte = pixels[i] & 0x0F; 2114 if (high) { 2115 data[index] = (byte)((data[index] & 0x0F) | (theByte << 4)); 2116 } else { 2117 data[index] = (byte)((data[index] & 0xF0) | theByte); 2118 } 2119 i++; 2120 n--; 2121 srcX++; 2122 if (srcX >= width) { 2123 srcY++; 2124 index = srcY * bytesPerLine; 2125 high = true; 2126 srcX = 0; 2127 } else { 2128 if (!high) index++; 2129 high = !high; 2130 } 2131 } 2132 return; 2133 } 2134 if (depth == 8) { 2135 index = (y * bytesPerLine) + x; 2136 for (int j = 0; j < putWidth; j++) { 2137 data[index] = (byte)(pixels[i] & 0xFF); 2138 i++; 2139 srcX++; 2140 if (srcX >= width) { 2141 srcY++; 2142 index = srcY * bytesPerLine; 2143 srcX = 0; 2144 } else { 2145 index++; 2146 } 2147 } 2148 return; 2149 } 2150 SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH); 2151} 2152 2153 2175public void setPixels(int x, int y, int putWidth, int[] pixels, int startIndex) { 2176 if (pixels == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); 2177 if (putWidth < 0 || x >= width || y >= height || x < 0 || y < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT); 2178 if (putWidth == 0) return; 2179 int index; 2180 int theByte; 2181 int mask; 2182 int n = putWidth; 2183 int i = startIndex; 2184 int pixel; 2185 int srcX = x, srcY = y; 2186 if (depth == 1) { 2187 index = (y * bytesPerLine) + (x >> 3); 2188 while (n > 0) { 2189 mask = 1 << (7 - (srcX & 0x7)); 2190 if ((pixels[i] & 0x1) == 1) { 2191 data[index] = (byte)((data[index] & 0xFF) | mask); 2192 } else { 2193 data[index] = (byte)((data[index] & 0xFF) & (mask ^ -1)); 2194 } 2195 i++; 2196 n--; 2197 srcX++; 2198 if (srcX >= width) { 2199 srcY++; 2200 index = srcY * bytesPerLine; 2201 srcX = 0; 2202 } else { 2203 if (mask == 1) { 2204 index++; 2205 } 2206 } 2207 } 2208 return; 2209 } 2210 if (depth == 2) { 2211 byte [] masks = { (byte)0xFC, (byte)0xF3, (byte)0xCF, (byte)0x3F }; 2212 index = (y * bytesPerLine) + (x >> 2); 2213 int offset = 3 - (x % 4); 2214 while (n > 0) { 2215 theByte = pixels[i] & 0x3; 2216 data[index] = (byte)((data[index] & masks[offset]) | (theByte << (offset * 2))); 2217 i++; 2218 n--; 2219 srcX++; 2220 if (srcX >= width) { 2221 srcY++; 2222 index = srcY * bytesPerLine; 2223 offset = 3; 2224 srcX = 0; 2225 } else { 2226 if (offset == 0) { 2227 index++; 2228 offset = 3; 2229 } else { 2230 offset--; 2231 } 2232 } 2233 } 2234 return; 2235 } 2236 if (depth == 4) { 2237 index = (y * bytesPerLine) + (x >> 1); 2238 boolean high = (x & 0x1) == 0; 2239 while (n > 0) { 2240 theByte = pixels[i] & 0x0F; 2241 if (high) { 2242 data[index] = (byte)((data[index] & 0x0F) | (theByte << 4)); 2243 } else { 2244 data[index] = (byte)((data[index] & 0xF0) | theByte); 2245 } 2246 i++; 2247 n--; 2248 srcX++; 2249 if (srcX >= width) { 2250 srcY++; 2251 index = srcY * bytesPerLine; 2252 high = true; 2253 srcX = 0; 2254 } else { 2255 if (!high) index++; 2256 high = !high; 2257 } 2258 } 2259 return; 2260 } 2261 if (depth == 8) { 2262 index = (y * bytesPerLine) + x; 2263 for (int j = 0; j < putWidth; j++) { 2264 data[index] = (byte)(pixels[i] & 0xFF); 2265 i++; 2266 srcX++; 2267 if (srcX >= width) { 2268 srcY++; 2269 index = srcY * bytesPerLine; 2270 srcX = 0; 2271 } else { 2272 index++; 2273 } 2274 } 2275 return; 2276 2277 } 2278 if (depth == 16) { 2279 index = (y * bytesPerLine) + (x * 2); 2280 for (int j = 0; j < putWidth; j++) { 2281 pixel = pixels[i]; 2282 data[index] = (byte)(pixel & 0xFF); 2283 data[index + 1] = (byte)((pixel >> 8) & 0xFF); 2284 i++; 2285 srcX++; 2286 if (srcX >= width) { 2287 srcY++; 2288 index = srcY * bytesPerLine; 2289 srcX = 0; 2290 } else { 2291 index += 2; 2292 } 2293 } 2294 return; 2295 } 2296 if (depth == 24) { 2297 index = (y * bytesPerLine) + (x * 3); 2298 for (int j = 0; j < putWidth; j++) { 2299 pixel = pixels[i]; 2300 data[index] = (byte)((pixel >> 16) & 0xFF); 2301 data[index + 1] = (byte)((pixel >> 8) & 0xFF); 2302 data[index + 2] = (byte)(pixel & 0xFF); 2303 i++; 2304 srcX++; 2305 if (srcX >= width) { 2306 srcY++; 2307 index = srcY * bytesPerLine; 2308 srcX = 0; 2309 } else { 2310 index += 3; 2311 } 2312 } 2313 return; 2314 } 2315 if (depth == 32) { 2316 index = (y * bytesPerLine) + (x * 4); 2317 for (int j = 0; j < putWidth; j++) { 2318 pixel = pixels[i]; 2319 data[index] = (byte)((pixel >> 24) & 0xFF); 2320 data[index + 1] = (byte)((pixel >> 16) & 0xFF); 2321 data[index + 2] = (byte)((pixel >> 8) & 0xFF); 2322 data[index + 3] = (byte)(pixel & 0xFF); 2323 i++; 2324 srcX++; 2325 if (srcX >= width) { 2326 srcY++; 2327 index = srcY * bytesPerLine; 2328 srcX = 0; 2329 } else { 2330 index += 4; 2331 } 2332 } 2333 return; 2334 } 2335 SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH); 2336} 2337 2338 2341static PaletteData bwPalette() { 2342 return new PaletteData(new RGB[] {new RGB(0, 0, 0), new RGB(255, 255, 255)}); 2343} 2344 2345 2349static int getMSBOffset(int mask) { 2350 for (int i = 31; i >= 0; i--) { 2351 if (((mask >> i) & 0x1) != 0) return i + 1; 2352 } 2353 return 0; 2354} 2355 2356 2359static int closestMatch(int depth, byte red, byte green, byte blue, int redMask, int greenMask, int blueMask, byte[] reds, byte[] greens, byte[] blues) { 2360 if (depth > 8) { 2361 int rshift = 32 - getMSBOffset(redMask); 2362 int gshift = 32 - getMSBOffset(greenMask); 2363 int bshift = 32 - getMSBOffset(blueMask); 2364 return (((red << 24) >>> rshift) & redMask) | 2365 (((green << 24) >>> gshift) & greenMask) | 2366 (((blue << 24) >>> bshift) & blueMask); 2367 } 2368 int r, g, b; 2369 int minDistance = 0x7fffffff; 2370 int nearestPixel = 0; 2371 int n = reds.length; 2372 for (int j = 0; j < n; j++) { 2373 r = (reds[j] & 0xFF) - (red & 0xFF); 2374 g = (greens[j] & 0xFF) - (green & 0xFF); 2375 b = (blues[j] & 0xFF) - (blue & 0xFF); 2376 int distance = r*r + g*g + b*b; 2377 if (distance < minDistance) { 2378 nearestPixel = j; 2379 if (distance == 0) break; 2380 minDistance = distance; 2381 } 2382 } 2383 return nearestPixel; 2384} 2385 2386static final ImageData convertMask(ImageData mask) { 2387 if (mask.depth == 1) return mask; 2388 PaletteData palette = new PaletteData(new RGB[] {new RGB(0, 0, 0), new RGB(255,255,255)}); 2389 ImageData newMask = new ImageData(mask.width, mask.height, 1, palette); 2390 2391 int blackIndex = 0; 2392 RGB[] rgbs = mask.getRGBs(); 2393 if (rgbs != null) { 2394 while (blackIndex < rgbs.length) { 2395 if (rgbs[blackIndex].equals(palette.colors[0])) break; 2396 blackIndex++; 2397 } 2398 } 2399 int[] pixels = new int[mask.width]; 2400 for (int y = 0; y < mask.height; y++) { 2401 mask.getPixels(0, y, mask.width, pixels, 0); 2402 for (int i = 0; i < pixels.length; i++) { 2403 if (pixels[i] == blackIndex) { 2404 pixels[i] = 0; 2405 } else { 2406 pixels[i] = 1; 2407 } 2408 } 2409 newMask.setPixels(0, y, mask.width, pixels, 0); 2410 } 2411 return newMask; 2412} 2413 2414static final byte[] convertPad(byte[] data, int width, int height, int depth, int pad, int newPad) { 2415 if (pad == newPad) return data; 2416 int stride = (width * depth + 7) / 8; 2417 int bpl = (stride + (pad - 1)) / pad * pad; 2418 int newBpl = (stride + (newPad - 1)) / newPad * newPad; 2419 byte[] newData = new byte[height * newBpl]; 2420 int srcIndex = 0, destIndex = 0; 2421 for (int y = 0; y < height; y++) { 2422 System.arraycopy(data, srcIndex, newData, destIndex, stride); 2423 srcIndex += bpl; 2424 destIndex += newBpl; 2425 } 2426 return newData; 2427} 2428 2429 2432static final int 2433 BLIT_SRC = 1, BLIT_ALPHA = 2, BLIT_DITHER = 4; 2437 2440static final int 2441 ALPHA_OPAQUE = 255, ALPHA_TRANSPARENT = 0, ALPHA_CHANNEL_SEPARATE = -1, ALPHA_CHANNEL_SOURCE = -2, ALPHA_MASK_UNPACKED = -3, ALPHA_MASK_PACKED = -4, ALPHA_MASK_INDEX = -5, ALPHA_MASK_RGB = -6; 2450 2453static final int LSB_FIRST = 0; 2454static final int MSB_FIRST = 1; 2455 2456 2459 2475 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 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 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 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 2548 protected byte[] buf; 2549 2550 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 (); 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 2582 public int getPosition() { 2583 return position; 2584 } 2585 2586 2589 public int available() throws IOException { 2590 if (buf == null) throw new IOException(); 2591 return (buf.length - pos) + in.available(); 2592 } 2593 2594 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 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 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 (); 2644 } 2645 2646 int cacheCopied = 0; 2647 int newOffset = offset; 2648 2649 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 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 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 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 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 for (int i = startIndex; i < endIndex; i++) { 2719 data[i] = (byte)(255 - data[i - startIndex]); 2720 } 2721 return data; 2722} 2723 2724 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 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) { if (decompressRLE8Data(src, src.length, stride, dest, dest.length) <= 0) 2764 SWT.error(SWT.ERROR_INVALID_IMAGE); 2765 return; 2766 } 2767 if (cmp == 2) { 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: 2788 y++; 2789 x = 0; 2790 dp = y * stride; 2791 if (dp >= de) 2792 return -1; 2793 break; 2794 case 1: 2795 return 1; 2796 case 2: 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: 2806 if ((len & 1) != 0) 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++; 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: 2854 y++; 2855 x = 0; 2856 dp = y * stride; 2857 if (dp >= de) 2858 return -1; 2859 break; 2860 case 1: 2861 return 1; 2862 case 2: 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: 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++; 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 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; 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) { 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 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 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 type = (this.compression == 1 ) || (this.compression == 2 ) ? SWT.IMAGE_BMP_RLE : SWT.IMAGE_BMP; 2987 return new ImageData[] { 2988 ImageData.internal_new( 2989 width, 2990 height, 2991 bitCount, 2992 palette, 2993 4, 2994 data, 2995 0, 2996 null, 2997 null, 2998 -1, 2999 -1, 3000 type, 3001 0, 3002 0, 3003 0, 3004 0) 3005 }; 3006} 3007PaletteData loadPalette(byte[] infoHeader) { 3008 int depth = (infoHeader[14] & 0xFF) | ((infoHeader[15] & 0xFF) << 8); 3009 if (depth <= 8) { 3010 int numColors = (infoHeader[32] & 0xFF) | ((infoHeader[33] & 0xFF) << 8) | ((infoHeader[34] & 0xFF) << 16) | ((infoHeader[35] & 0xFF) << 24); 3011 if (numColors == 0) { 3012 numColors = 1 << depth; 3013 } else { 3014 if (numColors > 256) 3015 numColors = 256; 3016 } 3017 byte[] buf = new byte[numColors * 4]; 3018 try { 3019 if (inputStream.read(buf) != buf.length) 3020 SWT.error(SWT.ERROR_INVALID_IMAGE); 3021 } catch (IOException e) { 3022 SWT.error(SWT.ERROR_IO, e); 3023 } 3024 return paletteFromBytes(buf, numColors); 3025 } 3026 if (depth == 16) return new PaletteData(0x7C00, 0x3E0, 0x1F); 3027 if (depth == 24) return new PaletteData(0xFF, 0xFF00, 0xFF0000); 3028 return new PaletteData(0xFF00, 0xFF0000, 0xFF000000); 3029} 3030PaletteData paletteFromBytes(byte[] bytes, int numColors) { 3031 int bytesOffset = 0; 3032 RGB[] colors = new RGB[numColors]; 3033 for (int i = 0; i < numColors; i++) { 3034 colors[i] = new RGB(bytes[bytesOffset + 2] & 0xFF, 3035 bytes[bytesOffset + 1] & 0xFF, 3036 bytes[bytesOffset] & 0xFF); 3037 bytesOffset += 4; 3038 } 3039 return new PaletteData(colors); 3040} 3041 3045static byte[] paletteToBytes(PaletteData pal) { 3046 int n = pal.colors == null ? 0 : (pal.colors.length < 256 ? pal.colors.length : 256); 3047 byte[] bytes = new byte[n * 4]; 3048 int offset = 0; 3049 for (int i = 0; i < n; i++) { 3050 RGB col = pal.colors[i]; 3051 bytes[offset] = (byte)col.blue; 3052 bytes[offset + 1] = (byte)col.green; 3053 bytes[offset + 2] = (byte)col.red; 3054 offset += 4; 3055 } 3056 return bytes; 3057} 3058 3059void flipScanLines(byte[] data, int stride, int height) { 3060 int i1 = 0; 3061 int i2 = (height - 1) * stride; 3062 for (int i = 0; i < height / 2; i++) { 3063 for (int index = 0; index < stride; index++) { 3064 byte b = data[index + i1]; 3065 data[index + i1] = data[index + i2]; 3066 data[index + i2] = b; 3067 } 3068 i1 += stride; 3069 i2 -= stride; 3070 } 3071} 3072 3073} 3074 3075static class WinICOFileFormat extends FileFormat { 3076 3077static final byte[] convertPad(byte[] data, int width, int height, int depth, int pad, int newPad) { 3078 if (pad == newPad) return data; 3079 int stride = (width * depth + 7) / 8; 3080 int bpl = (stride + (pad - 1)) / pad * pad; 3081 int newBpl = (stride + (newPad - 1)) / newPad * newPad; 3082 byte[] newData = new byte[height * newBpl]; 3083 int srcIndex = 0, destIndex = 0; 3084 for (int y = 0; y < height; y++) { 3085 System.arraycopy(data, srcIndex, newData, destIndex, newBpl); 3086 srcIndex += bpl; 3087 destIndex += newBpl; 3088 } 3089 return newData; 3090} 3091 3095int iconSize(ImageData i) { 3096 int shapeDataStride = (i.width * i.depth + 31) / 32 * 4; 3097 int maskDataStride = (i.width + 31) / 32 * 4; 3098 int dataSize = (shapeDataStride + maskDataStride) * i.height; 3099 int paletteSize = i.palette.colors != null ? i.palette.colors.length * 4 : 0; 3100 return WinBMPFileFormat.BMPHeaderFixedSize + paletteSize + dataSize; 3101} 3102boolean isFileFormat(LEDataInputStream stream) { 3103 try { 3104 byte[] header = new byte[4]; 3105 stream.read(header); 3106 stream.unread(header); 3107 return header[0] == 0 && header[1] == 0 && header[2] == 1 && header[3] == 0; 3108 } catch (Exception e) { 3109 return false; 3110 } 3111} 3112boolean isValidIcon(ImageData i) { 3113 switch (i.depth) { 3114 case 1: 3115 case 4: 3116 case 8: 3117 if (i.palette.isDirect) return false; 3118 int size = i.palette.colors.length; 3119 return size == 2 || size == 16 || size == 32 || size == 256; 3120 case 24: 3121 case 32: 3122 return i.palette.isDirect; 3123 } 3124 return false; 3125} 3126int loadFileHeader(LEDataInputStream byteStream) { 3127 int[] fileHeader = new int[3]; 3128 try { 3129 fileHeader[0] = byteStream.readShort(); 3130 fileHeader[1] = byteStream.readShort(); 3131 fileHeader[2] = byteStream.readShort(); 3132 } catch (IOException e) { 3133 SWT.error(SWT.ERROR_IO, e); 3134 } 3135 if ((fileHeader[0] != 0) || (fileHeader[1] != 1)) 3136 SWT.error(SWT.ERROR_INVALID_IMAGE); 3137 int numIcons = fileHeader[2]; 3138 if (numIcons <= 0) 3139 SWT.error(SWT.ERROR_INVALID_IMAGE); 3140 return numIcons; 3141} 3142int loadFileHeader(LEDataInputStream byteStream, boolean hasHeader) { 3143 int[] fileHeader = new int[3]; 3144 try { 3145 if (hasHeader) { 3146 fileHeader[0] = byteStream.readShort(); 3147 fileHeader[1] = byteStream.readShort(); 3148 } else { 3149 fileHeader[0] = 0; 3150 fileHeader[1] = 1; 3151 } 3152 fileHeader[2] = byteStream.readShort(); 3153 } catch (IOException e) { 3154 SWT.error(SWT.ERROR_IO, e); 3155 } 3156 if ((fileHeader[0] != 0) || (fileHeader[1] != 1)) 3157 SWT.error(SWT.ERROR_INVALID_IMAGE); 3158 int numIcons = fileHeader[2]; 3159 if (numIcons <= 0) 3160 SWT.error(SWT.ERROR_INVALID_IMAGE); 3161 return numIcons; 3162} 3163ImageData[] loadFromByteStream() { 3164 int numIcons = loadFileHeader(inputStream); 3165 int[][] headers = loadIconHeaders(numIcons); 3166 ImageData[] icons = new ImageData[headers.length]; 3167 for (int i = 0; i < icons.length; i++) { 3168 icons[i] = loadIcon(headers[i]); 3169 } 3170 return icons; 3171} 3172 3175ImageData loadIcon(int[] iconHeader) { 3176 byte[] infoHeader = loadInfoHeader(iconHeader); 3177 WinBMPFileFormat bmpFormat = new WinBMPFileFormat(); 3178 bmpFormat.inputStream = inputStream; 3179 PaletteData palette = bmpFormat.loadPalette(infoHeader); 3180 byte[] shapeData = bmpFormat.loadData(infoHeader); 3181 int width = (infoHeader[4] & 0xFF) | ((infoHeader[5] & 0xFF) << 8) | ((infoHeader[6] & 0xFF) << 16) | ((infoHeader[7] & 0xFF) << 24); 3182 int height = (infoHeader[8] & 0xFF) | ((infoHeader[9] & 0xFF) << 8) | ((infoHeader[10] & 0xFF) << 16) | ((infoHeader[11] & 0xFF) << 24); 3183 int depth = (infoHeader[14] & 0xFF) | ((infoHeader[15] & 0xFF) << 8); 3184 infoHeader[14] = 1; 3185 infoHeader[15] = 0; 3186 byte[] maskData = bmpFormat.loadData(infoHeader); 3187 maskData = convertPad(maskData, width, height, 1, 4, 2); 3188 bitInvertData(maskData, 0, maskData.length); 3189 return ImageData.internal_new( 3190 width, 3191 height, 3192 depth, 3193 palette, 3194 4, 3195 shapeData, 3196 2, 3197 maskData, 3198 null, 3199 -1, 3200 -1, 3201 SWT.IMAGE_ICO, 3202 0, 3203 0, 3204 0, 3205 0); 3206} 3207int[][] loadIconHeaders(int numIcons) { 3208 int[][] headers = new int[numIcons][7]; 3209 try { 3210 for (int i = 0; i < numIcons; i++) { 3211 headers[i][0] = inputStream.read(); 3212 headers[i][1] = inputStream.read(); 3213 headers[i][2] = inputStream.readShort(); 3214 headers[i][3] = inputStream.readShort(); 3215 headers[i][4] = inputStream.readShort(); 3216 headers[i][5] = inputStream.readInt(); 3217 headers[i][6] = inputStream.readInt(); 3218 } 3219 } catch (IOException e) { 3220 SWT.error(SWT.ERROR_IO, e); 3221 } 3222 return headers; 3223} 3224byte[] loadInfoHeader(int[] iconHeader) { 3225 int width = iconHeader[0]; 3226 int height = iconHeader[1]; 3227 int numColors = iconHeader[2]; if (numColors == 0) numColors = 256; if ((numColors != 2) && (numColors != 8) && (numColors != 16) && 3230 (numColors != 32) && (numColors != 256)) 3231 SWT.error(SWT.ERROR_INVALID_IMAGE); 3232 if (inputStream.getPosition() < iconHeader[6]) { 3233 try { 3235 inputStream.skip(iconHeader[6] - inputStream.getPosition()); 3236 } catch (IOException e) { 3237 SWT.error(SWT.ERROR_IO, e); 3238 return null; 3239 } 3240 } 3241 byte[] infoHeader = new byte[WinBMPFileFormat.BMPHeaderFixedSize]; 3242 try { 3243 inputStream.read(infoHeader); 3244 } catch (IOException e) { 3245 SWT.error(SWT.ERROR_IO, e); 3246 } 3247 if (((infoHeader[12] & 0xFF) | ((infoHeader[13] & 0xFF) << 8)) != 1) 3248 SWT.error(SWT.ERROR_INVALID_IMAGE); 3249 int infoWidth = (infoHeader[4] & 0xFF) | ((infoHeader[5] & 0xFF) << 8) | ((infoHeader[6] & 0xFF) << 16) | ((infoHeader[7] & 0xFF) << 24); 3250 int infoHeight = (infoHeader[8] & 0xFF) | ((infoHeader[9] & 0xFF) << 8) | ((infoHeader[10] & 0xFF) << 16) | ((infoHeader[11] & 0xFF) << 24); 3251 int bitCount = (infoHeader[14] & 0xFF) | ((infoHeader[15] & 0xFF) << 8); 3252 if (height == infoHeight && bitCount == 1) height /= 2; 3253 if (!((width == infoWidth) && (height * 2 == infoHeight) && 3254 (bitCount == 1 || bitCount == 4 || bitCount == 8 || bitCount == 24 || bitCount == 32))) 3255 SWT.error(SWT.ERROR_INVALID_IMAGE); 3256 infoHeader[8] = (byte)(height & 0xFF); 3257 infoHeader[9] = (byte)((height >> 8) & 0xFF); 3258 infoHeader[10] = (byte)((height >> 16) & 0xFF); 3259 infoHeader[11] = (byte)((height >> 24) & 0xFF); 3260 return infoHeader; 3261} 3262} 3263static class SWT { 3264 public static final int IMAGE_ICO = 3; 3265 public static final int ERROR_IO = 39; 3266 public static final int ERROR_INVALID_IMAGE = 40; 3267 public static final int ERROR_NULL_ARGUMENT = 4; 3268 public static final int ERROR_INVALID_ARGUMENT = 5; 3269 public static final int ERROR_CANNOT_BE_ZERO = 7; 3270 public static final int IMAGE_UNDEFINED = -1; 3271 public static final int ERROR_UNSUPPORTED_DEPTH = 38; 3272 public static final int TRANSPARENCY_MASK = 1 << 1; 3273 public static final int ERROR_UNSUPPORTED_FORMAT = 42; 3274 public static final int TRANSPARENCY_ALPHA = 1 << 0; 3275 public static final int TRANSPARENCY_NONE = 0x0; 3276 public static final int TRANSPARENCY_PIXEL = 1 << 2; 3277 public static final int IMAGE_BMP = 0; 3278 public static final int IMAGE_BMP_RLE = 1; 3279 3280 public static void error(int code) { 3281 throw new RuntimeException ("Error "+code); } 3283 public static void error(int code, Throwable t) { 3284 throw new RuntimeException (t); 3285 } 3286} 3287} 3288 | Popular Tags |