X-Git-Url: https://code.delx.au/refind/blobdiff_plain/e22f7ac1eccb5958dd960e157d0f35606f7db26e..8b5b878155046a6da1956a2855f39f364abc0338:/libeg/load_icns.c diff --git a/libeg/load_icns.c b/libeg/load_icns.c index 6af234d..41fca77 100644 --- a/libeg/load_icns.c +++ b/libeg/load_icns.c @@ -36,6 +36,8 @@ #include "libegint.h" +#define MAX_ICNS_SIZES 4 + // // Decompress .icns RLE data // @@ -48,13 +50,13 @@ VOID egDecompressIcnsRLE(IN OUT UINT8 **CompData, IN OUT UINTN *CompLen, IN UINT UINTN pp_left; UINTN len, i; UINT8 value; - + // setup variables cp = *CompData; cp_end = cp + *CompLen; pp = PixelData; pp_left = PixelCount; - + // decode while (cp + 1 < cp_end && pp_left > 0) { len = *cp++; @@ -78,11 +80,11 @@ VOID egDecompressIcnsRLE(IN OUT UINT8 **CompData, IN OUT UINTN *CompLen, IN UINT } pp_left -= len; } - + if (pp_left > 0) { Print(L" egDecompressIcnsRLE: still need %d bytes of pixel data\n", pp_left); } - + // record what's left of the compressed data stream *CompData = cp; *CompLen = (UINTN)(cp_end - cp); @@ -97,97 +99,95 @@ EG_IMAGE * egDecodeICNS(IN UINT8 *FileData, IN UINTN FileDataLength, IN UINTN Ic EG_IMAGE *NewImage; UINT8 *Ptr, *BufferEnd, *DataPtr, *MaskPtr; UINT32 BlockLen, DataLen, MaskLen; - UINTN FetchPixelSize, PixelCount, i; + UINTN PixelCount, i; UINT8 *CompData; UINTN CompLen; UINT8 *SrcPtr; EG_PIXEL *DestPtr; + UINTN SizesToTry[MAX_ICNS_SIZES + 1] = {IconSize, 128, 48, 32, 16}; + UINTN SizeToTry = 0; if (FileDataLength < 8 || FileData == NULL || FileData[0] != 'i' || FileData[1] != 'c' || FileData[2] != 'n' || FileData[3] != 's') { // not an icns file... return NULL; } - - FetchPixelSize = IconSize; + for (;;) { DataPtr = NULL; DataLen = 0; MaskPtr = NULL; MaskLen = 0; - - Ptr = FileData + 8; - BufferEnd = FileData + FileDataLength; - // iterate over tagged blocks in the file - while (Ptr + 8 <= BufferEnd) { - BlockLen = ((UINT32)Ptr[4] << 24) + ((UINT32)Ptr[5] << 16) + ((UINT32)Ptr[6] << 8) + (UINT32)Ptr[7]; - if (Ptr + BlockLen > BufferEnd) // block continues beyond end of file - break; - - // extract the appropriate blocks for each pixel size - if (FetchPixelSize == 128) { - if (Ptr[0] == 'i' && Ptr[1] == 't' && Ptr[2] == '3' && Ptr[3] == '2') { - if (Ptr[8] == 0 && Ptr[9] == 0 && Ptr[10] == 0 && Ptr[11] == 0) { - DataPtr = Ptr + 12; - DataLen = BlockLen - 12; - } - } else if (Ptr[0] == 't' && Ptr[1] == '8' && Ptr[2] == 'm' && Ptr[3] == 'k') { - MaskPtr = Ptr + 8; - MaskLen = BlockLen - 8; - } - - } else if (FetchPixelSize == 48) { - if (Ptr[0] == 'i' && Ptr[1] == 'h' && Ptr[2] == '3' && Ptr[3] == '2') { - DataPtr = Ptr + 8; - DataLen = BlockLen - 8; - } else if (Ptr[0] == 'h' && Ptr[1] == '8' && Ptr[2] == 'm' && Ptr[3] == 'k') { - MaskPtr = Ptr + 8; - MaskLen = BlockLen - 8; - } - - } else if (FetchPixelSize == 32) { - if (Ptr[0] == 'i' && Ptr[1] == 'l' && Ptr[2] == '3' && Ptr[3] == '2') { - DataPtr = Ptr + 8; - DataLen = BlockLen - 8; - } else if (Ptr[0] == 'l' && Ptr[1] == '8' && Ptr[2] == 'm' && Ptr[3] == 'k') { - MaskPtr = Ptr + 8; - MaskLen = BlockLen - 8; - } - - } else if (FetchPixelSize == 16) { - if (Ptr[0] == 'i' && Ptr[1] == 's' && Ptr[2] == '3' && Ptr[3] == '2') { - DataPtr = Ptr + 8; - DataLen = BlockLen - 8; - } else if (Ptr[0] == 's' && Ptr[1] == '8' && Ptr[2] == 'm' && Ptr[3] == 'k') { - MaskPtr = Ptr + 8; - MaskLen = BlockLen - 8; - } - - } - - Ptr += BlockLen; - } - - /* FUTURE: try to load a different size and scale it later - if (DataPtr == NULL && FetchPixelSize == 32) { - FetchPixelSize = 128; - continue; - } - */ + + do { + IconSize = SizesToTry[SizeToTry]; + Ptr = FileData + 8; + BufferEnd = FileData + FileDataLength; + // iterate over tagged blocks in the file + while (Ptr + 8 <= BufferEnd) { + BlockLen = ((UINT32)Ptr[4] << 24) + ((UINT32)Ptr[5] << 16) + ((UINT32)Ptr[6] << 8) + (UINT32)Ptr[7]; + if (Ptr + BlockLen > BufferEnd) // block continues beyond end of file + break; + + // extract the appropriate blocks for each pixel size + if (IconSize == 128) { + if (Ptr[0] == 'i' && Ptr[1] == 't' && Ptr[2] == '3' && Ptr[3] == '2') { + if (Ptr[8] == 0 && Ptr[9] == 0 && Ptr[10] == 0 && Ptr[11] == 0) { + DataPtr = Ptr + 12; + DataLen = BlockLen - 12; + } + } else if (Ptr[0] == 't' && Ptr[1] == '8' && Ptr[2] == 'm' && Ptr[3] == 'k') { + MaskPtr = Ptr + 8; + MaskLen = BlockLen - 8; + } + + } else if (IconSize == 48) { + if (Ptr[0] == 'i' && Ptr[1] == 'h' && Ptr[2] == '3' && Ptr[3] == '2') { + DataPtr = Ptr + 8; + DataLen = BlockLen - 8; + } else if (Ptr[0] == 'h' && Ptr[1] == '8' && Ptr[2] == 'm' && Ptr[3] == 'k') { + MaskPtr = Ptr + 8; + MaskLen = BlockLen - 8; + } + + } else if (IconSize == 32) { + if (Ptr[0] == 'i' && Ptr[1] == 'l' && Ptr[2] == '3' && Ptr[3] == '2') { + DataPtr = Ptr + 8; + DataLen = BlockLen - 8; + } else if (Ptr[0] == 'l' && Ptr[1] == '8' && Ptr[2] == 'm' && Ptr[3] == 'k') { + MaskPtr = Ptr + 8; + MaskLen = BlockLen - 8; + } + + } else if (IconSize == 16) { + if (Ptr[0] == 'i' && Ptr[1] == 's' && Ptr[2] == '3' && Ptr[3] == '2') { + DataPtr = Ptr + 8; + DataLen = BlockLen - 8; + } else if (Ptr[0] == 's' && Ptr[1] == '8' && Ptr[2] == 'm' && Ptr[3] == 'k') { + MaskPtr = Ptr + 8; + MaskLen = BlockLen - 8; + } + + } + + Ptr += BlockLen; + } + } while ((DataPtr == NULL) && (SizeToTry++ < MAX_ICNS_SIZES)); + break; } - + if (DataPtr == NULL) return NULL; // no image found - + // allocate image structure and buffer - NewImage = egCreateImage(FetchPixelSize, FetchPixelSize, WantAlpha); + NewImage = egCreateImage(IconSize, IconSize, WantAlpha); if (NewImage == NULL) return NULL; - PixelCount = FetchPixelSize * FetchPixelSize; - + PixelCount = IconSize * IconSize; + if (DataLen < PixelCount * 3) { - + // pixel data is compressed, RGB planar CompData = DataPtr; CompLen = DataLen; @@ -198,9 +198,9 @@ EG_IMAGE * egDecodeICNS(IN UINT8 *FileData, IN UINTN FileDataLength, IN UINTN Ic if (CompLen > 0) { Print(L" egLoadICNSIcon: %d bytes of compressed data left\n", CompLen); } - + } else { - + // pixel data is uncompressed, RGB interleaved SrcPtr = DataPtr; DestPtr = NewImage->PixelData; @@ -209,18 +209,18 @@ EG_IMAGE * egDecodeICNS(IN UINT8 *FileData, IN UINTN FileDataLength, IN UINTN Ic DestPtr->g = *SrcPtr++; DestPtr->b = *SrcPtr++; } - + } - + // add/set alpha plane if (MaskPtr != NULL && MaskLen >= PixelCount && WantAlpha) egInsertPlane(MaskPtr, PLPTR(NewImage, a), PixelCount); else egSetPlane(PLPTR(NewImage, a), WantAlpha ? 255 : 0, PixelCount); - + // FUTURE: scale to originally requested size if we had to load another size - + return NewImage; -} +} // EG_IMAGE * egDecodeICNS() /* EOF */