LCOV - code coverage report
Current view: directory - image/decoders - nsICODecoder.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 284 218 76.8 %
Date: 2012-06-02 Functions: 14 13 92.9 %

       1                 : /* vim:set tw=80 expandtab softtabstop=4 ts=4 sw=4: */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is the Mozilla ICO Decoder.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Netscape.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 2001
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   David Hyatt <hyatt@netscape.com> (Original Author)
      24                 :  *   Christian Biesinger <cbiesinger@web.de>
      25                 :  *   Bobby Holley <bobbyholley@gmail.com>
      26                 :  *   Brian R. Bondy <netzen@gmail.com>
      27                 :  *
      28                 :  * Alternatively, the contents of this file may be used under the terms of
      29                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      30                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      31                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      32                 :  * of those above. If you wish to allow use of your version of this file only
      33                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      34                 :  * use your version of this file under the terms of the MPL, indicate your
      35                 :  * decision by deleting the provisions above and replace them with the notice
      36                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      37                 :  * the provisions above, a recipient may use your version of this file under
      38                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      39                 :  *
      40                 :  * ***** END LICENSE BLOCK ***** */
      41                 : 
      42                 : /* This is a Cross-Platform ICO Decoder, which should work everywhere, including
      43                 :  * Big-Endian machines like the PowerPC. */
      44                 : 
      45                 : #include <stdlib.h>
      46                 : 
      47                 : #include "EndianMacros.h"
      48                 : #include "nsICODecoder.h"
      49                 : 
      50                 : #include "nsIInputStream.h"
      51                 : #include "nsIComponentManager.h"
      52                 : #include "RasterImage.h"
      53                 : #include "imgIContainerObserver.h"
      54                 : 
      55                 : #include "nsIProperties.h"
      56                 : #include "nsISupportsPrimitives.h"
      57                 : 
      58                 : namespace mozilla {
      59                 : namespace image {
      60                 : 
      61                 : #define ICONCOUNTOFFSET 4
      62                 : #define DIRENTRYOFFSET 6
      63                 : #define BITMAPINFOSIZE 40
      64                 : #define PREFICONSIZE 16
      65                 : 
      66                 : // ----------------------------------------
      67                 : // Actual Data Processing
      68                 : // ----------------------------------------
      69                 : 
      70                 : PRUint32
      71               0 : nsICODecoder::CalcAlphaRowSize() 
      72                 : {
      73                 :   // Calculate rowsize in DWORD's and then return in # of bytes
      74               0 :   PRUint32 rowSize = (GetRealWidth() + 31) / 32; // + 31 to round up
      75               0 :   return rowSize * 4; // Return rowSize in bytes
      76                 : }
      77                 : 
      78                 : // Obtains the number of colors from the bits per pixel
      79                 : PRUint16
      80              13 : nsICODecoder::GetNumColors() 
      81                 : {
      82              13 :   PRUint16 numColors = 0;
      83              13 :   if (mBPP <= 8) {
      84              11 :     switch (mBPP) {
      85                 :     case 1:
      86               0 :       numColors = 2;
      87               0 :       break;
      88                 :     case 4:
      89               0 :       numColors = 16;
      90               0 :       break;
      91                 :     case 8:
      92              11 :       numColors = 256;
      93              11 :       break;
      94                 :     default:
      95               0 :       numColors = (PRUint16)-1;
      96                 :     }
      97                 :   }
      98              13 :   return numColors;
      99                 : }
     100                 : 
     101                 : 
     102               5 : nsICODecoder::nsICODecoder(RasterImage &aImage, imgIDecoderObserver* aObserver)
     103               5 :  : Decoder(aImage, aObserver)
     104                 : {
     105               5 :   mPos = mImageOffset = mCurrIcon = mNumIcons = mBPP = mRowBytes = 0;
     106               5 :   mIsPNG = false;
     107               5 :   mRow = nsnull;
     108               5 :   mOldLine = mCurLine = 1; // Otherwise decoder will never start
     109               5 : }
     110                 : 
     111              15 : nsICODecoder::~nsICODecoder()
     112                 : {
     113               5 :   if (mRow) {
     114               3 :     moz_free(mRow);
     115                 :   }
     116              20 : }
     117                 : 
     118                 : void
     119               4 : nsICODecoder::FinishInternal()
     120                 : {
     121                 :   // We shouldn't be called in error cases
     122               4 :   NS_ABORT_IF_FALSE(!HasError(), "Shouldn't call FinishInternal after error!");
     123                 : 
     124                 :   // Finish the internally used decoder as well
     125               4 :   if (mContainedDecoder) {
     126               4 :     mContainedDecoder->FinishSharedDecoder();
     127               4 :     mDecodeDone = mContainedDecoder->GetDecodeDone();
     128                 :   }
     129               4 : }
     130                 : 
     131                 : // Returns a buffer filled with the bitmap file header in little endian:
     132                 : // Signature 2 bytes 'BM'
     133                 : // FileSize      4 bytes File size in bytes
     134                 : // reserved      4 bytes unused (=0)
     135                 : // DataOffset    4 bytes File offset to Raster Data
     136                 : // Returns true if successful
     137               4 : bool nsICODecoder::FillBitmapFileHeaderBuffer(PRInt8 *bfh) 
     138                 : {
     139               4 :   memset(bfh, 0, 14);
     140               4 :   bfh[0] = 'B';
     141               4 :   bfh[1] = 'M';
     142               4 :   PRInt32 dataOffset = 0;
     143               4 :   PRInt32 fileSize = 0;
     144               4 :   dataOffset = BFH_LENGTH + BITMAPINFOSIZE;
     145                 : 
     146                 :   // The color table is present only if BPP is <= 8
     147               4 :   if (mDirEntry.mBitCount <= 8) {
     148               3 :     PRUint16 numColors = GetNumColors();
     149               3 :     if (numColors == (PRUint16)-1) {
     150               0 :       return false;
     151                 :     }
     152               3 :     dataOffset += 4 * numColors;
     153               3 :     fileSize = dataOffset + GetRealWidth() * GetRealHeight();
     154                 :   } else {
     155               1 :     fileSize = dataOffset + (mDirEntry.mBitCount * GetRealWidth() * 
     156               2 :                              GetRealHeight()) / 8;
     157                 :   }
     158                 : 
     159               4 :   fileSize = NATIVE32_TO_LITTLE(fileSize);
     160               4 :   memcpy(bfh + 2, &fileSize, sizeof(fileSize));
     161               4 :   dataOffset = NATIVE32_TO_LITTLE(dataOffset);
     162               4 :   memcpy(bfh + 10, &dataOffset, sizeof(dataOffset));
     163               4 :   return true;
     164                 : }
     165                 : 
     166                 : // A BMP inside of an ICO has *2 height because of the AND mask
     167                 : // that follows the actual bitmap.  The BMP shouldn't know about
     168                 : // this difference though.
     169                 : bool
     170               4 : nsICODecoder::FixBitmapHeight(PRInt8 *bih) 
     171                 : {
     172                 :   // Get the height from the BMP file information header
     173                 :   PRInt32 height;
     174               4 :   memcpy(&height, bih + 8, sizeof(height));
     175               4 :   height = LITTLE_TO_NATIVE32(height);
     176                 : 
     177                 :   // The bitmap height is by definition * 2 what it should be to account for
     178                 :   // the 'AND mask'. It is * 2 even if the `AND mask` is not present.
     179               4 :   height /= 2;
     180                 : 
     181               4 :   if (height > 256) {
     182               0 :     return false;
     183                 :   }
     184                 : 
     185                 :   // We should always trust the height from the bitmap itself instead of 
     186                 :   // the ICO height.  So fix the ICO height.
     187               4 :   if (height == 256) {
     188               0 :     mDirEntry.mHeight = 0;
     189                 :   } else {
     190               4 :     mDirEntry.mHeight = (PRInt8)height;
     191                 :   }
     192                 : 
     193                 :   // Fix the BMP height in the BIH so that the BMP decoder can work properly
     194               4 :   height = NATIVE32_TO_LITTLE(height);
     195               4 :   memcpy(bih + 8, &height, sizeof(height));
     196               4 :   return true;
     197                 : }
     198                 : 
     199                 : // We should always trust the contained resource for the width
     200                 : // information over our own information.
     201                 : bool
     202               4 : nsICODecoder::FixBitmapWidth(PRInt8 *bih) 
     203                 : {
     204                 :   // Get the width from the BMP file information header
     205                 :   PRInt32 width;
     206               4 :   memcpy(&width, bih + 4, sizeof(width));
     207               4 :   width = LITTLE_TO_NATIVE32(width);
     208               4 :   if (width > 256) {
     209               0 :     return false;
     210                 :   }
     211                 : 
     212                 :   // We should always trust the width  from the bitmap itself instead of 
     213                 :   // the ICO width.
     214               4 :   if (width == 256) {
     215               0 :     mDirEntry.mWidth = 0;
     216                 :   } else {
     217               4 :     mDirEntry.mWidth = (PRInt8)width;
     218                 :   }
     219               4 :   return true;
     220                 : }
     221                 : 
     222                 : // The BMP information header's bits per pixel should be trusted
     223                 : // more than what we have.  Usually the ICO's BPP is set to 0
     224                 : PRInt32 
     225               4 : nsICODecoder::ExtractBPPFromBitmap(PRInt8 *bih)
     226                 : {
     227                 :   PRInt32 bitsPerPixel;
     228               4 :   memcpy(&bitsPerPixel, bih + 14, sizeof(bitsPerPixel));
     229               4 :   bitsPerPixel = LITTLE_TO_NATIVE32(bitsPerPixel);
     230               4 :   return bitsPerPixel;
     231                 : }
     232                 : 
     233                 : PRInt32 
     234               5 : nsICODecoder::ExtractBIHSizeFromBitmap(PRInt8 *bih)
     235                 : {
     236                 :   PRInt32 headerSize;
     237               5 :   memcpy(&headerSize, bih, sizeof(headerSize));
     238               5 :   headerSize = LITTLE_TO_NATIVE32(headerSize);
     239               5 :   return headerSize;
     240                 : }
     241                 : 
     242                 : void
     243               4 : nsICODecoder::SetHotSpotIfCursor() {
     244               4 :   if (!mIsCursor) {
     245               4 :     return;
     246                 :   }
     247                 : 
     248                 :   nsCOMPtr<nsISupportsPRUint32> intwrapx = 
     249               0 :     do_CreateInstance("@mozilla.org/supports-PRUint32;1");
     250                 :   nsCOMPtr<nsISupportsPRUint32> intwrapy = 
     251               0 :     do_CreateInstance("@mozilla.org/supports-PRUint32;1");
     252                 : 
     253               0 :   if (intwrapx && intwrapy) {
     254               0 :     intwrapx->SetData(mDirEntry.mXHotspot);
     255               0 :     intwrapy->SetData(mDirEntry.mYHotspot);
     256                 : 
     257               0 :     mImage.Set("hotspotX", intwrapx);
     258               0 :     mImage.Set("hotspotY", intwrapy);
     259                 :   }
     260                 : }
     261                 : 
     262                 : void
     263              19 : nsICODecoder::WriteInternal(const char* aBuffer, PRUint32 aCount)
     264                 : {
     265              19 :   NS_ABORT_IF_FALSE(!HasError(), "Shouldn't call WriteInternal after error!");
     266                 : 
     267              19 :   if (!aCount) // aCount=0 means EOF
     268               0 :     return;
     269                 : 
     270              58 :   while (aCount && (mPos < ICONCOUNTOFFSET)) { // Skip to the # of icons.
     271              20 :     if (mPos == 2) { // if the third byte is 1: This is an icon, 2: a cursor
     272               5 :       if ((*aBuffer != 1) && (*aBuffer != 2)) {
     273               0 :         PostDataError();
     274               0 :         return;
     275                 :       }
     276               5 :       mIsCursor = (*aBuffer == 2);
     277                 :     }
     278              20 :     mPos++; aBuffer++; aCount--;
     279                 :   }
     280                 : 
     281              19 :   if (mPos == ICONCOUNTOFFSET && aCount >= 2) {
     282               5 :     mNumIcons = LITTLE_TO_NATIVE16(((PRUint16*)aBuffer)[0]);
     283               5 :     aBuffer += 2;
     284               5 :     mPos += 2;
     285               5 :     aCount -= 2;
     286                 :   }
     287                 : 
     288              19 :   if (mNumIcons == 0)
     289               0 :     return; // Nothing to do.
     290                 : 
     291              19 :   PRUint16 colorDepth = 0;
     292                 :   // Loop through each entry's dir entry
     293              60 :   while (mCurrIcon < mNumIcons) { 
     294              22 :     if (mPos >= DIRENTRYOFFSET + (mCurrIcon * sizeof(mDirEntryArray)) && 
     295                 :         mPos < DIRENTRYOFFSET + ((mCurrIcon + 1) * sizeof(mDirEntryArray))) {
     296                 :       PRUint32 toCopy = sizeof(mDirEntryArray) - 
     297              22 :                         (mPos - DIRENTRYOFFSET - mCurrIcon * sizeof(mDirEntryArray));
     298              22 :       if (toCopy > aCount) {
     299               0 :         toCopy = aCount;
     300                 :       }
     301              22 :       memcpy(mDirEntryArray + sizeof(mDirEntryArray) - toCopy, aBuffer, toCopy);
     302              22 :       mPos += toCopy;
     303              22 :       aCount -= toCopy;
     304              22 :       aBuffer += toCopy;
     305                 :     }
     306              22 :     if (aCount == 0)
     307               0 :       return; // Need more data
     308                 : 
     309                 :     IconDirEntry e;
     310              22 :     if (mPos == (DIRENTRYOFFSET + ICODIRENTRYSIZE) + 
     311                 :                 (mCurrIcon * sizeof(mDirEntryArray))) {
     312              22 :       mCurrIcon++;
     313              22 :       ProcessDirEntry(e);
     314                 :       // We can't use GetRealWidth and GetRealHeight here because those operate
     315                 :       // on mDirEntry, here we are going through each item in the directory
     316              22 :       if (((e.mWidth == 0 ? 256 : e.mWidth) == PREFICONSIZE && 
     317                 :            (e.mHeight == 0 ? 256 : e.mHeight) == PREFICONSIZE && 
     318                 :            (e.mBitCount >= colorDepth)) ||
     319                 :           (mCurrIcon == mNumIcons && mImageOffset == 0)) {
     320               8 :         mImageOffset = e.mImageOffset;
     321                 : 
     322                 :         // ensure mImageOffset is >= size of the direntry headers (bug #245631)
     323                 :         PRUint32 minImageOffset = DIRENTRYOFFSET + 
     324               8 :                                   mNumIcons * sizeof(mDirEntryArray);
     325               8 :         if (mImageOffset < minImageOffset) {
     326               0 :           PostDataError();
     327               0 :           return;
     328                 :         }
     329                 : 
     330               8 :         colorDepth = e.mBitCount;
     331               8 :         memcpy(&mDirEntry, &e, sizeof(IconDirEntry));
     332                 :       }
     333                 :     }
     334                 :   }
     335                 : 
     336              19 :   if (mPos < mImageOffset) {
     337                 :     // Skip to (or at least towards) the desired image offset
     338              14 :     PRUint32 toSkip = mImageOffset - mPos;
     339              14 :     if (toSkip > aCount)
     340              12 :       toSkip = aCount;
     341                 : 
     342              14 :     mPos    += toSkip;
     343              14 :     aBuffer += toSkip;
     344              14 :     aCount  -= toSkip;
     345                 :   }
     346                 : 
     347                 :   // If we are within the first PNGSIGNATURESIZE bytes of the image data,
     348                 :   // then we have either a BMP or a PNG.  We use the first PNGSIGNATURESIZE
     349                 :   // bytes to determine which one we have.
     350              19 :   if (mCurrIcon == mNumIcons && mPos >= mImageOffset && 
     351                 :       mPos < mImageOffset + PNGSIGNATURESIZE)
     352                 :   {
     353               5 :     PRUint32 toCopy = PNGSIGNATURESIZE - (mPos - mImageOffset);
     354               5 :     if (toCopy > aCount) {
     355               0 :       toCopy = aCount;
     356                 :     }
     357                 : 
     358               5 :     memcpy(mSignature + (mPos - mImageOffset), aBuffer, toCopy);
     359               5 :     mPos += toCopy;
     360               5 :     aCount -= toCopy;
     361               5 :     aBuffer += toCopy;
     362                 : 
     363                 :     mIsPNG = !memcmp(mSignature, nsPNGDecoder::pngSignatureBytes, 
     364               5 :                      PNGSIGNATURESIZE);
     365               5 :     if (mIsPNG) {
     366               0 :       mContainedDecoder = new nsPNGDecoder(mImage, mObserver);
     367               0 :       mContainedDecoder->InitSharedDecoder();
     368               0 :       mContainedDecoder->Write(mSignature, PNGSIGNATURESIZE);
     369               0 :       mDataError = mContainedDecoder->HasDataError();
     370               0 :       if (mContainedDecoder->HasDataError()) {
     371               0 :         return;
     372                 :       }
     373                 :     }
     374                 :   }
     375                 : 
     376                 :   // If we have a PNG, let the PNG decoder do all of the rest of the work
     377              19 :   if (mIsPNG && mContainedDecoder && mPos >= mImageOffset + PNGSIGNATURESIZE) {
     378               0 :     mContainedDecoder->Write(aBuffer, aCount);
     379               0 :     mDataError = mContainedDecoder->HasDataError();
     380               0 :     if (mContainedDecoder->HasDataError()) {
     381               0 :       return;
     382                 :     }
     383               0 :     mPos += aCount;
     384               0 :     aBuffer += aCount;
     385               0 :     aCount = 0;
     386                 : 
     387                 :     // Raymond Chen says that 32bpp only are valid PNG ICOs
     388                 :     // http://blogs.msdn.com/b/oldnewthing/archive/2010/10/22/10079192.aspx
     389               0 :     if (!static_cast<nsPNGDecoder*>(mContainedDecoder.get())->IsValidICO()) {
     390               0 :       PostDataError();
     391                 :     }
     392               0 :     return;
     393                 :   }
     394                 : 
     395                 :   // We've processed all of the icon dir entries and are within the 
     396                 :   // bitmap info size
     397              19 :   if (!mIsPNG && mCurrIcon == mNumIcons && mPos >= mImageOffset && 
     398                 :       mPos >= mImageOffset + PNGSIGNATURESIZE && 
     399                 :       mPos < mImageOffset + BITMAPINFOSIZE) {
     400                 : 
     401                 :     // As we were decoding, we did not know if we had a PNG signature or the
     402                 :     // start of a bitmap information header.  At this point we know we had
     403                 :     // a bitmap information header and not a PNG signature, so fill the bitmap
     404                 :     // information header with the data it should already have.
     405               5 :     memcpy(mBIHraw, mSignature, PNGSIGNATURESIZE);
     406                 : 
     407                 :     // We've found the icon.
     408               5 :     PRUint32 toCopy = sizeof(mBIHraw) - (mPos - mImageOffset);
     409               5 :     if (toCopy > aCount)
     410               0 :       toCopy = aCount;
     411                 : 
     412               5 :     memcpy(mBIHraw + (mPos - mImageOffset), aBuffer, toCopy);
     413               5 :     mPos += toCopy;
     414               5 :     aCount -= toCopy;
     415               5 :     aBuffer += toCopy;
     416                 :   }
     417                 : 
     418                 :   // If we have a BMP inside the ICO and we have read the BIH header
     419              19 :   if (!mIsPNG && mPos == mImageOffset + BITMAPINFOSIZE) {
     420                 : 
     421                 :     // Make sure we have a sane value for the bitmap information header
     422               5 :     PRInt32 bihSize = ExtractBIHSizeFromBitmap(reinterpret_cast<PRInt8*>(mBIHraw));
     423               5 :     if (bihSize != BITMAPINFOSIZE) {
     424               1 :       PostDataError();
     425               1 :       return;
     426                 :     }
     427                 :     // We are extracting the BPP from the BIH header as it should be trusted 
     428                 :     // over the one we have from the icon header
     429               4 :     mBPP = ExtractBPPFromBitmap(reinterpret_cast<PRInt8*>(mBIHraw));
     430                 :     
     431                 :     // Init the bitmap decoder which will do most of the work for us
     432                 :     // It will do everything except the AND mask which isn't present in bitmaps
     433                 :     // bmpDecoder is for local scope ease, it will be freed by mContainedDecoder
     434               8 :     nsBMPDecoder *bmpDecoder = new nsBMPDecoder(mImage, mObserver); 
     435               4 :     mContainedDecoder = bmpDecoder;
     436               4 :     bmpDecoder->SetUseAlphaData(true);
     437               4 :     mContainedDecoder->SetSizeDecode(IsSizeDecode());
     438               4 :     mContainedDecoder->InitSharedDecoder();
     439                 : 
     440                 :     // The ICO format when containing a BMP does not include the 14 byte
     441                 :     // bitmap file header. To use the code of the BMP decoder we need to 
     442                 :     // generate this header ourselves and feed it to the BMP decoder.
     443                 :     PRInt8 bfhBuffer[BMPFILEHEADERSIZE];
     444               4 :     if (!FillBitmapFileHeaderBuffer(bfhBuffer)) {
     445               0 :       PostDataError();
     446               0 :       return;
     447                 :     }
     448               4 :     mContainedDecoder->Write((const char*)bfhBuffer, sizeof(bfhBuffer));
     449               4 :     mDataError = mContainedDecoder->HasDataError();
     450               4 :     if (mContainedDecoder->HasDataError()) {
     451               0 :       return;
     452                 :     }
     453                 : 
     454                 :     // Setup the cursor hot spot if one is present
     455               4 :     SetHotSpotIfCursor();
     456                 : 
     457                 :     // Fix the ICO height from the BIH.
     458                 :     // Fix the height on the BIH to be /2 so our BMP decoder will understand.
     459               4 :     if (!FixBitmapHeight(reinterpret_cast<PRInt8*>(mBIHraw))) {
     460               0 :       PostDataError();
     461               0 :       return;
     462                 :     }
     463                 : 
     464                 :     // Fix the ICO width from the BIH.
     465               4 :     if (!FixBitmapWidth(reinterpret_cast<PRInt8*>(mBIHraw))) {
     466               0 :       PostDataError();
     467               0 :       return;
     468                 :     }
     469                 : 
     470                 :     // Write out the BMP's bitmap info header
     471               4 :     mContainedDecoder->Write(mBIHraw, sizeof(mBIHraw));
     472               4 :     mDataError = mContainedDecoder->HasDataError();
     473               4 :     if (mContainedDecoder->HasDataError()) {
     474               0 :       return;
     475                 :     }
     476                 : 
     477                 :     // We have the size. If we're doing a size decode, we got what
     478                 :     // we came for.
     479               4 :     if (IsSizeDecode())
     480               0 :       return;
     481                 : 
     482                 :     // Sometimes the ICO BPP header field is not filled out
     483                 :     // so we should trust the contained resource over our own
     484                 :     // information.
     485               4 :     mBPP = bmpDecoder->GetBitsPerPixel();
     486                 : 
     487                 :     // Check to make sure we have valid color settings
     488               4 :     PRUint16 numColors = GetNumColors();
     489               4 :     if (numColors == (PRUint16)-1) {
     490               0 :       PostDataError();
     491               0 :       return;
     492                 :     }
     493                 :   }
     494                 : 
     495                 :   // If we have a BMP
     496              18 :   if (!mIsPNG && mContainedDecoder && mPos >= mImageOffset + BITMAPINFOSIZE) {
     497               6 :     PRUint16 numColors = GetNumColors();
     498               6 :     if (numColors == (PRUint16)-1) {
     499               0 :       PostDataError();
     500               0 :       return;
     501                 :     }
     502                 :     // Feed the actual image data (not including headers) into the BMP decoder
     503               6 :     PRInt32 bmpDataOffset = mDirEntry.mImageOffset + BITMAPINFOSIZE;
     504                 :     PRInt32 bmpDataEnd = mDirEntry.mImageOffset + BITMAPINFOSIZE + 
     505               6 :                          static_cast<nsBMPDecoder*>(mContainedDecoder.get())->GetCompressedImageSize() +
     506              12 :                          4 * numColors;
     507                 : 
     508                 :     // If we are feeding in the core image data, but we have not yet
     509                 :     // reached the ICO's 'AND buffer mask'
     510               6 :     if (mPos >= bmpDataOffset && mPos < bmpDataEnd) {
     511                 : 
     512                 :       // Figure out how much data the BMP decoder wants
     513               6 :       PRUint32 toFeed = bmpDataEnd - mPos;
     514               6 :       if (toFeed > aCount) {
     515               2 :         toFeed = aCount;
     516                 :       }
     517                 : 
     518               6 :       mContainedDecoder->Write(aBuffer, toFeed);
     519               6 :       mDataError = mContainedDecoder->HasDataError();
     520               6 :       if (mContainedDecoder->HasDataError()) {
     521               0 :         return;
     522                 :       }
     523                 : 
     524               6 :       mPos += toFeed;
     525               6 :       aCount -= toFeed;
     526               6 :       aBuffer += toFeed;
     527                 :     }
     528                 :   
     529                 :     // If the bitmap is fully processed, treat any left over data as the ICO's
     530                 :     // 'AND buffer mask' which appears after the bitmap resource.
     531               6 :     if (!mIsPNG && mPos >= bmpDataEnd) {
     532                 :       // There may be an optional AND bit mask after the data.  This is
     533                 :       // only used if the alpha data is not already set. The alpha data 
     534                 :       // is used for 32bpp bitmaps as per the comment in ICODecoder.h
     535                 :       // The alpha mask should be checked in all other cases.
     536               5 :       if (static_cast<nsBMPDecoder*>(mContainedDecoder.get())->GetBitsPerPixel() != 32 || 
     537               1 :           !static_cast<nsBMPDecoder*>(mContainedDecoder.get())->HasAlphaData()) {
     538               3 :         PRUint32 rowSize = ((GetRealWidth() + 31) / 32) * 4; // + 31 to round up
     539               3 :         if (mPos == bmpDataEnd) {
     540               3 :           mPos++;
     541               3 :           mRowBytes = 0;
     542               3 :           mCurLine = GetRealHeight();
     543               3 :           mRow = (PRUint8*)moz_realloc(mRow, rowSize);
     544               3 :           if (!mRow) {
     545               0 :             PostDecoderError(NS_ERROR_OUT_OF_MEMORY);
     546               0 :             return;
     547                 :           }
     548                 :         }
     549                 : 
     550                 :         // Ensure memory has been allocated before decoding.
     551               3 :         NS_ABORT_IF_FALSE(mRow, "mRow is null");
     552               3 :         if (!mRow) {
     553               0 :           PostDataError();
     554               0 :           return;
     555                 :         }
     556                 : 
     557              54 :         while (mCurLine > 0 && aCount > 0) {
     558              48 :           PRUint32 toCopy = NS_MIN(rowSize - mRowBytes, aCount);
     559              48 :           if (toCopy) {
     560              48 :             memcpy(mRow + mRowBytes, aBuffer, toCopy);
     561              48 :             aCount -= toCopy;
     562              48 :             aBuffer += toCopy;
     563              48 :             mRowBytes += toCopy;
     564                 :           }
     565              48 :           if (rowSize == mRowBytes) {
     566              48 :             mCurLine--;
     567              48 :             mRowBytes = 0;
     568                 : 
     569                 :             PRUint32* imageData = 
     570              48 :               static_cast<nsBMPDecoder*>(mContainedDecoder.get())->GetImageData();
     571              48 :             if (!imageData) {
     572               0 :               PostDataError();
     573               0 :               return;
     574                 :             }
     575              48 :             PRUint32* decoded = imageData + mCurLine * GetRealWidth();
     576              48 :             PRUint32* decoded_end = decoded + GetRealWidth();
     577              48 :             PRUint8* p = mRow, *p_end = mRow + rowSize; 
     578             288 :             while (p < p_end) {
     579             192 :               PRUint8 idx = *p++;
     580             960 :               for (PRUint8 bit = 0x80; bit && decoded<decoded_end; bit >>= 1) {
     581                 :                 // Clear pixel completely for transparency.
     582             768 :                 if (idx & bit) {
     583             282 :                   *decoded = 0;
     584                 :                 }
     585             768 :                 decoded++;
     586                 :               }
     587                 :             }
     588                 :           }
     589                 :         }
     590                 :       }
     591                 :     }
     592                 :   }
     593                 : }
     594                 : 
     595                 : void
     596              22 : nsICODecoder::ProcessDirEntry(IconDirEntry& aTarget)
     597                 : {
     598              22 :   memset(&aTarget, 0, sizeof(aTarget));
     599              22 :   memcpy(&aTarget.mWidth, mDirEntryArray, sizeof(aTarget.mWidth));
     600              22 :   memcpy(&aTarget.mHeight, mDirEntryArray + 1, sizeof(aTarget.mHeight));
     601              22 :   memcpy(&aTarget.mColorCount, mDirEntryArray + 2, sizeof(aTarget.mColorCount));
     602              22 :   memcpy(&aTarget.mReserved, mDirEntryArray + 3, sizeof(aTarget.mReserved));
     603              22 :   memcpy(&aTarget.mPlanes, mDirEntryArray + 4, sizeof(aTarget.mPlanes));
     604              22 :   aTarget.mPlanes = LITTLE_TO_NATIVE16(aTarget.mPlanes);
     605              22 :   memcpy(&aTarget.mBitCount, mDirEntryArray + 6, sizeof(aTarget.mBitCount));
     606              22 :   aTarget.mBitCount = LITTLE_TO_NATIVE16(aTarget.mBitCount);
     607              22 :   memcpy(&aTarget.mBytesInRes, mDirEntryArray + 8, sizeof(aTarget.mBytesInRes));
     608              22 :   aTarget.mBytesInRes = LITTLE_TO_NATIVE32(aTarget.mBytesInRes);
     609                 :   memcpy(&aTarget.mImageOffset, mDirEntryArray + 12, 
     610              22 :          sizeof(aTarget.mImageOffset));
     611              22 :   aTarget.mImageOffset = LITTLE_TO_NATIVE32(aTarget.mImageOffset);
     612              22 : }
     613                 : 
     614                 : } // namespace image
     615                 : } // namespace mozilla

Generated by: LCOV version 1.7