image/decoders/nsICODecoder.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* vim:set tw=80 expandtab softtabstop=4 ts=4 sw=4: */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 /* This is a Cross-Platform ICO Decoder, which should work everywhere, including
     7  * Big-Endian machines like the PowerPC. */
     9 #include <stdlib.h>
    11 #include "mozilla/Endian.h"
    12 #include "nsICODecoder.h"
    14 #include "RasterImage.h"
    16 namespace mozilla {
    17 namespace image {
    19 #define ICONCOUNTOFFSET 4
    20 #define DIRENTRYOFFSET 6
    21 #define BITMAPINFOSIZE 40
    22 #define PREFICONSIZE 16
    24 // ----------------------------------------
    25 // Actual Data Processing
    26 // ----------------------------------------
    28 uint32_t
    29 nsICODecoder::CalcAlphaRowSize() 
    30 {
    31   // Calculate rowsize in DWORD's and then return in # of bytes
    32   uint32_t rowSize = (GetRealWidth() + 31) / 32; // + 31 to round up
    33   return rowSize * 4; // Return rowSize in bytes
    34 }
    36 // Obtains the number of colors from the bits per pixel
    37 uint16_t
    38 nsICODecoder::GetNumColors() 
    39 {
    40   uint16_t numColors = 0;
    41   if (mBPP <= 8) {
    42     switch (mBPP) {
    43     case 1:
    44       numColors = 2;
    45       break;
    46     case 4:
    47       numColors = 16;
    48       break;
    49     case 8:
    50       numColors = 256;
    51       break;
    52     default:
    53       numColors = (uint16_t)-1;
    54     }
    55   }
    56   return numColors;
    57 }
    60 nsICODecoder::nsICODecoder(RasterImage &aImage)
    61  : Decoder(aImage)
    62 {
    63   mPos = mImageOffset = mCurrIcon = mNumIcons = mBPP = mRowBytes = 0;
    64   mIsPNG = false;
    65   mRow = nullptr;
    66   mOldLine = mCurLine = 1; // Otherwise decoder will never start
    67 }
    69 nsICODecoder::~nsICODecoder()
    70 {
    71   if (mRow) {
    72     moz_free(mRow);
    73   }
    74 }
    76 void
    77 nsICODecoder::FinishInternal()
    78 {
    79   // We shouldn't be called in error cases
    80   NS_ABORT_IF_FALSE(!HasError(), "Shouldn't call FinishInternal after error!");
    82   // Finish the internally used decoder as well
    83   if (mContainedDecoder) {
    84     mContainedDecoder->FinishSharedDecoder();
    85     mDecodeDone = mContainedDecoder->GetDecodeDone();
    86   }
    87 }
    89 // Returns a buffer filled with the bitmap file header in little endian:
    90 // Signature 2 bytes 'BM'
    91 // FileSize	 4 bytes File size in bytes
    92 // reserved	 4 bytes unused (=0)
    93 // DataOffset	 4 bytes File offset to Raster Data
    94 // Returns true if successful
    95 bool nsICODecoder::FillBitmapFileHeaderBuffer(int8_t *bfh) 
    96 {
    97   memset(bfh, 0, 14);
    98   bfh[0] = 'B';
    99   bfh[1] = 'M';
   100   int32_t dataOffset = 0;
   101   int32_t fileSize = 0;
   102   dataOffset = BFH_LENGTH + BITMAPINFOSIZE;
   104   // The color table is present only if BPP is <= 8
   105   if (mDirEntry.mBitCount <= 8) {
   106     uint16_t numColors = GetNumColors();
   107     if (numColors == (uint16_t)-1) {
   108       return false;
   109     }
   110     dataOffset += 4 * numColors;
   111     fileSize = dataOffset + GetRealWidth() * GetRealHeight();
   112   } else {
   113     fileSize = dataOffset + (mDirEntry.mBitCount * GetRealWidth() * 
   114                              GetRealHeight()) / 8;
   115   }
   117   NativeEndian::swapToLittleEndianInPlace(&fileSize, 1);
   118   memcpy(bfh + 2, &fileSize, sizeof(fileSize));
   119   NativeEndian::swapToLittleEndianInPlace(&dataOffset, 1);
   120   memcpy(bfh + 10, &dataOffset, sizeof(dataOffset));
   121   return true;
   122 }
   124 // A BMP inside of an ICO has *2 height because of the AND mask
   125 // that follows the actual bitmap.  The BMP shouldn't know about
   126 // this difference though.
   127 bool
   128 nsICODecoder::FixBitmapHeight(int8_t *bih) 
   129 {
   130   // Get the height from the BMP file information header
   131   int32_t height;
   132   memcpy(&height, bih + 8, sizeof(height));
   133   NativeEndian::swapFromLittleEndianInPlace(&height, 1);
   134   // BMPs can be stored inverted by having a negative height
   135   height = abs(height);
   137   // The bitmap height is by definition * 2 what it should be to account for
   138   // the 'AND mask'. It is * 2 even if the `AND mask` is not present.
   139   height /= 2;
   141   if (height > 256) {
   142     return false;
   143   }
   145   // We should always trust the height from the bitmap itself instead of 
   146   // the ICO height.  So fix the ICO height.
   147   if (height == 256) {
   148     mDirEntry.mHeight = 0;
   149   } else {
   150     mDirEntry.mHeight = (int8_t)height;
   151   }
   153   // Fix the BMP height in the BIH so that the BMP decoder can work properly
   154   NativeEndian::swapToLittleEndianInPlace(&height, 1);
   155   memcpy(bih + 8, &height, sizeof(height));
   156   return true;
   157 }
   159 // We should always trust the contained resource for the width
   160 // information over our own information.
   161 bool
   162 nsICODecoder::FixBitmapWidth(int8_t *bih) 
   163 {
   164   // Get the width from the BMP file information header
   165   int32_t width;
   166   memcpy(&width, bih + 4, sizeof(width));
   167   NativeEndian::swapFromLittleEndianInPlace(&width, 1);
   168   if (width > 256) {
   169     return false;
   170   }
   172   // We should always trust the width  from the bitmap itself instead of 
   173   // the ICO width.
   174   if (width == 256) {
   175     mDirEntry.mWidth = 0;
   176   } else {
   177     mDirEntry.mWidth = (int8_t)width;
   178   }
   179   return true;
   180 }
   182 // The BMP information header's bits per pixel should be trusted
   183 // more than what we have.  Usually the ICO's BPP is set to 0
   184 int32_t 
   185 nsICODecoder::ExtractBPPFromBitmap(int8_t *bih)
   186 {
   187   int32_t bitsPerPixel;
   188   memcpy(&bitsPerPixel, bih + 14, sizeof(bitsPerPixel));
   189   NativeEndian::swapFromLittleEndianInPlace(&bitsPerPixel, 1);
   190   return bitsPerPixel;
   191 }
   193 int32_t 
   194 nsICODecoder::ExtractBIHSizeFromBitmap(int8_t *bih)
   195 {
   196   int32_t headerSize;
   197   memcpy(&headerSize, bih, sizeof(headerSize));
   198   NativeEndian::swapFromLittleEndianInPlace(&headerSize, 1);
   199   return headerSize;
   200 }
   202 void
   203 nsICODecoder::SetHotSpotIfCursor() {
   204   if (!mIsCursor) {
   205     return;
   206   }
   208   mImageMetadata.SetHotspot(mDirEntry.mXHotspot, mDirEntry.mYHotspot);
   209 }
   211 void
   212 nsICODecoder::WriteInternal(const char* aBuffer, uint32_t aCount, DecodeStrategy aStrategy)
   213 {
   214   NS_ABORT_IF_FALSE(!HasError(), "Shouldn't call WriteInternal after error!");
   216   if (!aCount) {
   217     if (mContainedDecoder) {
   218       WriteToContainedDecoder(aBuffer, aCount, aStrategy);
   219     }
   220     return;
   221   }
   223   while (aCount && (mPos < ICONCOUNTOFFSET)) { // Skip to the # of icons.
   224     if (mPos == 2) { // if the third byte is 1: This is an icon, 2: a cursor
   225       if ((*aBuffer != 1) && (*aBuffer != 2)) {
   226         PostDataError();
   227         return;
   228       }
   229       mIsCursor = (*aBuffer == 2);
   230     }
   231     mPos++; aBuffer++; aCount--;
   232   }
   234   if (mPos == ICONCOUNTOFFSET && aCount >= 2) {
   235     mNumIcons = LittleEndian::readUint16(reinterpret_cast<const uint16_t*>(aBuffer));
   236     aBuffer += 2;
   237     mPos += 2;
   238     aCount -= 2;
   239   }
   241   if (mNumIcons == 0)
   242     return; // Nothing to do.
   244   uint16_t colorDepth = 0;
   245   nsIntSize prefSize = mImage.GetRequestedResolution();
   246   if (prefSize.width == 0 && prefSize.height == 0) {
   247     prefSize.SizeTo(PREFICONSIZE, PREFICONSIZE);
   248   }
   250   // A measure of the difference in size between the entry we've found
   251   // and the requested size. We will choose the smallest image that is
   252   // >= requested size (i.e. we assume it's better to downscale a larger
   253   // icon than to upscale a smaller one).
   254   int32_t diff = INT_MIN;
   256   // Loop through each entry's dir entry
   257   while (mCurrIcon < mNumIcons) { 
   258     if (mPos >= DIRENTRYOFFSET + (mCurrIcon * sizeof(mDirEntryArray)) && 
   259         mPos < DIRENTRYOFFSET + ((mCurrIcon + 1) * sizeof(mDirEntryArray))) {
   260       uint32_t toCopy = sizeof(mDirEntryArray) - 
   261                         (mPos - DIRENTRYOFFSET - mCurrIcon * sizeof(mDirEntryArray));
   262       if (toCopy > aCount) {
   263         toCopy = aCount;
   264       }
   265       memcpy(mDirEntryArray + sizeof(mDirEntryArray) - toCopy, aBuffer, toCopy);
   266       mPos += toCopy;
   267       aCount -= toCopy;
   268       aBuffer += toCopy;
   269     }
   270     if (aCount == 0)
   271       return; // Need more data
   273     IconDirEntry e;
   274     if (mPos == (DIRENTRYOFFSET + ICODIRENTRYSIZE) + 
   275                 (mCurrIcon * sizeof(mDirEntryArray))) {
   276       mCurrIcon++;
   277       ProcessDirEntry(e);
   278       // We can't use GetRealWidth and GetRealHeight here because those operate
   279       // on mDirEntry, here we are going through each item in the directory.
   280       // Calculate the delta between this image's size and the desired size,
   281       // so we can see if it is better than our current-best option.
   282       // In the case of several equally-good images, we use the last one.
   283       int32_t delta = (e.mWidth == 0 ? 256 : e.mWidth) - prefSize.width +
   284                       (e.mHeight == 0 ? 256 : e.mHeight) - prefSize.height;
   285       if (e.mBitCount >= colorDepth &&
   286           ((diff < 0 && delta >= diff) || (delta >= 0 && delta <= diff))) {
   287         diff = delta;
   288         mImageOffset = e.mImageOffset;
   290         // ensure mImageOffset is >= size of the direntry headers (bug #245631)
   291         uint32_t minImageOffset = DIRENTRYOFFSET + 
   292                                   mNumIcons * sizeof(mDirEntryArray);
   293         if (mImageOffset < minImageOffset) {
   294           PostDataError();
   295           return;
   296         }
   298         colorDepth = e.mBitCount;
   299         memcpy(&mDirEntry, &e, sizeof(IconDirEntry));
   300       }
   301     }
   302   }
   304   if (mPos < mImageOffset) {
   305     // Skip to (or at least towards) the desired image offset
   306     uint32_t toSkip = mImageOffset - mPos;
   307     if (toSkip > aCount)
   308       toSkip = aCount;
   310     mPos    += toSkip;
   311     aBuffer += toSkip;
   312     aCount  -= toSkip;
   313   }
   315   // If we are within the first PNGSIGNATURESIZE bytes of the image data,
   316   // then we have either a BMP or a PNG.  We use the first PNGSIGNATURESIZE
   317   // bytes to determine which one we have.
   318   if (mCurrIcon == mNumIcons && mPos >= mImageOffset && 
   319       mPos < mImageOffset + PNGSIGNATURESIZE)
   320   {
   321     uint32_t toCopy = PNGSIGNATURESIZE - (mPos - mImageOffset);
   322     if (toCopy > aCount) {
   323       toCopy = aCount;
   324     }
   326     memcpy(mSignature + (mPos - mImageOffset), aBuffer, toCopy);
   327     mPos += toCopy;
   328     aCount -= toCopy;
   329     aBuffer += toCopy;
   331     mIsPNG = !memcmp(mSignature, nsPNGDecoder::pngSignatureBytes, 
   332                      PNGSIGNATURESIZE);
   333     if (mIsPNG) {
   334       mContainedDecoder = new nsPNGDecoder(mImage);
   335       mContainedDecoder->SetObserver(mObserver);
   336       mContainedDecoder->SetSizeDecode(IsSizeDecode());
   337       mContainedDecoder->InitSharedDecoder(mImageData, mImageDataLength,
   338                                            mColormap, mColormapSize,
   339                                            mCurrentFrame);
   340       if (!WriteToContainedDecoder(mSignature, PNGSIGNATURESIZE, aStrategy)) {
   341         return;
   342       }
   343     }
   344   }
   346   // If we have a PNG, let the PNG decoder do all of the rest of the work
   347   if (mIsPNG && mContainedDecoder && mPos >= mImageOffset + PNGSIGNATURESIZE) {
   348     if (!WriteToContainedDecoder(aBuffer, aCount, aStrategy)) {
   349       return;
   350     }
   352     if (!HasSize() && mContainedDecoder->HasSize()) {
   353       PostSize(mContainedDecoder->GetImageMetadata().GetWidth(),
   354                mContainedDecoder->GetImageMetadata().GetHeight());
   355     }
   357     mPos += aCount;
   358     aBuffer += aCount;
   359     aCount = 0;
   361     // Raymond Chen says that 32bpp only are valid PNG ICOs
   362     // http://blogs.msdn.com/b/oldnewthing/archive/2010/10/22/10079192.aspx
   363     if (!IsSizeDecode() &&
   364         !static_cast<nsPNGDecoder*>(mContainedDecoder.get())->IsValidICO()) {
   365       PostDataError();
   366     }
   367     return;
   368   }
   370   // We've processed all of the icon dir entries and are within the 
   371   // bitmap info size
   372   if (!mIsPNG && mCurrIcon == mNumIcons && mPos >= mImageOffset && 
   373       mPos >= mImageOffset + PNGSIGNATURESIZE && 
   374       mPos < mImageOffset + BITMAPINFOSIZE) {
   376     // As we were decoding, we did not know if we had a PNG signature or the
   377     // start of a bitmap information header.  At this point we know we had
   378     // a bitmap information header and not a PNG signature, so fill the bitmap
   379     // information header with the data it should already have.
   380     memcpy(mBIHraw, mSignature, PNGSIGNATURESIZE);
   382     // We've found the icon.
   383     uint32_t toCopy = sizeof(mBIHraw) - (mPos - mImageOffset);
   384     if (toCopy > aCount)
   385       toCopy = aCount;
   387     memcpy(mBIHraw + (mPos - mImageOffset), aBuffer, toCopy);
   388     mPos += toCopy;
   389     aCount -= toCopy;
   390     aBuffer += toCopy;
   391   }
   393   // If we have a BMP inside the ICO and we have read the BIH header
   394   if (!mIsPNG && mPos == mImageOffset + BITMAPINFOSIZE) {
   396     // Make sure we have a sane value for the bitmap information header
   397     int32_t bihSize = ExtractBIHSizeFromBitmap(reinterpret_cast<int8_t*>(mBIHraw));
   398     if (bihSize != BITMAPINFOSIZE) {
   399       PostDataError();
   400       return;
   401     }
   402     // We are extracting the BPP from the BIH header as it should be trusted 
   403     // over the one we have from the icon header
   404     mBPP = ExtractBPPFromBitmap(reinterpret_cast<int8_t*>(mBIHraw));
   406     // Init the bitmap decoder which will do most of the work for us
   407     // It will do everything except the AND mask which isn't present in bitmaps
   408     // bmpDecoder is for local scope ease, it will be freed by mContainedDecoder
   409     nsBMPDecoder *bmpDecoder = new nsBMPDecoder(mImage);
   410     mContainedDecoder = bmpDecoder;
   411     bmpDecoder->SetUseAlphaData(true);
   412     mContainedDecoder->SetObserver(mObserver);
   413     mContainedDecoder->SetSizeDecode(IsSizeDecode());
   414     mContainedDecoder->InitSharedDecoder(mImageData, mImageDataLength,
   415                                          mColormap, mColormapSize,
   416                                          mCurrentFrame);
   418     // The ICO format when containing a BMP does not include the 14 byte
   419     // bitmap file header. To use the code of the BMP decoder we need to 
   420     // generate this header ourselves and feed it to the BMP decoder.
   421     int8_t bfhBuffer[BMPFILEHEADERSIZE];
   422     if (!FillBitmapFileHeaderBuffer(bfhBuffer)) {
   423       PostDataError();
   424       return;
   425     }
   426     if (!WriteToContainedDecoder((const char*)bfhBuffer, sizeof(bfhBuffer), aStrategy)) {
   427       return;
   428     }
   430     // Setup the cursor hot spot if one is present
   431     SetHotSpotIfCursor();
   433     // Fix the ICO height from the BIH.
   434     // Fix the height on the BIH to be /2 so our BMP decoder will understand.
   435     if (!FixBitmapHeight(reinterpret_cast<int8_t*>(mBIHraw))) {
   436       PostDataError();
   437       return;
   438     }
   440     // Fix the ICO width from the BIH.
   441     if (!FixBitmapWidth(reinterpret_cast<int8_t*>(mBIHraw))) {
   442       PostDataError();
   443       return;
   444     }
   446     // Write out the BMP's bitmap info header
   447     if (!WriteToContainedDecoder(mBIHraw, sizeof(mBIHraw), aStrategy)) {
   448       return;
   449     }
   451     PostSize(mContainedDecoder->GetImageMetadata().GetWidth(),
   452              mContainedDecoder->GetImageMetadata().GetHeight());
   454     // We have the size. If we're doing a size decode, we got what
   455     // we came for.
   456     if (IsSizeDecode())
   457       return;
   459     // Sometimes the ICO BPP header field is not filled out
   460     // so we should trust the contained resource over our own
   461     // information.
   462     mBPP = bmpDecoder->GetBitsPerPixel();
   464     // Check to make sure we have valid color settings
   465     uint16_t numColors = GetNumColors();
   466     if (numColors == (uint16_t)-1) {
   467       PostDataError();
   468       return;
   469     }
   470   }
   472   // If we have a BMP
   473   if (!mIsPNG && mContainedDecoder && mPos >= mImageOffset + BITMAPINFOSIZE) {
   474     uint16_t numColors = GetNumColors();
   475     if (numColors == (uint16_t)-1) {
   476       PostDataError();
   477       return;
   478     }
   479     // Feed the actual image data (not including headers) into the BMP decoder
   480     uint32_t bmpDataOffset = mDirEntry.mImageOffset + BITMAPINFOSIZE;
   481     uint32_t bmpDataEnd = mDirEntry.mImageOffset + BITMAPINFOSIZE + 
   482                           static_cast<nsBMPDecoder*>(mContainedDecoder.get())->GetCompressedImageSize() +
   483                           4 * numColors;
   485     // If we are feeding in the core image data, but we have not yet
   486     // reached the ICO's 'AND buffer mask'
   487     if (mPos >= bmpDataOffset && mPos < bmpDataEnd) {
   489       // Figure out how much data the BMP decoder wants
   490       uint32_t toFeed = bmpDataEnd - mPos;
   491       if (toFeed > aCount) {
   492         toFeed = aCount;
   493       }
   495       if (!WriteToContainedDecoder(aBuffer, toFeed, aStrategy)) {
   496         return;
   497       }
   499       mPos += toFeed;
   500       aCount -= toFeed;
   501       aBuffer += toFeed;
   502     }
   504     // If the bitmap is fully processed, treat any left over data as the ICO's
   505     // 'AND buffer mask' which appears after the bitmap resource.
   506     if (!mIsPNG && mPos >= bmpDataEnd) {
   507       // There may be an optional AND bit mask after the data.  This is
   508       // only used if the alpha data is not already set. The alpha data 
   509       // is used for 32bpp bitmaps as per the comment in ICODecoder.h
   510       // The alpha mask should be checked in all other cases.
   511       if (static_cast<nsBMPDecoder*>(mContainedDecoder.get())->GetBitsPerPixel() != 32 || 
   512           !static_cast<nsBMPDecoder*>(mContainedDecoder.get())->HasAlphaData()) {
   513         uint32_t rowSize = ((GetRealWidth() + 31) / 32) * 4; // + 31 to round up
   514         if (mPos == bmpDataEnd) {
   515           mPos++;
   516           mRowBytes = 0;
   517           mCurLine = GetRealHeight();
   518           mRow = (uint8_t*)moz_realloc(mRow, rowSize);
   519           if (!mRow) {
   520             PostDecoderError(NS_ERROR_OUT_OF_MEMORY);
   521             return;
   522           }
   523         }
   525         // Ensure memory has been allocated before decoding.
   526         NS_ABORT_IF_FALSE(mRow, "mRow is null");
   527         if (!mRow) {
   528           PostDataError();
   529           return;
   530         }
   532         while (mCurLine > 0 && aCount > 0) {
   533           uint32_t toCopy = std::min(rowSize - mRowBytes, aCount);
   534           if (toCopy) {
   535             memcpy(mRow + mRowBytes, aBuffer, toCopy);
   536             aCount -= toCopy;
   537             aBuffer += toCopy;
   538             mRowBytes += toCopy;
   539           }
   540           if (rowSize == mRowBytes) {
   541             mCurLine--;
   542             mRowBytes = 0;
   544             uint32_t* imageData = 
   545               static_cast<nsBMPDecoder*>(mContainedDecoder.get())->GetImageData();
   546             if (!imageData) {
   547               PostDataError();
   548               return;
   549             }
   550             uint32_t* decoded = imageData + mCurLine * GetRealWidth();
   551             uint32_t* decoded_end = decoded + GetRealWidth();
   552             uint8_t* p = mRow, *p_end = mRow + rowSize; 
   553             while (p < p_end) {
   554               uint8_t idx = *p++;
   555               for (uint8_t bit = 0x80; bit && decoded<decoded_end; bit >>= 1) {
   556                 // Clear pixel completely for transparency.
   557                 if (idx & bit) {
   558                   *decoded = 0;
   559                 }
   560                 decoded++;
   561               }
   562             }
   563           }
   564         }
   565       }
   566     }
   567   }
   568 }
   570 bool
   571 nsICODecoder::WriteToContainedDecoder(const char* aBuffer, uint32_t aCount, DecodeStrategy aStrategy)
   572 {
   573   mContainedDecoder->Write(aBuffer, aCount, aStrategy);
   574   if (mContainedDecoder->HasDataError()) {
   575     mDataError = mContainedDecoder->HasDataError();
   576   }
   577   if (mContainedDecoder->HasDecoderError()) {
   578     PostDecoderError(mContainedDecoder->GetDecoderError());
   579   }
   580   return !HasError();
   581 }
   583 void
   584 nsICODecoder::ProcessDirEntry(IconDirEntry& aTarget)
   585 {
   586   memset(&aTarget, 0, sizeof(aTarget));
   587   memcpy(&aTarget.mWidth, mDirEntryArray, sizeof(aTarget.mWidth));
   588   memcpy(&aTarget.mHeight, mDirEntryArray + 1, sizeof(aTarget.mHeight));
   589   memcpy(&aTarget.mColorCount, mDirEntryArray + 2, sizeof(aTarget.mColorCount));
   590   memcpy(&aTarget.mReserved, mDirEntryArray + 3, sizeof(aTarget.mReserved));
   591   memcpy(&aTarget.mPlanes, mDirEntryArray + 4, sizeof(aTarget.mPlanes));
   592   aTarget.mPlanes = LittleEndian::readUint16(&aTarget.mPlanes);
   593   memcpy(&aTarget.mBitCount, mDirEntryArray + 6, sizeof(aTarget.mBitCount));
   594   aTarget.mBitCount = LittleEndian::readUint16(&aTarget.mBitCount);
   595   memcpy(&aTarget.mBytesInRes, mDirEntryArray + 8, sizeof(aTarget.mBytesInRes));
   596   aTarget.mBytesInRes = LittleEndian::readUint32(&aTarget.mBytesInRes);
   597   memcpy(&aTarget.mImageOffset, mDirEntryArray + 12, 
   598          sizeof(aTarget.mImageOffset));
   599   aTarget.mImageOffset = LittleEndian::readUint32(&aTarget.mImageOffset);
   600 }
   602 bool
   603 nsICODecoder::NeedsNewFrame() const
   604 {
   605   if (mContainedDecoder) {
   606     return mContainedDecoder->NeedsNewFrame();
   607   }
   609   return Decoder::NeedsNewFrame();
   610 }
   612 nsresult
   613 nsICODecoder::AllocateFrame()
   614 {
   615   if (mContainedDecoder) {
   616     nsresult rv = mContainedDecoder->AllocateFrame();
   617     mCurrentFrame = mContainedDecoder->GetCurrentFrame();
   618     return rv;
   619   }
   621   return Decoder::AllocateFrame();
   622 }
   624 } // namespace image
   625 } // namespace mozilla

mercurial