michael@0: /* vim:set tw=80 expandtab softtabstop=4 ts=4 sw=4: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* This is a Cross-Platform ICO Decoder, which should work everywhere, including michael@0: * Big-Endian machines like the PowerPC. */ michael@0: michael@0: #include michael@0: michael@0: #include "mozilla/Endian.h" michael@0: #include "nsICODecoder.h" michael@0: michael@0: #include "RasterImage.h" michael@0: michael@0: namespace mozilla { michael@0: namespace image { michael@0: michael@0: #define ICONCOUNTOFFSET 4 michael@0: #define DIRENTRYOFFSET 6 michael@0: #define BITMAPINFOSIZE 40 michael@0: #define PREFICONSIZE 16 michael@0: michael@0: // ---------------------------------------- michael@0: // Actual Data Processing michael@0: // ---------------------------------------- michael@0: michael@0: uint32_t michael@0: nsICODecoder::CalcAlphaRowSize() michael@0: { michael@0: // Calculate rowsize in DWORD's and then return in # of bytes michael@0: uint32_t rowSize = (GetRealWidth() + 31) / 32; // + 31 to round up michael@0: return rowSize * 4; // Return rowSize in bytes michael@0: } michael@0: michael@0: // Obtains the number of colors from the bits per pixel michael@0: uint16_t michael@0: nsICODecoder::GetNumColors() michael@0: { michael@0: uint16_t numColors = 0; michael@0: if (mBPP <= 8) { michael@0: switch (mBPP) { michael@0: case 1: michael@0: numColors = 2; michael@0: break; michael@0: case 4: michael@0: numColors = 16; michael@0: break; michael@0: case 8: michael@0: numColors = 256; michael@0: break; michael@0: default: michael@0: numColors = (uint16_t)-1; michael@0: } michael@0: } michael@0: return numColors; michael@0: } michael@0: michael@0: michael@0: nsICODecoder::nsICODecoder(RasterImage &aImage) michael@0: : Decoder(aImage) michael@0: { michael@0: mPos = mImageOffset = mCurrIcon = mNumIcons = mBPP = mRowBytes = 0; michael@0: mIsPNG = false; michael@0: mRow = nullptr; michael@0: mOldLine = mCurLine = 1; // Otherwise decoder will never start michael@0: } michael@0: michael@0: nsICODecoder::~nsICODecoder() michael@0: { michael@0: if (mRow) { michael@0: moz_free(mRow); michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsICODecoder::FinishInternal() michael@0: { michael@0: // We shouldn't be called in error cases michael@0: NS_ABORT_IF_FALSE(!HasError(), "Shouldn't call FinishInternal after error!"); michael@0: michael@0: // Finish the internally used decoder as well michael@0: if (mContainedDecoder) { michael@0: mContainedDecoder->FinishSharedDecoder(); michael@0: mDecodeDone = mContainedDecoder->GetDecodeDone(); michael@0: } michael@0: } michael@0: michael@0: // Returns a buffer filled with the bitmap file header in little endian: michael@0: // Signature 2 bytes 'BM' michael@0: // FileSize 4 bytes File size in bytes michael@0: // reserved 4 bytes unused (=0) michael@0: // DataOffset 4 bytes File offset to Raster Data michael@0: // Returns true if successful michael@0: bool nsICODecoder::FillBitmapFileHeaderBuffer(int8_t *bfh) michael@0: { michael@0: memset(bfh, 0, 14); michael@0: bfh[0] = 'B'; michael@0: bfh[1] = 'M'; michael@0: int32_t dataOffset = 0; michael@0: int32_t fileSize = 0; michael@0: dataOffset = BFH_LENGTH + BITMAPINFOSIZE; michael@0: michael@0: // The color table is present only if BPP is <= 8 michael@0: if (mDirEntry.mBitCount <= 8) { michael@0: uint16_t numColors = GetNumColors(); michael@0: if (numColors == (uint16_t)-1) { michael@0: return false; michael@0: } michael@0: dataOffset += 4 * numColors; michael@0: fileSize = dataOffset + GetRealWidth() * GetRealHeight(); michael@0: } else { michael@0: fileSize = dataOffset + (mDirEntry.mBitCount * GetRealWidth() * michael@0: GetRealHeight()) / 8; michael@0: } michael@0: michael@0: NativeEndian::swapToLittleEndianInPlace(&fileSize, 1); michael@0: memcpy(bfh + 2, &fileSize, sizeof(fileSize)); michael@0: NativeEndian::swapToLittleEndianInPlace(&dataOffset, 1); michael@0: memcpy(bfh + 10, &dataOffset, sizeof(dataOffset)); michael@0: return true; michael@0: } michael@0: michael@0: // A BMP inside of an ICO has *2 height because of the AND mask michael@0: // that follows the actual bitmap. The BMP shouldn't know about michael@0: // this difference though. michael@0: bool michael@0: nsICODecoder::FixBitmapHeight(int8_t *bih) michael@0: { michael@0: // Get the height from the BMP file information header michael@0: int32_t height; michael@0: memcpy(&height, bih + 8, sizeof(height)); michael@0: NativeEndian::swapFromLittleEndianInPlace(&height, 1); michael@0: // BMPs can be stored inverted by having a negative height michael@0: height = abs(height); michael@0: michael@0: // The bitmap height is by definition * 2 what it should be to account for michael@0: // the 'AND mask'. It is * 2 even if the `AND mask` is not present. michael@0: height /= 2; michael@0: michael@0: if (height > 256) { michael@0: return false; michael@0: } michael@0: michael@0: // We should always trust the height from the bitmap itself instead of michael@0: // the ICO height. So fix the ICO height. michael@0: if (height == 256) { michael@0: mDirEntry.mHeight = 0; michael@0: } else { michael@0: mDirEntry.mHeight = (int8_t)height; michael@0: } michael@0: michael@0: // Fix the BMP height in the BIH so that the BMP decoder can work properly michael@0: NativeEndian::swapToLittleEndianInPlace(&height, 1); michael@0: memcpy(bih + 8, &height, sizeof(height)); michael@0: return true; michael@0: } michael@0: michael@0: // We should always trust the contained resource for the width michael@0: // information over our own information. michael@0: bool michael@0: nsICODecoder::FixBitmapWidth(int8_t *bih) michael@0: { michael@0: // Get the width from the BMP file information header michael@0: int32_t width; michael@0: memcpy(&width, bih + 4, sizeof(width)); michael@0: NativeEndian::swapFromLittleEndianInPlace(&width, 1); michael@0: if (width > 256) { michael@0: return false; michael@0: } michael@0: michael@0: // We should always trust the width from the bitmap itself instead of michael@0: // the ICO width. michael@0: if (width == 256) { michael@0: mDirEntry.mWidth = 0; michael@0: } else { michael@0: mDirEntry.mWidth = (int8_t)width; michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: // The BMP information header's bits per pixel should be trusted michael@0: // more than what we have. Usually the ICO's BPP is set to 0 michael@0: int32_t michael@0: nsICODecoder::ExtractBPPFromBitmap(int8_t *bih) michael@0: { michael@0: int32_t bitsPerPixel; michael@0: memcpy(&bitsPerPixel, bih + 14, sizeof(bitsPerPixel)); michael@0: NativeEndian::swapFromLittleEndianInPlace(&bitsPerPixel, 1); michael@0: return bitsPerPixel; michael@0: } michael@0: michael@0: int32_t michael@0: nsICODecoder::ExtractBIHSizeFromBitmap(int8_t *bih) michael@0: { michael@0: int32_t headerSize; michael@0: memcpy(&headerSize, bih, sizeof(headerSize)); michael@0: NativeEndian::swapFromLittleEndianInPlace(&headerSize, 1); michael@0: return headerSize; michael@0: } michael@0: michael@0: void michael@0: nsICODecoder::SetHotSpotIfCursor() { michael@0: if (!mIsCursor) { michael@0: return; michael@0: } michael@0: michael@0: mImageMetadata.SetHotspot(mDirEntry.mXHotspot, mDirEntry.mYHotspot); michael@0: } michael@0: michael@0: void michael@0: nsICODecoder::WriteInternal(const char* aBuffer, uint32_t aCount, DecodeStrategy aStrategy) michael@0: { michael@0: NS_ABORT_IF_FALSE(!HasError(), "Shouldn't call WriteInternal after error!"); michael@0: michael@0: if (!aCount) { michael@0: if (mContainedDecoder) { michael@0: WriteToContainedDecoder(aBuffer, aCount, aStrategy); michael@0: } michael@0: return; michael@0: } michael@0: michael@0: while (aCount && (mPos < ICONCOUNTOFFSET)) { // Skip to the # of icons. michael@0: if (mPos == 2) { // if the third byte is 1: This is an icon, 2: a cursor michael@0: if ((*aBuffer != 1) && (*aBuffer != 2)) { michael@0: PostDataError(); michael@0: return; michael@0: } michael@0: mIsCursor = (*aBuffer == 2); michael@0: } michael@0: mPos++; aBuffer++; aCount--; michael@0: } michael@0: michael@0: if (mPos == ICONCOUNTOFFSET && aCount >= 2) { michael@0: mNumIcons = LittleEndian::readUint16(reinterpret_cast(aBuffer)); michael@0: aBuffer += 2; michael@0: mPos += 2; michael@0: aCount -= 2; michael@0: } michael@0: michael@0: if (mNumIcons == 0) michael@0: return; // Nothing to do. michael@0: michael@0: uint16_t colorDepth = 0; michael@0: nsIntSize prefSize = mImage.GetRequestedResolution(); michael@0: if (prefSize.width == 0 && prefSize.height == 0) { michael@0: prefSize.SizeTo(PREFICONSIZE, PREFICONSIZE); michael@0: } michael@0: michael@0: // A measure of the difference in size between the entry we've found michael@0: // and the requested size. We will choose the smallest image that is michael@0: // >= requested size (i.e. we assume it's better to downscale a larger michael@0: // icon than to upscale a smaller one). michael@0: int32_t diff = INT_MIN; michael@0: michael@0: // Loop through each entry's dir entry michael@0: while (mCurrIcon < mNumIcons) { michael@0: if (mPos >= DIRENTRYOFFSET + (mCurrIcon * sizeof(mDirEntryArray)) && michael@0: mPos < DIRENTRYOFFSET + ((mCurrIcon + 1) * sizeof(mDirEntryArray))) { michael@0: uint32_t toCopy = sizeof(mDirEntryArray) - michael@0: (mPos - DIRENTRYOFFSET - mCurrIcon * sizeof(mDirEntryArray)); michael@0: if (toCopy > aCount) { michael@0: toCopy = aCount; michael@0: } michael@0: memcpy(mDirEntryArray + sizeof(mDirEntryArray) - toCopy, aBuffer, toCopy); michael@0: mPos += toCopy; michael@0: aCount -= toCopy; michael@0: aBuffer += toCopy; michael@0: } michael@0: if (aCount == 0) michael@0: return; // Need more data michael@0: michael@0: IconDirEntry e; michael@0: if (mPos == (DIRENTRYOFFSET + ICODIRENTRYSIZE) + michael@0: (mCurrIcon * sizeof(mDirEntryArray))) { michael@0: mCurrIcon++; michael@0: ProcessDirEntry(e); michael@0: // We can't use GetRealWidth and GetRealHeight here because those operate michael@0: // on mDirEntry, here we are going through each item in the directory. michael@0: // Calculate the delta between this image's size and the desired size, michael@0: // so we can see if it is better than our current-best option. michael@0: // In the case of several equally-good images, we use the last one. michael@0: int32_t delta = (e.mWidth == 0 ? 256 : e.mWidth) - prefSize.width + michael@0: (e.mHeight == 0 ? 256 : e.mHeight) - prefSize.height; michael@0: if (e.mBitCount >= colorDepth && michael@0: ((diff < 0 && delta >= diff) || (delta >= 0 && delta <= diff))) { michael@0: diff = delta; michael@0: mImageOffset = e.mImageOffset; michael@0: michael@0: // ensure mImageOffset is >= size of the direntry headers (bug #245631) michael@0: uint32_t minImageOffset = DIRENTRYOFFSET + michael@0: mNumIcons * sizeof(mDirEntryArray); michael@0: if (mImageOffset < minImageOffset) { michael@0: PostDataError(); michael@0: return; michael@0: } michael@0: michael@0: colorDepth = e.mBitCount; michael@0: memcpy(&mDirEntry, &e, sizeof(IconDirEntry)); michael@0: } michael@0: } michael@0: } michael@0: michael@0: if (mPos < mImageOffset) { michael@0: // Skip to (or at least towards) the desired image offset michael@0: uint32_t toSkip = mImageOffset - mPos; michael@0: if (toSkip > aCount) michael@0: toSkip = aCount; michael@0: michael@0: mPos += toSkip; michael@0: aBuffer += toSkip; michael@0: aCount -= toSkip; michael@0: } michael@0: michael@0: // If we are within the first PNGSIGNATURESIZE bytes of the image data, michael@0: // then we have either a BMP or a PNG. We use the first PNGSIGNATURESIZE michael@0: // bytes to determine which one we have. michael@0: if (mCurrIcon == mNumIcons && mPos >= mImageOffset && michael@0: mPos < mImageOffset + PNGSIGNATURESIZE) michael@0: { michael@0: uint32_t toCopy = PNGSIGNATURESIZE - (mPos - mImageOffset); michael@0: if (toCopy > aCount) { michael@0: toCopy = aCount; michael@0: } michael@0: michael@0: memcpy(mSignature + (mPos - mImageOffset), aBuffer, toCopy); michael@0: mPos += toCopy; michael@0: aCount -= toCopy; michael@0: aBuffer += toCopy; michael@0: michael@0: mIsPNG = !memcmp(mSignature, nsPNGDecoder::pngSignatureBytes, michael@0: PNGSIGNATURESIZE); michael@0: if (mIsPNG) { michael@0: mContainedDecoder = new nsPNGDecoder(mImage); michael@0: mContainedDecoder->SetObserver(mObserver); michael@0: mContainedDecoder->SetSizeDecode(IsSizeDecode()); michael@0: mContainedDecoder->InitSharedDecoder(mImageData, mImageDataLength, michael@0: mColormap, mColormapSize, michael@0: mCurrentFrame); michael@0: if (!WriteToContainedDecoder(mSignature, PNGSIGNATURESIZE, aStrategy)) { michael@0: return; michael@0: } michael@0: } michael@0: } michael@0: michael@0: // If we have a PNG, let the PNG decoder do all of the rest of the work michael@0: if (mIsPNG && mContainedDecoder && mPos >= mImageOffset + PNGSIGNATURESIZE) { michael@0: if (!WriteToContainedDecoder(aBuffer, aCount, aStrategy)) { michael@0: return; michael@0: } michael@0: michael@0: if (!HasSize() && mContainedDecoder->HasSize()) { michael@0: PostSize(mContainedDecoder->GetImageMetadata().GetWidth(), michael@0: mContainedDecoder->GetImageMetadata().GetHeight()); michael@0: } michael@0: michael@0: mPos += aCount; michael@0: aBuffer += aCount; michael@0: aCount = 0; michael@0: michael@0: // Raymond Chen says that 32bpp only are valid PNG ICOs michael@0: // http://blogs.msdn.com/b/oldnewthing/archive/2010/10/22/10079192.aspx michael@0: if (!IsSizeDecode() && michael@0: !static_cast(mContainedDecoder.get())->IsValidICO()) { michael@0: PostDataError(); michael@0: } michael@0: return; michael@0: } michael@0: michael@0: // We've processed all of the icon dir entries and are within the michael@0: // bitmap info size michael@0: if (!mIsPNG && mCurrIcon == mNumIcons && mPos >= mImageOffset && michael@0: mPos >= mImageOffset + PNGSIGNATURESIZE && michael@0: mPos < mImageOffset + BITMAPINFOSIZE) { michael@0: michael@0: // As we were decoding, we did not know if we had a PNG signature or the michael@0: // start of a bitmap information header. At this point we know we had michael@0: // a bitmap information header and not a PNG signature, so fill the bitmap michael@0: // information header with the data it should already have. michael@0: memcpy(mBIHraw, mSignature, PNGSIGNATURESIZE); michael@0: michael@0: // We've found the icon. michael@0: uint32_t toCopy = sizeof(mBIHraw) - (mPos - mImageOffset); michael@0: if (toCopy > aCount) michael@0: toCopy = aCount; michael@0: michael@0: memcpy(mBIHraw + (mPos - mImageOffset), aBuffer, toCopy); michael@0: mPos += toCopy; michael@0: aCount -= toCopy; michael@0: aBuffer += toCopy; michael@0: } michael@0: michael@0: // If we have a BMP inside the ICO and we have read the BIH header michael@0: if (!mIsPNG && mPos == mImageOffset + BITMAPINFOSIZE) { michael@0: michael@0: // Make sure we have a sane value for the bitmap information header michael@0: int32_t bihSize = ExtractBIHSizeFromBitmap(reinterpret_cast(mBIHraw)); michael@0: if (bihSize != BITMAPINFOSIZE) { michael@0: PostDataError(); michael@0: return; michael@0: } michael@0: // We are extracting the BPP from the BIH header as it should be trusted michael@0: // over the one we have from the icon header michael@0: mBPP = ExtractBPPFromBitmap(reinterpret_cast(mBIHraw)); michael@0: michael@0: // Init the bitmap decoder which will do most of the work for us michael@0: // It will do everything except the AND mask which isn't present in bitmaps michael@0: // bmpDecoder is for local scope ease, it will be freed by mContainedDecoder michael@0: nsBMPDecoder *bmpDecoder = new nsBMPDecoder(mImage); michael@0: mContainedDecoder = bmpDecoder; michael@0: bmpDecoder->SetUseAlphaData(true); michael@0: mContainedDecoder->SetObserver(mObserver); michael@0: mContainedDecoder->SetSizeDecode(IsSizeDecode()); michael@0: mContainedDecoder->InitSharedDecoder(mImageData, mImageDataLength, michael@0: mColormap, mColormapSize, michael@0: mCurrentFrame); michael@0: michael@0: // The ICO format when containing a BMP does not include the 14 byte michael@0: // bitmap file header. To use the code of the BMP decoder we need to michael@0: // generate this header ourselves and feed it to the BMP decoder. michael@0: int8_t bfhBuffer[BMPFILEHEADERSIZE]; michael@0: if (!FillBitmapFileHeaderBuffer(bfhBuffer)) { michael@0: PostDataError(); michael@0: return; michael@0: } michael@0: if (!WriteToContainedDecoder((const char*)bfhBuffer, sizeof(bfhBuffer), aStrategy)) { michael@0: return; michael@0: } michael@0: michael@0: // Setup the cursor hot spot if one is present michael@0: SetHotSpotIfCursor(); michael@0: michael@0: // Fix the ICO height from the BIH. michael@0: // Fix the height on the BIH to be /2 so our BMP decoder will understand. michael@0: if (!FixBitmapHeight(reinterpret_cast(mBIHraw))) { michael@0: PostDataError(); michael@0: return; michael@0: } michael@0: michael@0: // Fix the ICO width from the BIH. michael@0: if (!FixBitmapWidth(reinterpret_cast(mBIHraw))) { michael@0: PostDataError(); michael@0: return; michael@0: } michael@0: michael@0: // Write out the BMP's bitmap info header michael@0: if (!WriteToContainedDecoder(mBIHraw, sizeof(mBIHraw), aStrategy)) { michael@0: return; michael@0: } michael@0: michael@0: PostSize(mContainedDecoder->GetImageMetadata().GetWidth(), michael@0: mContainedDecoder->GetImageMetadata().GetHeight()); michael@0: michael@0: // We have the size. If we're doing a size decode, we got what michael@0: // we came for. michael@0: if (IsSizeDecode()) michael@0: return; michael@0: michael@0: // Sometimes the ICO BPP header field is not filled out michael@0: // so we should trust the contained resource over our own michael@0: // information. michael@0: mBPP = bmpDecoder->GetBitsPerPixel(); michael@0: michael@0: // Check to make sure we have valid color settings michael@0: uint16_t numColors = GetNumColors(); michael@0: if (numColors == (uint16_t)-1) { michael@0: PostDataError(); michael@0: return; michael@0: } michael@0: } michael@0: michael@0: // If we have a BMP michael@0: if (!mIsPNG && mContainedDecoder && mPos >= mImageOffset + BITMAPINFOSIZE) { michael@0: uint16_t numColors = GetNumColors(); michael@0: if (numColors == (uint16_t)-1) { michael@0: PostDataError(); michael@0: return; michael@0: } michael@0: // Feed the actual image data (not including headers) into the BMP decoder michael@0: uint32_t bmpDataOffset = mDirEntry.mImageOffset + BITMAPINFOSIZE; michael@0: uint32_t bmpDataEnd = mDirEntry.mImageOffset + BITMAPINFOSIZE + michael@0: static_cast(mContainedDecoder.get())->GetCompressedImageSize() + michael@0: 4 * numColors; michael@0: michael@0: // If we are feeding in the core image data, but we have not yet michael@0: // reached the ICO's 'AND buffer mask' michael@0: if (mPos >= bmpDataOffset && mPos < bmpDataEnd) { michael@0: michael@0: // Figure out how much data the BMP decoder wants michael@0: uint32_t toFeed = bmpDataEnd - mPos; michael@0: if (toFeed > aCount) { michael@0: toFeed = aCount; michael@0: } michael@0: michael@0: if (!WriteToContainedDecoder(aBuffer, toFeed, aStrategy)) { michael@0: return; michael@0: } michael@0: michael@0: mPos += toFeed; michael@0: aCount -= toFeed; michael@0: aBuffer += toFeed; michael@0: } michael@0: michael@0: // If the bitmap is fully processed, treat any left over data as the ICO's michael@0: // 'AND buffer mask' which appears after the bitmap resource. michael@0: if (!mIsPNG && mPos >= bmpDataEnd) { michael@0: // There may be an optional AND bit mask after the data. This is michael@0: // only used if the alpha data is not already set. The alpha data michael@0: // is used for 32bpp bitmaps as per the comment in ICODecoder.h michael@0: // The alpha mask should be checked in all other cases. michael@0: if (static_cast(mContainedDecoder.get())->GetBitsPerPixel() != 32 || michael@0: !static_cast(mContainedDecoder.get())->HasAlphaData()) { michael@0: uint32_t rowSize = ((GetRealWidth() + 31) / 32) * 4; // + 31 to round up michael@0: if (mPos == bmpDataEnd) { michael@0: mPos++; michael@0: mRowBytes = 0; michael@0: mCurLine = GetRealHeight(); michael@0: mRow = (uint8_t*)moz_realloc(mRow, rowSize); michael@0: if (!mRow) { michael@0: PostDecoderError(NS_ERROR_OUT_OF_MEMORY); michael@0: return; michael@0: } michael@0: } michael@0: michael@0: // Ensure memory has been allocated before decoding. michael@0: NS_ABORT_IF_FALSE(mRow, "mRow is null"); michael@0: if (!mRow) { michael@0: PostDataError(); michael@0: return; michael@0: } michael@0: michael@0: while (mCurLine > 0 && aCount > 0) { michael@0: uint32_t toCopy = std::min(rowSize - mRowBytes, aCount); michael@0: if (toCopy) { michael@0: memcpy(mRow + mRowBytes, aBuffer, toCopy); michael@0: aCount -= toCopy; michael@0: aBuffer += toCopy; michael@0: mRowBytes += toCopy; michael@0: } michael@0: if (rowSize == mRowBytes) { michael@0: mCurLine--; michael@0: mRowBytes = 0; michael@0: michael@0: uint32_t* imageData = michael@0: static_cast(mContainedDecoder.get())->GetImageData(); michael@0: if (!imageData) { michael@0: PostDataError(); michael@0: return; michael@0: } michael@0: uint32_t* decoded = imageData + mCurLine * GetRealWidth(); michael@0: uint32_t* decoded_end = decoded + GetRealWidth(); michael@0: uint8_t* p = mRow, *p_end = mRow + rowSize; michael@0: while (p < p_end) { michael@0: uint8_t idx = *p++; michael@0: for (uint8_t bit = 0x80; bit && decoded>= 1) { michael@0: // Clear pixel completely for transparency. michael@0: if (idx & bit) { michael@0: *decoded = 0; michael@0: } michael@0: decoded++; michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: bool michael@0: nsICODecoder::WriteToContainedDecoder(const char* aBuffer, uint32_t aCount, DecodeStrategy aStrategy) michael@0: { michael@0: mContainedDecoder->Write(aBuffer, aCount, aStrategy); michael@0: if (mContainedDecoder->HasDataError()) { michael@0: mDataError = mContainedDecoder->HasDataError(); michael@0: } michael@0: if (mContainedDecoder->HasDecoderError()) { michael@0: PostDecoderError(mContainedDecoder->GetDecoderError()); michael@0: } michael@0: return !HasError(); michael@0: } michael@0: michael@0: void michael@0: nsICODecoder::ProcessDirEntry(IconDirEntry& aTarget) michael@0: { michael@0: memset(&aTarget, 0, sizeof(aTarget)); michael@0: memcpy(&aTarget.mWidth, mDirEntryArray, sizeof(aTarget.mWidth)); michael@0: memcpy(&aTarget.mHeight, mDirEntryArray + 1, sizeof(aTarget.mHeight)); michael@0: memcpy(&aTarget.mColorCount, mDirEntryArray + 2, sizeof(aTarget.mColorCount)); michael@0: memcpy(&aTarget.mReserved, mDirEntryArray + 3, sizeof(aTarget.mReserved)); michael@0: memcpy(&aTarget.mPlanes, mDirEntryArray + 4, sizeof(aTarget.mPlanes)); michael@0: aTarget.mPlanes = LittleEndian::readUint16(&aTarget.mPlanes); michael@0: memcpy(&aTarget.mBitCount, mDirEntryArray + 6, sizeof(aTarget.mBitCount)); michael@0: aTarget.mBitCount = LittleEndian::readUint16(&aTarget.mBitCount); michael@0: memcpy(&aTarget.mBytesInRes, mDirEntryArray + 8, sizeof(aTarget.mBytesInRes)); michael@0: aTarget.mBytesInRes = LittleEndian::readUint32(&aTarget.mBytesInRes); michael@0: memcpy(&aTarget.mImageOffset, mDirEntryArray + 12, michael@0: sizeof(aTarget.mImageOffset)); michael@0: aTarget.mImageOffset = LittleEndian::readUint32(&aTarget.mImageOffset); michael@0: } michael@0: michael@0: bool michael@0: nsICODecoder::NeedsNewFrame() const michael@0: { michael@0: if (mContainedDecoder) { michael@0: return mContainedDecoder->NeedsNewFrame(); michael@0: } michael@0: michael@0: return Decoder::NeedsNewFrame(); michael@0: } michael@0: michael@0: nsresult michael@0: nsICODecoder::AllocateFrame() michael@0: { michael@0: if (mContainedDecoder) { michael@0: nsresult rv = mContainedDecoder->AllocateFrame(); michael@0: mCurrentFrame = mContainedDecoder->GetCurrentFrame(); michael@0: return rv; michael@0: } michael@0: michael@0: return Decoder::AllocateFrame(); michael@0: } michael@0: michael@0: } // namespace image michael@0: } // namespace mozilla