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
|