bug 772897 - implement addon manager ui for click-to-play plugins r=unfocused
[gecko.git] / image / decoders / nsBMPDecoder.cpp
blobd6d9377a2892efbcfb54f15fb6101da7a1e801f9
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/. */
5 /* I got the format description from http://www.daubnet.com/formats/BMP.html */
7 /* This is a Cross-Platform BMP Decoder, which should work everywhere, including
8 * Big-Endian machines like the PowerPC. */
10 #include <stdlib.h>
12 #include "EndianMacros.h"
13 #include "nsBMPDecoder.h"
15 #include "nsIInputStream.h"
16 #include "RasterImage.h"
17 #include "imgIContainerObserver.h"
18 #include "ImageLogging.h"
20 namespace mozilla {
21 namespace image {
23 #ifdef PR_LOGGING
24 PRLogModuleInfo *gBMPLog = PR_NewLogModule("BMPDecoder");
25 #endif
27 // Convert from row (1..height) to absolute line (0..height-1)
28 #define LINE(row) ((mBIH.height < 0) ? (-mBIH.height - (row)) : ((row) - 1))
29 #define PIXEL_OFFSET(row, col) (LINE(row) * mBIH.width + col)
31 nsBMPDecoder::nsBMPDecoder(RasterImage &aImage, imgIDecoderObserver* aObserver)
32 : Decoder(aImage, aObserver)
34 mColors = nullptr;
35 mRow = nullptr;
36 mImageData = nullptr;
37 mCurPos = mPos = mNumColors = mRowBytes = 0;
38 mOldLine = mCurLine = 1; // Otherwise decoder will never start
39 mState = eRLEStateInitial;
40 mStateData = 0;
41 mLOH = WIN_V3_HEADER_LENGTH;
42 mUseAlphaData = mHaveAlphaData = false;
45 nsBMPDecoder::~nsBMPDecoder()
47 delete[] mColors;
48 if (mRow) {
49 moz_free(mRow);
53 // Sets whether or not the BMP will use alpha data
54 void
55 nsBMPDecoder::SetUseAlphaData(bool useAlphaData)
57 mUseAlphaData = useAlphaData;
60 // Obtains the bits per pixel from the internal BIH header
61 int32_t
62 nsBMPDecoder::GetBitsPerPixel() const
64 return mBIH.bpp;
67 // Obtains the width from the internal BIH header
68 int32_t
69 nsBMPDecoder::GetWidth() const
71 return mBIH.width;
74 // Obtains the abs-value of the height from the internal BIH header
75 int32_t
76 nsBMPDecoder::GetHeight() const
78 return abs(mBIH.height);
81 // Obtains the internal output image buffer
82 uint32_t*
83 nsBMPDecoder::GetImageData()
85 return mImageData;
88 // Obtains the size of the compressed image resource
89 int32_t
90 nsBMPDecoder::GetCompressedImageSize() const
92 // For everything except BI_RGB the header field must be defined
93 if (mBIH.compression != BI_RGB) {
94 return mBIH.image_size;
97 // mBIH.image_size isn't always filled for BI_RGB so calculate it manually
98 // The pixel array size is calculated based on extra 4 byte boundary padding
99 uint32_t rowSize = (mBIH.bpp * mBIH.width + 7) / 8; // + 7 to round up
100 // Pad to DWORD Boundary
101 if (rowSize % 4) {
102 rowSize += (4 - (rowSize % 4));
105 // The height should be the absolute value of what the height is in the BIH.
106 // If positive the bitmap is stored bottom to top, otherwise top to bottom
107 int32_t pixelArraySize = rowSize * GetHeight();
108 return pixelArraySize;
111 // Obtains whether or not a BMP file had alpha data in its 4th byte
112 // for 32BPP bitmaps. Only use after the bitmap has been processed.
113 bool
114 nsBMPDecoder::HasAlphaData() const
116 return mHaveAlphaData;
120 void
121 nsBMPDecoder::FinishInternal()
123 // We shouldn't be called in error cases
124 NS_ABORT_IF_FALSE(!HasError(), "Can't call FinishInternal on error!");
126 // We should never make multiple frames
127 NS_ABORT_IF_FALSE(GetFrameCount() <= 1, "Multiple BMP frames?");
129 // Send notifications if appropriate
130 if (!IsSizeDecode() && (GetFrameCount() == 1)) {
132 // Invalidate
133 nsIntRect r(0, 0, mBIH.width, GetHeight());
134 PostInvalidation(r);
136 PostFrameStop();
137 PostDecodeDone();
141 // ----------------------------------------
142 // Actual Data Processing
143 // ----------------------------------------
145 static void calcBitmask(uint32_t aMask, uint8_t& aBegin, uint8_t& aLength)
147 // find the rightmost 1
148 uint8_t pos;
149 bool started = false;
150 aBegin = aLength = 0;
151 for (pos = 0; pos <= 31; pos++) {
152 if (!started && (aMask & (1 << pos))) {
153 aBegin = pos;
154 started = true;
156 else if (started && !(aMask & (1 << pos))) {
157 aLength = pos - aBegin;
158 break;
163 NS_METHOD nsBMPDecoder::CalcBitShift()
165 uint8_t begin, length;
166 // red
167 calcBitmask(mBitFields.red, begin, length);
168 mBitFields.redRightShift = begin;
169 mBitFields.redLeftShift = 8 - length;
170 // green
171 calcBitmask(mBitFields.green, begin, length);
172 mBitFields.greenRightShift = begin;
173 mBitFields.greenLeftShift = 8 - length;
174 // blue
175 calcBitmask(mBitFields.blue, begin, length);
176 mBitFields.blueRightShift = begin;
177 mBitFields.blueLeftShift = 8 - length;
178 return NS_OK;
181 void
182 nsBMPDecoder::WriteInternal(const char* aBuffer, uint32_t aCount)
184 NS_ABORT_IF_FALSE(!HasError(), "Shouldn't call WriteInternal after error!");
186 // aCount=0 means EOF, mCurLine=0 means we're past end of image
187 if (!aCount || !mCurLine)
188 return;
190 nsresult rv;
191 if (mPos < BFH_INTERNAL_LENGTH) { /* In BITMAPFILEHEADER */
192 uint32_t toCopy = BFH_INTERNAL_LENGTH - mPos;
193 if (toCopy > aCount)
194 toCopy = aCount;
195 memcpy(mRawBuf + mPos, aBuffer, toCopy);
196 mPos += toCopy;
197 aCount -= toCopy;
198 aBuffer += toCopy;
200 if (mPos == BFH_INTERNAL_LENGTH) {
201 ProcessFileHeader();
202 if (mBFH.signature[0] != 'B' || mBFH.signature[1] != 'M') {
203 PostDataError();
204 return;
206 if (mBFH.bihsize == OS2_BIH_LENGTH)
207 mLOH = OS2_HEADER_LENGTH;
209 if (mPos >= BFH_INTERNAL_LENGTH && mPos < mLOH) { /* In BITMAPINFOHEADER */
210 uint32_t toCopy = mLOH - mPos;
211 if (toCopy > aCount)
212 toCopy = aCount;
213 memcpy(mRawBuf + (mPos - BFH_INTERNAL_LENGTH), aBuffer, toCopy);
214 mPos += toCopy;
215 aCount -= toCopy;
216 aBuffer += toCopy;
219 // GetNumFrames is called to ensure that if at this point mPos == mLOH but
220 // we have no data left to process, the next time WriteInternal is called
221 // we won't enter this condition again.
222 if (mPos == mLOH && GetFrameCount() == 0) {
223 ProcessInfoHeader();
224 PR_LOG(gBMPLog, PR_LOG_DEBUG, ("BMP is %lix%lix%lu. compression=%lu\n",
225 mBIH.width, mBIH.height, mBIH.bpp, mBIH.compression));
226 // Verify we support this bit depth
227 if (mBIH.bpp != 1 && mBIH.bpp != 4 && mBIH.bpp != 8 &&
228 mBIH.bpp != 16 && mBIH.bpp != 24 && mBIH.bpp != 32) {
229 PostDataError();
230 return;
233 // BMPs with negative width are invalid
234 // Reject extremely wide images to keep the math sane
235 const int32_t k64KWidth = 0x0000FFFF;
236 if (mBIH.width < 0 || mBIH.width > k64KWidth) {
237 PostDataError();
238 return;
241 uint32_t real_height = GetHeight();
243 // Post our size to the superclass
244 PostSize(mBIH.width, real_height);
245 if (HasError()) {
246 // Setting the size led to an error.
247 return;
250 // We have the size. If we're doing a size decode, we got what
251 // we came for.
252 if (IsSizeDecode())
253 return;
255 // We're doing a real decode.
256 mOldLine = mCurLine = real_height;
258 if (mBIH.bpp <= 8) {
259 mNumColors = 1 << mBIH.bpp;
260 if (mBIH.colors && mBIH.colors < mNumColors)
261 mNumColors = mBIH.colors;
263 // Always allocate 256 even though mNumColors might be smaller
264 mColors = new colorTable[256];
265 memset(mColors, 0, 256 * sizeof(colorTable));
267 else if (mBIH.compression != BI_BITFIELDS && mBIH.bpp == 16) {
268 // Use default 5-5-5 format
269 mBitFields.red = 0x7C00;
270 mBitFields.green = 0x03E0;
271 mBitFields.blue = 0x001F;
272 CalcBitShift();
275 // Make sure we have a valid value for our supported compression modes
276 // before adding the frame
277 if (mBIH.compression != BI_RGB && mBIH.compression != BI_RLE8 &&
278 mBIH.compression != BI_RLE4 && mBIH.compression != BI_BITFIELDS) {
279 PostDataError();
280 return;
283 // If we have RLE4 or RLE8 or BI_ALPHABITFIELDS, then ensure we
284 // have valid BPP values before adding the frame
285 if (mBIH.compression == BI_RLE8 && mBIH.bpp != 8) {
286 PR_LOG(gBMPLog, PR_LOG_DEBUG,
287 ("BMP RLE8 compression only supports 8 bits per pixel\n"));
288 PostDataError();
289 return;
291 if (mBIH.compression == BI_RLE4 && mBIH.bpp != 4 && mBIH.bpp != 1) {
292 PR_LOG(gBMPLog, PR_LOG_DEBUG,
293 ("BMP RLE4 compression only supports 4 bits per pixel\n"));
294 PostDataError();
295 return;
297 if (mBIH.compression == BI_ALPHABITFIELDS &&
298 mBIH.bpp != 16 && mBIH.bpp != 32) {
299 PR_LOG(gBMPLog, PR_LOG_DEBUG,
300 ("BMP ALPHABITFIELDS only supports 16 or 32 bits per pixel\n"));
301 PostDataError();
302 return;
305 uint32_t imageLength;
306 if (mBIH.compression == BI_RLE8 || mBIH.compression == BI_RLE4 ||
307 mBIH.compression == BI_ALPHABITFIELDS) {
308 rv = mImage.EnsureFrame(0, 0, 0, mBIH.width, real_height,
309 gfxASurface::ImageFormatARGB32,
310 (uint8_t**)&mImageData, &imageLength);
311 } else {
312 // mRow is not used for RLE encoded images
313 mRow = (uint8_t*)moz_malloc((mBIH.width * mBIH.bpp) / 8 + 4);
314 // + 4 because the line is padded to a 4 bit boundary, but I don't want
315 // to make exact calculations here, that's unnecessary.
316 // Also, it compensates rounding error.
317 if (!mRow) {
318 PostDecoderError(NS_ERROR_OUT_OF_MEMORY);
319 return;
322 if (mUseAlphaData) {
323 rv = mImage.EnsureFrame(0, 0, 0, mBIH.width, real_height,
324 gfxASurface::ImageFormatARGB32,
325 (uint8_t**)&mImageData, &imageLength);
326 } else {
327 rv = mImage.EnsureFrame(0, 0, 0, mBIH.width, real_height,
328 gfxASurface::ImageFormatRGB24,
329 (uint8_t**)&mImageData, &imageLength);
332 if (NS_FAILED(rv) || !mImageData) {
333 PostDecoderError(NS_ERROR_FAILURE);
334 return;
337 // Prepare for transparency
338 if ((mBIH.compression == BI_RLE8) || (mBIH.compression == BI_RLE4)) {
339 // Clear the image, as the RLE may jump over areas
340 memset(mImageData, 0, imageLength);
343 // Tell the superclass we're starting a frame
344 PostFrameStart();
347 if (mColors && mPos >= mLOH) {
348 // OS/2 Bitmaps have no padding byte
349 uint8_t bytesPerColor = (mBFH.bihsize == OS2_BIH_LENGTH) ? 3 : 4;
350 if (mPos < (mLOH + mNumColors * bytesPerColor)) {
351 // Number of bytes already received
352 uint32_t colorBytes = mPos - mLOH;
353 // Color which is currently received
354 uint8_t colorNum = colorBytes / bytesPerColor;
355 uint8_t at = colorBytes % bytesPerColor;
356 while (aCount && (mPos < (mLOH + mNumColors * bytesPerColor))) {
357 switch (at) {
358 case 0:
359 mColors[colorNum].blue = *aBuffer;
360 break;
361 case 1:
362 mColors[colorNum].green = *aBuffer;
363 break;
364 case 2:
365 mColors[colorNum].red = *aBuffer;
366 // If there is no padding byte, increment the color index
367 // since we're done with the current color.
368 if (bytesPerColor == 3)
369 colorNum++;
370 break;
371 case 3:
372 // This is a padding byte only in Windows BMPs. Increment
373 // the color index since we're done with the current color.
374 colorNum++;
375 break;
377 mPos++; aBuffer++; aCount--;
378 at = (at + 1) % bytesPerColor;
382 else if (aCount && mBIH.compression == BI_BITFIELDS && mPos < (WIN_V3_HEADER_LENGTH + BITFIELD_LENGTH)) {
383 // If compression is used, this is a windows bitmap, hence we can
384 // use WIN_HEADER_LENGTH instead of mLOH
385 uint32_t toCopy = (WIN_V3_HEADER_LENGTH + BITFIELD_LENGTH) - mPos;
386 if (toCopy > aCount)
387 toCopy = aCount;
388 memcpy(mRawBuf + (mPos - WIN_V3_HEADER_LENGTH), aBuffer, toCopy);
389 mPos += toCopy;
390 aBuffer += toCopy;
391 aCount -= toCopy;
393 if (mPos == WIN_V3_HEADER_LENGTH + BITFIELD_LENGTH &&
394 mBIH.compression == BI_BITFIELDS) {
395 mBitFields.red = LITTLE_TO_NATIVE32(*(uint32_t*)mRawBuf);
396 mBitFields.green = LITTLE_TO_NATIVE32(*(uint32_t*)(mRawBuf + 4));
397 mBitFields.blue = LITTLE_TO_NATIVE32(*(uint32_t*)(mRawBuf + 8));
398 CalcBitShift();
400 while (aCount && (mPos < mBFH.dataoffset)) { // Skip whatever is between header and data
401 mPos++; aBuffer++; aCount--;
403 if (aCount && ++mPos >= mBFH.dataoffset) {
404 // Need to increment mPos, else we might get to mPos==mLOH again
405 // From now on, mPos is irrelevant
406 if (!mBIH.compression || mBIH.compression == BI_BITFIELDS) {
407 uint32_t rowSize = (mBIH.bpp * mBIH.width + 7) / 8; // + 7 to round up
408 if (rowSize % 4) {
409 rowSize += (4 - (rowSize % 4)); // Pad to DWORD Boundary
411 uint32_t toCopy;
412 do {
413 toCopy = rowSize - mRowBytes;
414 if (toCopy) {
415 if (toCopy > aCount)
416 toCopy = aCount;
417 memcpy(mRow + mRowBytes, aBuffer, toCopy);
418 aCount -= toCopy;
419 aBuffer += toCopy;
420 mRowBytes += toCopy;
422 if (rowSize == mRowBytes) {
423 // Collected a whole row into mRow, process it
424 uint8_t* p = mRow;
425 uint32_t* d = mImageData + PIXEL_OFFSET(mCurLine, 0);
426 uint32_t lpos = mBIH.width;
427 switch (mBIH.bpp) {
428 case 1:
429 while (lpos > 0) {
430 int8_t bit;
431 uint8_t idx;
432 for (bit = 7; bit >= 0 && lpos > 0; bit--) {
433 idx = (*p >> bit) & 1;
434 SetPixel(d, idx, mColors);
435 --lpos;
437 ++p;
439 break;
440 case 4:
441 while (lpos > 0) {
442 Set4BitPixel(d, *p, lpos, mColors);
443 ++p;
445 break;
446 case 8:
447 while (lpos > 0) {
448 SetPixel(d, *p, mColors);
449 --lpos;
450 ++p;
452 break;
453 case 16:
454 while (lpos > 0) {
455 uint16_t val = LITTLE_TO_NATIVE16(*(uint16_t*)p);
456 SetPixel(d,
457 (val & mBitFields.red) >> mBitFields.redRightShift << mBitFields.redLeftShift,
458 (val & mBitFields.green) >> mBitFields.greenRightShift << mBitFields.greenLeftShift,
459 (val & mBitFields.blue) >> mBitFields.blueRightShift << mBitFields.blueLeftShift);
460 --lpos;
461 p+=2;
463 break;
464 case 24:
465 while (lpos > 0) {
466 SetPixel(d, p[2], p[1], p[0]);
467 p += 2;
468 --lpos;
469 ++p;
471 break;
472 case 32:
473 while (lpos > 0) {
474 if (mUseAlphaData) {
475 if (!mHaveAlphaData && p[3]) {
476 // Non-zero alpha byte detected! Clear previous
477 // pixels that we have already processed.
478 // This works because we know that if we
479 // are reaching here then the alpha data in byte
480 // 4 has been right all along. And we know it
481 // has been set to 0 the whole time, so that
482 // means that everything is transparent so far.
483 uint32_t* start = mImageData + GetWidth() * (mCurLine - 1);
484 uint32_t heightDifference = GetHeight() - mCurLine + 1;
485 uint32_t pixelCount = GetWidth() * heightDifference;
487 memset(start, 0, pixelCount * sizeof(uint32_t));
489 mHaveAlphaData = true;
491 SetPixel(d, p[2], p[1], p[0], mHaveAlphaData ? p[3] : 0xFF);
492 } else {
493 SetPixel(d, p[2], p[1], p[0]);
495 p += 4;
496 --lpos;
498 break;
499 default:
500 NS_NOTREACHED("Unsupported color depth, but earlier check didn't catch it");
502 mCurLine --;
503 if (mCurLine == 0) { // Finished last line
504 break;
506 mRowBytes = 0;
509 } while (aCount > 0);
511 else if ((mBIH.compression == BI_RLE8) || (mBIH.compression == BI_RLE4)) {
512 if (((mBIH.compression == BI_RLE8) && (mBIH.bpp != 8)) ||
513 ((mBIH.compression == BI_RLE4) && (mBIH.bpp != 4) && (mBIH.bpp != 1))) {
514 PR_LOG(gBMPLog, PR_LOG_DEBUG, ("BMP RLE8/RLE4 compression only supports 8/4 bits per pixel\n"));
515 PostDataError();
516 return;
519 while (aCount > 0) {
520 uint8_t byte;
522 switch(mState) {
523 case eRLEStateInitial:
524 mStateData = (uint8_t)*aBuffer++;
525 aCount--;
527 mState = eRLEStateNeedSecondEscapeByte;
528 continue;
530 case eRLEStateNeedSecondEscapeByte:
531 byte = *aBuffer++;
532 aCount--;
533 if (mStateData != RLE_ESCAPE) { // encoded mode
534 // Encoded mode consists of two bytes:
535 // the first byte (mStateData) specifies the
536 // number of consecutive pixels to be drawn
537 // using the color index contained in
538 // the second byte
539 // Work around bitmaps that specify too many pixels
540 mState = eRLEStateInitial;
541 uint32_t pixelsNeeded = NS_MIN<uint32_t>(mBIH.width - mCurPos, mStateData);
542 if (pixelsNeeded) {
543 uint32_t* d = mImageData + PIXEL_OFFSET(mCurLine, mCurPos);
544 mCurPos += pixelsNeeded;
545 if (mBIH.compression == BI_RLE8) {
546 do {
547 SetPixel(d, byte, mColors);
548 pixelsNeeded --;
549 } while (pixelsNeeded);
550 } else {
551 do {
552 Set4BitPixel(d, byte, pixelsNeeded, mColors);
553 } while (pixelsNeeded);
556 continue;
559 switch(byte) {
560 case RLE_ESCAPE_EOL:
561 // End of Line: Go to next row
562 mCurLine --;
563 mCurPos = 0;
564 mState = eRLEStateInitial;
565 break;
567 case RLE_ESCAPE_EOF: // EndOfFile
568 mCurPos = mCurLine = 0;
569 break;
571 case RLE_ESCAPE_DELTA:
572 mState = eRLEStateNeedXDelta;
573 continue;
575 default : // absolute mode
576 // Save the number of pixels to read
577 mStateData = byte;
578 if (mCurPos + mStateData > (uint32_t)mBIH.width) {
579 // We can work around bitmaps that specify one
580 // pixel too many, but only if their width is odd.
581 mStateData -= mBIH.width & 1;
582 if (mCurPos + mStateData > (uint32_t)mBIH.width) {
583 PostDataError();
584 return;
588 // See if we will need to skip a byte
589 // to word align the pixel data
590 // mStateData is a number of pixels
591 // so allow for the RLE compression type
592 // Pixels RLE8=1 RLE4=2
593 // 1 Pad Pad
594 // 2 No Pad
595 // 3 Pad No
596 // 4 No No
597 if (((mStateData - 1) & mBIH.compression) != 0)
598 mState = eRLEStateAbsoluteMode;
599 else
600 mState = eRLEStateAbsoluteModePadded;
601 continue;
603 break;
605 case eRLEStateNeedXDelta:
606 // Handle the XDelta and proceed to get Y Delta
607 byte = *aBuffer++;
608 aCount--;
609 mCurPos += byte;
610 if (mCurPos > mBIH.width)
611 mCurPos = mBIH.width;
613 mState = eRLEStateNeedYDelta;
614 continue;
616 case eRLEStateNeedYDelta:
617 // Get the Y Delta and then "handle" the move
618 byte = *aBuffer++;
619 aCount--;
620 mState = eRLEStateInitial;
621 mCurLine -= NS_MIN<int32_t>(byte, mCurLine);
622 break;
624 case eRLEStateAbsoluteMode: // Absolute Mode
625 case eRLEStateAbsoluteModePadded:
626 if (mStateData) {
627 // In absolute mode, the second byte (mStateData)
628 // represents the number of pixels
629 // that follow, each of which contains
630 // the color index of a single pixel.
631 uint32_t* d = mImageData + PIXEL_OFFSET(mCurLine, mCurPos);
632 uint32_t* oldPos = d;
633 if (mBIH.compression == BI_RLE8) {
634 while (aCount > 0 && mStateData > 0) {
635 byte = *aBuffer++;
636 aCount--;
637 SetPixel(d, byte, mColors);
638 mStateData--;
640 } else {
641 while (aCount > 0 && mStateData > 0) {
642 byte = *aBuffer++;
643 aCount--;
644 Set4BitPixel(d, byte, mStateData, mColors);
647 mCurPos += d - oldPos;
650 if (mStateData == 0) {
651 // In absolute mode, each run must
652 // be aligned on a word boundary
654 if (mState == eRLEStateAbsoluteMode) { // Word Aligned
655 mState = eRLEStateInitial;
656 } else if (aCount > 0) { // Not word Aligned
657 // "next" byte is just a padding byte
658 // so "move" past it and we can continue
659 aBuffer++;
660 aCount--;
661 mState = eRLEStateInitial;
664 // else state is still eRLEStateAbsoluteMode
665 continue;
667 default :
668 NS_ABORT_IF_FALSE(0, "BMP RLE decompression: unknown state!");
669 PostDecoderError(NS_ERROR_UNEXPECTED);
670 return;
672 // Because of the use of the continue statement
673 // we only get here for eol, eof or y delta
674 if (mCurLine == 0) { // Finished last line
675 break;
681 const uint32_t rows = mOldLine - mCurLine;
682 if (rows) {
684 // Invalidate
685 nsIntRect r(0, mBIH.height < 0 ? -mBIH.height - mOldLine : mCurLine,
686 mBIH.width, rows);
687 PostInvalidation(r);
689 mOldLine = mCurLine;
692 return;
695 void nsBMPDecoder::ProcessFileHeader()
697 memset(&mBFH, 0, sizeof(mBFH));
698 memcpy(&mBFH.signature, mRawBuf, sizeof(mBFH.signature));
699 memcpy(&mBFH.filesize, mRawBuf + 2, sizeof(mBFH.filesize));
700 memcpy(&mBFH.reserved, mRawBuf + 6, sizeof(mBFH.reserved));
701 memcpy(&mBFH.dataoffset, mRawBuf + 10, sizeof(mBFH.dataoffset));
702 memcpy(&mBFH.bihsize, mRawBuf + 14, sizeof(mBFH.bihsize));
704 // Now correct the endianness of the header
705 mBFH.filesize = LITTLE_TO_NATIVE32(mBFH.filesize);
706 mBFH.dataoffset = LITTLE_TO_NATIVE32(mBFH.dataoffset);
707 mBFH.bihsize = LITTLE_TO_NATIVE32(mBFH.bihsize);
710 void nsBMPDecoder::ProcessInfoHeader()
712 memset(&mBIH, 0, sizeof(mBIH));
713 if (mBFH.bihsize == 12) { // OS/2 Bitmap
714 memcpy(&mBIH.width, mRawBuf, 2);
715 memcpy(&mBIH.height, mRawBuf + 2, 2);
716 memcpy(&mBIH.planes, mRawBuf + 4, sizeof(mBIH.planes));
717 memcpy(&mBIH.bpp, mRawBuf + 6, sizeof(mBIH.bpp));
719 else {
720 memcpy(&mBIH.width, mRawBuf, sizeof(mBIH.width));
721 memcpy(&mBIH.height, mRawBuf + 4, sizeof(mBIH.height));
722 memcpy(&mBIH.planes, mRawBuf + 8, sizeof(mBIH.planes));
723 memcpy(&mBIH.bpp, mRawBuf + 10, sizeof(mBIH.bpp));
724 memcpy(&mBIH.compression, mRawBuf + 12, sizeof(mBIH.compression));
725 memcpy(&mBIH.image_size, mRawBuf + 16, sizeof(mBIH.image_size));
726 memcpy(&mBIH.xppm, mRawBuf + 20, sizeof(mBIH.xppm));
727 memcpy(&mBIH.yppm, mRawBuf + 24, sizeof(mBIH.yppm));
728 memcpy(&mBIH.colors, mRawBuf + 28, sizeof(mBIH.colors));
729 memcpy(&mBIH.important_colors, mRawBuf + 32, sizeof(mBIH.important_colors));
732 // Convert endianness
733 mBIH.width = LITTLE_TO_NATIVE32(mBIH.width);
734 mBIH.height = LITTLE_TO_NATIVE32(mBIH.height);
735 mBIH.planes = LITTLE_TO_NATIVE16(mBIH.planes);
736 mBIH.bpp = LITTLE_TO_NATIVE16(mBIH.bpp);
738 mBIH.compression = LITTLE_TO_NATIVE32(mBIH.compression);
739 mBIH.image_size = LITTLE_TO_NATIVE32(mBIH.image_size);
740 mBIH.xppm = LITTLE_TO_NATIVE32(mBIH.xppm);
741 mBIH.yppm = LITTLE_TO_NATIVE32(mBIH.yppm);
742 mBIH.colors = LITTLE_TO_NATIVE32(mBIH.colors);
743 mBIH.important_colors = LITTLE_TO_NATIVE32(mBIH.important_colors);
746 } // namespace image
747 } // namespace mozilla