Bug 1215334 (part 1) - Avoid creating a fake header for BMP files in ICO files. r=seth.

The FileHeader and V5InfoHeader structs are shared by the BMP decoder and
encoder. But most of the fields within those structs are actually unused by the
decoder. It makes things clearer if we create a decoder-only struct that
contains the used fields, and then make FileHeader and V5InfoHeader only used
by the encoder. This patch does that.

This patch also renames BMPFileHeaders.h as BMPHeaders.h, which is now a better
name for it.
This commit is contained in:
Nicholas Nethercote 2015-10-15 15:43:25 -07:00
parent 9d19429c30
commit 8ef8ffb5d0
8 changed files with 228 additions and 206 deletions

View File

@ -1,84 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_image_BMPFileHeaders_h
#define mozilla_image_BMPFileHeaders_h
#include <stddef.h>
#include <stdint.h>
namespace mozilla {
namespace image {
namespace bmp {
// This length is stored in the |bihsize| field of bmp::FileHeader.
struct InfoHeaderLength {
enum {
WIN_V2 = 12,
WIN_V3 = 40,
WIN_V4 = 108,
WIN_V5 = 124,
// OS2_V1 is omitted; it's the same as WIN_V2.
OS2_V2_MIN = 16, // Minimum allowed value for OS2v2.
OS2_V2_MAX = 64, // Maximum allowed value for OS2v2.
};
};
struct FileHeader {
char signature[2]; // String "BM".
uint32_t filesize; // File size; unreliable in practice.
int32_t reserved; // Zero.
uint32_t dataoffset; // Offset to raster data.
// The length of the file header as defined in the BMP spec.
static const size_t LENGTH = 14;
};
struct XYZ {
int32_t x, y, z;
};
struct XYZTriple {
XYZ r, g, b;
};
struct V5InfoHeader {
uint32_t bihsize; // Header size
int32_t width; // Uint16 in OS/2 BMPs
int32_t height; // Uint16 in OS/2 BMPs
uint16_t planes; // =1
uint16_t bpp; // Bits per pixel.
// The rest of the header is not available in WIN_V2/OS2_V1 BMP Files
uint32_t compression; // See Compression for valid values
uint32_t image_size; // (compressed) image size. Can be 0 if
// compression==0
uint32_t xppm; // Pixels per meter, horizontal
uint32_t yppm; // Pixels per meter, vertical
uint32_t colors; // Used Colors
uint32_t important_colors; // Number of important colors. 0=all
uint32_t red_mask; // Bits used for red component
uint32_t green_mask; // Bits used for green component
uint32_t blue_mask; // Bits used for blue component
uint32_t alpha_mask; // Bits used for alpha component
uint32_t color_space; // 0x73524742=LCS_sRGB ...
// These members are unused unless color_space == LCS_CALIBRATED_RGB
XYZTriple white_point; // Logical white point
uint32_t gamma_red; // Red gamma component
uint32_t gamma_green; // Green gamma component
uint32_t gamma_blue; // Blue gamma component
uint32_t intent; // Rendering intent
// These members are unused unless color_space == LCS_PROFILE_*
uint32_t profile_offset; // Offset to profile data in bytes
uint32_t profile_size; // Size of profile data in bytes
uint32_t reserved; // =0
static const uint32_t COLOR_SPACE_LCS_SRGB = 0x73524742;
};
} // namespace bmp
} // namespace image
} // namespace mozilla
#endif // mozilla_image_BMPFileHeaders_h

36
image/BMPHeaders.h Normal file
View File

@ -0,0 +1,36 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_image_BMPHeaders_h
#define mozilla_image_BMPHeaders_h
#include <stddef.h>
#include <stdint.h>
namespace mozilla {
namespace image {
namespace bmp {
// The length of the file header as defined in the BMP spec.
static const size_t FILE_HEADER_LENGTH = 14;
// This lengths of the info header for the different BMP versions.
struct InfoHeaderLength {
enum {
WIN_V2 = 12,
WIN_V3 = 40,
WIN_V4 = 108,
WIN_V5 = 124,
// OS2_V1 is omitted; it's the same as WIN_V2.
OS2_V2_MIN = 16, // Minimum allowed value for OS2v2.
OS2_V2_MAX = 64, // Maximum allowed value for OS2v2.
};
};
} // namespace bmp
} // namespace image
} // namespace mozilla
#endif // mozilla_image_BMPHeaders_h

View File

@ -25,28 +25,28 @@
//
// WinBMPv2.
// - First is a 14 byte file header that includes: the magic number ("BM"),
// file size, and offset to the pixel data (|dataoffset|).
// file size, and offset to the pixel data (|mDataOffset|).
// - Next is a 12 byte info header which includes: the info header size
// (bihsize), width, height, number of color planes, and bits-per-pixel
// (|bpp|) which must be 1, 4, 8 or 24.
// - Next is the semi-optional color table, which has length 2^|bpp| and has 3
// bytes per value (BGR). The color table is required if |bpp| is 1, 4, or 8.
// (mBIHSize), width, height, number of color planes, and bits-per-pixel
// (|mBpp|) which must be 1, 4, 8 or 24.
// - Next is the semi-optional color table, which has length 2^|mBpp| and has 3
// bytes per value (BGR). The color table is required if |mBpp| is 1, 4, or 8.
// - Next is an optional gap.
// - Next is the pixel data, which is pointed to by |dataoffset|.
// - Next is the pixel data, which is pointed to by |mDataOffset|.
//
// WinBMPv3. This is the most widely used version.
// - It changed the info header to 40 bytes by taking the WinBMPv2 info
// header, enlargening its width and height fields, and adding more fields
// including: a compression type (|compression|) and number of colors
// (|colors|).
// including: a compression type (|mCompression|) and number of colors
// (|mNumColors|).
// - The semi-optional color table is now 4 bytes per value (BGR0), and its
// length is |colors|, or 2^|bpp| if |colors| is zero.
// - |compression| can be RGB (i.e. no compression), RLE4 (if bpp==4) or RLE8
// (if bpp==8) values.
// length is |mNumColors|, or 2^|mBpp| if |mNumColors| is zero.
// - |mCompression| can be RGB (i.e. no compression), RLE4 (if |mBpp|==4) or
// RLE8 (if |mBpp|==8) values.
//
// WinBMPv3-NT. A variant of WinBMPv3.
// - It did not change the info header layout from WinBMPv3.
// - |bpp| can now be 16 or 32, in which case |compression| can be RGB or the
// - |mBpp| can now be 16 or 32, in which case |mCompression| can be RGB or the
// new BITFIELDS value; in the latter case an additional 12 bytes of color
// bitfields follow the info header.
//
@ -174,7 +174,7 @@ GetBMPLog()
nsBMPDecoder::nsBMPDecoder(RasterImage* aImage)
: Decoder(aImage)
, mLexer(Transition::To(State::FILE_HEADER, FileHeader::LENGTH))
, mLexer(Transition::To(State::FILE_HEADER, FILE_HEADER_LENGTH))
, mIsWithinICO(false)
, mMayHaveTransparency(false)
, mDoesHaveTransparency(false)
@ -186,8 +186,6 @@ nsBMPDecoder::nsBMPDecoder(RasterImage* aImage)
, mCurrentPos(0)
, mAbsoluteModeNumPixels(0)
{
memset(&mBFH, 0, sizeof(mBFH));
memset(&mBIH, 0, sizeof(mBIH));
}
nsBMPDecoder::~nsBMPDecoder()
@ -198,14 +196,14 @@ nsBMPDecoder::~nsBMPDecoder()
int32_t
nsBMPDecoder::GetBitsPerPixel() const
{
return mBIH.bpp;
return mH.mBpp;
}
// Obtains the width from the internal BIH header.
int32_t
nsBMPDecoder::GetWidth() const
{
return mBIH.width;
return mH.mWidth;
}
// Obtains the absolute value of the height from the internal BIH header.
@ -213,7 +211,7 @@ nsBMPDecoder::GetWidth() const
int32_t
nsBMPDecoder::GetHeight() const
{
return abs(mBIH.height);
return abs(mH.mHeight);
}
// Obtains the internal output image buffer.
@ -227,11 +225,11 @@ nsBMPDecoder::GetImageData()
int32_t
nsBMPDecoder::GetCompressedImageSize() const
{
// In the RGB case image_size might not be set, so compute it manually.
// In the RGB case mImageSize might not be set, so compute it manually.
MOZ_ASSERT(mPixelRowSize != 0);
return mBIH.compression == Compression::RGB
return mH.mCompression == Compression::RGB
? mPixelRowSize * GetHeight()
: mBIH.image_size;
: mH.mImageSize;
}
void
@ -247,7 +245,7 @@ nsBMPDecoder::FinishInternal()
if (!IsMetadataDecode() && HasSize()) {
// Invalidate.
nsIntRect r(0, 0, mBIH.width, GetHeight());
nsIntRect r(0, 0, mH.mWidth, GetHeight());
PostInvalidation(r);
if (mDoesHaveTransparency) {
@ -400,11 +398,11 @@ nsBMPDecoder::RowBuffer()
return reinterpret_cast<uint32_t*>(mDownscaler->RowBuffer()) + mCurrentPos;
}
// Convert from row (1..height) to absolute line (0..height-1).
int32_t line = (mBIH.height < 0)
? -mBIH.height - mCurrentRow
// Convert from row (1..mHeight) to absolute line (0..mHeight-1).
int32_t line = (mH.mHeight < 0)
? -mH.mHeight - mCurrentRow
: mCurrentRow - 1;
int32_t offset = line * mBIH.width + mCurrentPos;
int32_t offset = line * mH.mWidth + mCurrentPos;
return reinterpret_cast<uint32_t*>(mImageData) + offset;
}
@ -420,7 +418,7 @@ nsBMPDecoder::FinishRow()
Some(invalidRect.mTargetSizeRect));
}
} else {
PostInvalidation(IntRect(0, mCurrentRow, mBIH.width, 1));
PostInvalidation(IntRect(0, mCurrentRow, mH.mWidth, 1));
}
mCurrentRow--;
}
@ -466,7 +464,7 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, uint32_t aCount)
return;
}
// The length of the bihsize field in the info header.
// The length of the mBIHSize field in the info header.
static const uint32_t BIHSIZE_FIELD_LENGTH = 4;
LexerTransition<nsBMPDecoder::State>
@ -474,51 +472,44 @@ nsBMPDecoder::ReadFileHeader(const char* aData, size_t aLength)
{
mPreGapLength += aLength;
mBFH.signature[0] = aData[0];
mBFH.signature[1] = aData[1];
bool signatureOk = mBFH.signature[0] == 'B' && mBFH.signature[1] == 'M';
bool signatureOk = aData[0] == 'B' && aData[1] == 'M';
if (!signatureOk) {
PostDataError();
return Transition::Terminate(State::FAILURE);
}
// Nb: this field is unreliable. In Windows BMPs it's the file size, but in
// OS/2 BMPs it's sometimes the size of the file and info headers. It doesn't
// matter because we don't consult it.
mBFH.filesize = LittleEndian::readUint32(aData + 2);
// We ignore the filesize (aData + 2) and reserved (aData + 6) fields.
mBFH.reserved = 0;
mBFH.dataoffset = LittleEndian::readUint32(aData + 10);
mH.mDataOffset = LittleEndian::readUint32(aData + 10);
return Transition::To(State::INFO_HEADER_SIZE, BIHSIZE_FIELD_LENGTH);
}
// We read the info header in two steps: (a) read the bihsize field to
// We read the info header in two steps: (a) read the mBIHSize field to
// determine how long the header is; (b) read the rest of the header.
LexerTransition<nsBMPDecoder::State>
nsBMPDecoder::ReadInfoHeaderSize(const char* aData, size_t aLength)
{
mPreGapLength += aLength;
mBIH.bihsize = LittleEndian::readUint32(aData);
mH.mBIHSize = LittleEndian::readUint32(aData);
bool bihsizeOk = mBIH.bihsize == InfoHeaderLength::WIN_V2 ||
mBIH.bihsize == InfoHeaderLength::WIN_V3 ||
mBIH.bihsize == InfoHeaderLength::WIN_V4 ||
mBIH.bihsize == InfoHeaderLength::WIN_V5 ||
(mBIH.bihsize >= InfoHeaderLength::OS2_V2_MIN &&
mBIH.bihsize <= InfoHeaderLength::OS2_V2_MAX);
if (!bihsizeOk) {
bool bihSizeOk = mH.mBIHSize == InfoHeaderLength::WIN_V2 ||
mH.mBIHSize == InfoHeaderLength::WIN_V3 ||
mH.mBIHSize == InfoHeaderLength::WIN_V4 ||
mH.mBIHSize == InfoHeaderLength::WIN_V5 ||
(mH.mBIHSize >= InfoHeaderLength::OS2_V2_MIN &&
mH.mBIHSize <= InfoHeaderLength::OS2_V2_MAX);
if (!bihSizeOk) {
PostDataError();
return Transition::Terminate(State::FAILURE);
}
// ICO BMPs must have a WinVMPv3 header. nsICODecoder should have already
// terminated decoding if this isn't the case.
MOZ_ASSERT_IF(mIsWithinICO, mBIH.bihsize == InfoHeaderLength::WIN_V3);
MOZ_ASSERT_IF(mIsWithinICO, mH.mBIHSize == InfoHeaderLength::WIN_V3);
return Transition::To(State::INFO_HEADER_REST,
mBIH.bihsize - BIHSIZE_FIELD_LENGTH);
mH.mBIHSize - BIHSIZE_FIELD_LENGTH);
}
LexerTransition<nsBMPDecoder::State>
@ -526,28 +517,26 @@ nsBMPDecoder::ReadInfoHeaderRest(const char* aData, size_t aLength)
{
mPreGapLength += aLength;
// |width| and |height| may be signed (Windows) or unsigned (OS/2). We just
// |mWidth| and |mHeight| may be signed (Windows) or unsigned (OS/2). We just
// read as unsigned because in practice that's good enough.
if (mBIH.bihsize == InfoHeaderLength::WIN_V2) {
mBIH.width = LittleEndian::readUint16(aData + 0);
mBIH.height = LittleEndian::readUint16(aData + 2);
mBIH.planes = LittleEndian::readUint16(aData + 4);
mBIH.bpp = LittleEndian::readUint16(aData + 6);
if (mH.mBIHSize == InfoHeaderLength::WIN_V2) {
mH.mWidth = LittleEndian::readUint16(aData + 0);
mH.mHeight = LittleEndian::readUint16(aData + 2);
// We ignore the planes (aData + 4) field; it should always be 1.
mH.mBpp = LittleEndian::readUint16(aData + 6);
} else {
mBIH.width = LittleEndian::readUint32(aData + 0);
mBIH.height = LittleEndian::readUint32(aData + 4);
mBIH.planes = LittleEndian::readUint16(aData + 8);
mBIH.bpp = LittleEndian::readUint16(aData + 10);
mH.mWidth = LittleEndian::readUint32(aData + 0);
mH.mHeight = LittleEndian::readUint32(aData + 4);
// We ignore the planes (aData + 4) field; it should always be 1.
mH.mBpp = LittleEndian::readUint16(aData + 10);
// For OS2-BMPv2 the info header may be as little as 16 bytes, so be
// careful for these fields.
mBIH.compression = aLength >= 16 ? LittleEndian::readUint32(aData + 12) : 0;
mBIH.image_size = aLength >= 20 ? LittleEndian::readUint32(aData + 16) : 0;
mBIH.xppm = aLength >= 24 ? LittleEndian::readUint32(aData + 20) : 0;
mBIH.yppm = aLength >= 28 ? LittleEndian::readUint32(aData + 24) : 0;
mBIH.colors = aLength >= 32 ? LittleEndian::readUint32(aData + 28) : 0;
mBIH.important_colors
= aLength >= 36 ? LittleEndian::readUint32(aData + 32) : 0;
mH.mCompression = aLength >= 16 ? LittleEndian::readUint32(aData + 12) : 0;
mH.mImageSize = aLength >= 20 ? LittleEndian::readUint32(aData + 16) : 0;
// We ignore the xppm (aData + 20) and yppm (aData + 24) fields.
mH.mNumColors = aLength >= 32 ? LittleEndian::readUint32(aData + 28) : 0;
// We ignore the important_colors (aData + 36) field.
// For WinBMPv4, WinBMPv5 and (possibly) OS2-BMPv2 there are additional
// fields in the info header which we ignore, with the possible exception
@ -557,29 +546,29 @@ nsBMPDecoder::ReadInfoHeaderRest(const char* aData, size_t aLength)
// Run with NSPR_LOG_MODULES=BMPDecoder:4 set to see this output.
MOZ_LOG(GetBMPLog(), LogLevel::Debug,
("BMP: bihsize=%u, %d x %d, bpp=%u, compression=%u, colors=%u\n",
mBIH.bihsize, mBIH.width, mBIH.height, uint32_t(mBIH.bpp),
mBIH.compression, mBIH.colors));
mH.mBIHSize, mH.mWidth, mH.mHeight, uint32_t(mH.mBpp),
mH.mCompression, mH.mNumColors));
// BMPs with negative width are invalid. Also, reject extremely wide images
// to keep the math sane. And reject INT_MIN as a height because you can't
// get its absolute value (because -INT_MIN is one more than INT_MAX).
const int32_t k64KWidth = 0x0000FFFF;
bool sizeOk = 0 <= mBIH.width && mBIH.width <= k64KWidth &&
mBIH.height != INT_MIN;
bool sizeOk = 0 <= mH.mWidth && mH.mWidth <= k64KWidth &&
mH.mHeight != INT_MIN;
if (!sizeOk) {
PostDataError();
return Transition::Terminate(State::FAILURE);
}
// Check bpp and compression.
// Check mBpp and mCompression.
bool bppCompressionOk =
(mBIH.compression == Compression::RGB &&
(mBIH.bpp == 1 || mBIH.bpp == 4 || mBIH.bpp == 8 ||
mBIH.bpp == 16 || mBIH.bpp == 24 || mBIH.bpp == 32)) ||
(mBIH.compression == Compression::RLE8 && mBIH.bpp == 8) ||
(mBIH.compression == Compression::RLE4 && mBIH.bpp == 4) ||
(mBIH.compression == Compression::BITFIELDS &&
(mBIH.bpp == 16 || mBIH.bpp == 32));
(mH.mCompression == Compression::RGB &&
(mH.mBpp == 1 || mH.mBpp == 4 || mH.mBpp == 8 ||
mH.mBpp == 16 || mH.mBpp == 24 || mH.mBpp == 32)) ||
(mH.mCompression == Compression::RLE8 && mH.mBpp == 8) ||
(mH.mCompression == Compression::RLE4 && mH.mBpp == 4) ||
(mH.mCompression == Compression::BITFIELDS &&
(mH.mBpp == 16 || mH.mBpp == 32));
if (!bppCompressionOk) {
PostDataError();
return Transition::Terminate(State::FAILURE);
@ -587,22 +576,22 @@ nsBMPDecoder::ReadInfoHeaderRest(const char* aData, size_t aLength)
// Post our size to the superclass.
uint32_t realHeight = GetHeight();
PostSize(mBIH.width, realHeight);
PostSize(mH.mWidth, realHeight);
mCurrentRow = realHeight;
// Round it up to the nearest byte count, then pad to 4-byte boundary.
// Compute this even for a metadate decode because GetCompressedImageSize()
// relies on it.
mPixelRowSize = (mBIH.bpp * mBIH.width + 7) / 8;
mPixelRowSize = (mH.mBpp * mH.mWidth + 7) / 8;
uint32_t surplus = mPixelRowSize % 4;
if (surplus != 0) {
mPixelRowSize += 4 - surplus;
}
size_t bitFieldsLengthStillToRead = 0;
if (mBIH.compression == Compression::BITFIELDS) {
if (mH.mCompression == Compression::BITFIELDS) {
// Need to read bitfields.
if (mBIH.bihsize >= InfoHeaderLength::WIN_V4) {
if (mH.mBIHSize >= InfoHeaderLength::WIN_V4) {
// Bitfields are present in the info header, so we can read them
// immediately.
mBitFields.ReadFromHeader(aData + 36, /* aReadAlpha = */ true);
@ -611,10 +600,10 @@ nsBMPDecoder::ReadInfoHeaderRest(const char* aData, size_t aLength)
// ReadBitfields().
bitFieldsLengthStillToRead = BitFields::LENGTH;
}
} else if (mBIH.bpp == 16) {
} else if (mH.mBpp == 16) {
// No bitfields specified; use the default 5-5-5 values.
mBitFields.SetR5G5B5();
} else if (mBIH.bpp == 32) {
} else if (mH.mBpp == 32) {
// No bitfields specified; use the default 8-8-8 values.
mBitFields.SetR8G8B8();
}
@ -647,10 +636,10 @@ nsBMPDecoder::ReadBitfields(const char* aData, size_t aLength)
// Note that RLE-encoded BMPs might be transparent because the 'delta' mode
// can skip pixels and cause implicit transparency.
mMayHaveTransparency =
(mBIH.compression == Compression::RGB && mIsWithinICO && mBIH.bpp == 32) ||
mBIH.compression == Compression::RLE8 ||
mBIH.compression == Compression::RLE4 ||
(mBIH.compression == Compression::BITFIELDS &&
(mH.mCompression == Compression::RGB && mIsWithinICO && mH.mBpp == 32) ||
mH.mCompression == Compression::RLE8 ||
mH.mCompression == Compression::RLE4 ||
(mH.mCompression == Compression::BITFIELDS &&
mBitFields.mAlpha.IsPresent());
if (mMayHaveTransparency) {
PostHasTransparency();
@ -663,10 +652,10 @@ nsBMPDecoder::ReadBitfields(const char* aData, size_t aLength)
}
// Set up the color table, if present; it'll be filled in by ReadColorTable().
if (mBIH.bpp <= 8) {
mNumColors = 1 << mBIH.bpp;
if (0 < mBIH.colors && mBIH.colors < mNumColors) {
mNumColors = mBIH.colors;
if (mH.mBpp <= 8) {
mNumColors = 1 << mH.mBpp;
if (0 < mH.mNumColors && mH.mNumColors < mNumColors) {
mNumColors = mH.mNumColors;
}
// Always allocate and zero 256 entries, even though mNumColors might be
@ -675,7 +664,7 @@ nsBMPDecoder::ReadBitfields(const char* aData, size_t aLength)
memset(mColors.get(), 0, 256 * sizeof(ColorTableEntry));
// OS/2 Bitmaps have no padding byte.
mBytesPerColor = (mBIH.bihsize == InfoHeaderLength::WIN_V2) ? 3 : 4;
mBytesPerColor = (mH.mBIHSize == InfoHeaderLength::WIN_V2) ? 3 : 4;
}
MOZ_ASSERT(!mImageData, "Already have a buffer allocated?");
@ -718,25 +707,25 @@ nsBMPDecoder::ReadColorTable(const char* aData, size_t aLength)
}
// We know how many bytes we've read so far (mPreGapLength) and we know the
// offset of the pixel data (mBFH.dataoffset), so we can determine the length
// offset of the pixel data (mH.mDataOffset), so we can determine the length
// of the gap (possibly zero) between the color table and the pixel data.
//
// If the gap is negative the file must be malformed (e.g. mBFH.dataoffset
// If the gap is negative the file must be malformed (e.g. mH.mDataOffset
// points into the middle of the color palette instead of past the end) and
// we give up.
if (mPreGapLength > mBFH.dataoffset) {
if (mPreGapLength > mH.mDataOffset) {
PostDataError();
return Transition::Terminate(State::FAILURE);
}
uint32_t gapLength = mBFH.dataoffset - mPreGapLength;
uint32_t gapLength = mH.mDataOffset - mPreGapLength;
return Transition::To(State::GAP, gapLength);
}
LexerTransition<nsBMPDecoder::State>
nsBMPDecoder::SkipGap()
{
bool hasRLE = mBIH.compression == Compression::RLE8 ||
mBIH.compression == Compression::RLE4;
bool hasRLE = mH.mCompression == Compression::RLE8 ||
mH.mCompression == Compression::RLE4;
return hasRLE
? Transition::To(State::RLE_SEGMENT, RLE::SEGMENT_LENGTH)
: Transition::To(State::PIXEL_ROW, mPixelRowSize);
@ -749,8 +738,8 @@ nsBMPDecoder::ReadPixelRow(const char* aData)
const uint8_t* src = reinterpret_cast<const uint8_t*>(aData);
uint32_t* dst = RowBuffer();
uint32_t lpos = mBIH.width;
switch (mBIH.bpp) {
uint32_t lpos = mH.mWidth;
switch (mH.mBpp) {
case 1:
while (lpos > 0) {
int8_t bit;
@ -817,8 +806,8 @@ nsBMPDecoder::ReadPixelRow(const char* aData)
break;
case 32:
if (mBIH.compression == Compression::RGB && mIsWithinICO &&
mBIH.bpp == 32) {
if (mH.mCompression == Compression::RGB && mIsWithinICO &&
mH.mBpp == 32) {
// This is a special case only used for 32bpp WinBMPv3-ICO files, which
// could be in either 0RGB or ARGB format.
while (lpos > 0) {
@ -894,11 +883,11 @@ nsBMPDecoder::ReadRLESegment(const char* aData)
//
// Work around bitmaps that specify too many pixels.
uint32_t pixelsNeeded =
std::min<uint32_t>(mBIH.width - mCurrentPos, byte1);
std::min<uint32_t>(mH.mWidth - mCurrentPos, byte1);
if (pixelsNeeded) {
uint32_t* dst = RowBuffer();
mCurrentPos += pixelsNeeded;
if (mBIH.compression == Compression::RLE8) {
if (mH.mCompression == Compression::RLE8) {
do {
SetPixel(dst, byte2, mColors);
pixelsNeeded --;
@ -934,7 +923,7 @@ nsBMPDecoder::ReadRLESegment(const char* aData)
MOZ_ASSERT(mAbsoluteModeNumPixels == 0);
mAbsoluteModeNumPixels = byte2;
uint32_t length = byte2;
if (mBIH.compression == Compression::RLE4) {
if (mH.mCompression == Compression::RLE4) {
length = (length + 1) / 2; // halve, rounding up
}
if (length & 1) {
@ -959,8 +948,8 @@ nsBMPDecoder::ReadRLEDelta(const char* aData)
// Handle the XDelta.
mCurrentPos += uint8_t(aData[0]);
if (mCurrentPos > mBIH.width) {
mCurrentPos = mBIH.width;
if (mCurrentPos > mH.mWidth) {
mCurrentPos = mH.mWidth;
}
// Handle the Y Delta.
@ -989,7 +978,7 @@ nsBMPDecoder::ReadRLEAbsolute(const char* aData, size_t aLength)
uint32_t n = mAbsoluteModeNumPixels;
mAbsoluteModeNumPixels = 0;
if (mCurrentPos + n > uint32_t(mBIH.width)) {
if (mCurrentPos + n > uint32_t(mH.mWidth)) {
// Bad data. Stop decoding; at least part of the image may have been
// decoded.
return Transition::Terminate(State::SUCCESS);
@ -1000,7 +989,7 @@ nsBMPDecoder::ReadRLEAbsolute(const char* aData, size_t aLength)
uint32_t* dst = RowBuffer();
uint32_t iSrc = 0;
uint32_t* oldPos = dst;
if (mBIH.compression == Compression::RLE8) {
if (mH.mCompression == Compression::RLE8) {
while (n > 0) {
SetPixel(dst, aData[iSrc], mColors);
n--;

View File

@ -7,7 +7,7 @@
#ifndef mozilla_image_decoders_nsBMPDecoder_h
#define mozilla_image_decoders_nsBMPDecoder_h
#include "BMPFileHeaders.h"
#include "BMPHeaders.h"
#include "Decoder.h"
#include "gfxColor.h"
#include "StreamingLexer.h"
@ -18,6 +18,32 @@ namespace image {
namespace bmp {
/// This struct contains the fields from the file header and info header that
/// we use during decoding. (Excluding bitfields fields, which are kept in
/// BitFields.)
struct Header {
uint32_t mDataOffset; // Offset to raster data.
uint32_t mBIHSize; // Header size.
int32_t mWidth; // Image width.
int32_t mHeight; // Image height.
uint16_t mBpp; // Bits per pixel.
uint32_t mCompression; // See struct Compression for valid values.
uint32_t mImageSize; // (compressed) image size. Can be 0 if
// mCompression==0.
uint32_t mNumColors; // Used colors.
Header()
: mDataOffset(0)
, mBIHSize(0)
, mWidth(0)
, mHeight(0)
, mBpp(0)
, mCompression(0)
, mImageSize(0)
, mNumColors(0)
{}
};
/// An entry in the color table.
struct ColorTableEntry {
uint8_t mRed;
@ -173,8 +199,7 @@ private:
StreamingLexer<State> mLexer;
bmp::FileHeader mBFH;
bmp::V5InfoHeader mBIH;
bmp::Header mH;
// If the BMP is within an ICO file our treatment of it differs slightly.
bool mIsWithinICO;

View File

@ -124,7 +124,7 @@ nsICODecoder::FillBitmapFileHeaderBuffer(int8_t* bfh)
bfh[1] = 'M';
int32_t dataOffset = 0;
int32_t fileSize = 0;
dataOffset = bmp::FileHeader::LENGTH + BITMAPINFOSIZE;
dataOffset = bmp::FILE_HEADER_LENGTH + BITMAPINFOSIZE;
// The color table is present only if BPP is <= 8
if (mDirEntry.mBitCount <= 8) {

View File

@ -487,9 +487,9 @@ nsBMPEncoder::InitFileHeader(Version aVersion, uint32_t aBPP, uint32_t aWidth,
mBMPFileHeader.signature[1] = 'M';
if (aVersion == VERSION_3) {
mBMPFileHeader.dataoffset = FileHeader::LENGTH + InfoHeaderLength::WIN_V3;
mBMPFileHeader.dataoffset = FILE_HEADER_LENGTH + InfoHeaderLength::WIN_V3;
} else { // aVersion == 5
mBMPFileHeader.dataoffset = FileHeader::LENGTH + InfoHeaderLength::WIN_V5;
mBMPFileHeader.dataoffset = FILE_HEADER_LENGTH + InfoHeaderLength::WIN_V5;
}
// The color table is present only if BPP is <= 8

View File

@ -11,7 +11,7 @@
#include "mozilla/UniquePtr.h"
#include "imgIEncoder.h"
#include "BMPFileHeaders.h"
#include "BMPHeaders.h"
#include "nsCOMPtr.h"
@ -23,6 +23,62 @@
{0xbd, 0x16, 0xb0, 0x81, 0xa3, 0Xba, 0x8c, 0x0b} \
}
namespace mozilla {
namespace image {
namespace bmp {
struct FileHeader {
char signature[2]; // String "BM".
uint32_t filesize; // File size.
int32_t reserved; // Zero.
uint32_t dataoffset; // Offset to raster data.
};
struct XYZ {
int32_t x, y, z;
};
struct XYZTriple {
XYZ r, g, b;
};
struct V5InfoHeader {
uint32_t bihsize; // Header size
int32_t width; // Uint16 in OS/2 BMPs
int32_t height; // Uint16 in OS/2 BMPs
uint16_t planes; // =1
uint16_t bpp; // Bits per pixel.
uint32_t compression; // See Compression for valid values
uint32_t image_size; // (compressed) image size. Can be 0 if
// compression==0
uint32_t xppm; // Pixels per meter, horizontal
uint32_t yppm; // Pixels per meter, vertical
uint32_t colors; // Used Colors
uint32_t important_colors; // Number of important colors. 0=all
// The rest of the header is not available in WIN_V3 BMP Files
uint32_t red_mask; // Bits used for red component
uint32_t green_mask; // Bits used for green component
uint32_t blue_mask; // Bits used for blue component
uint32_t alpha_mask; // Bits used for alpha component
uint32_t color_space; // 0x73524742=LCS_sRGB ...
// These members are unused unless color_space == LCS_CALIBRATED_RGB
XYZTriple white_point; // Logical white point
uint32_t gamma_red; // Red gamma component
uint32_t gamma_green; // Green gamma component
uint32_t gamma_blue; // Blue gamma component
uint32_t intent; // Rendering intent
// These members are unused unless color_space == LCS_PROFILE_*
uint32_t profile_offset; // Offset to profile data in bytes
uint32_t profile_size; // Size of profile data in bytes
uint32_t reserved; // =0
static const uint32_t COLOR_SPACE_LCS_SRGB = 0x73524742;
};
} // namespace bmp
} // namespace image
} // namespace mozilla
// Provides BMP encoding functionality. Use InitFromData() to do the
// encoding. See that function definition for encoding options.

View File

@ -162,10 +162,10 @@ nsICOEncoder::AddImageFrame(const uint8_t* aData,
// Icon files that wrap a BMP file must not include the BITMAPFILEHEADER
// section at the beginning of the encoded BMP data, so we must skip over
// bmp::FileHeader::LENGTH bytes when adding the BMP content to the icon
// bmp::FILE_HEADER_LENGTH bytes when adding the BMP content to the icon
// file.
mICODirEntry.mBytesInRes =
BMPImageBufferSize - bmp::FileHeader::LENGTH + andMaskSize;
BMPImageBufferSize - bmp::FILE_HEADER_LENGTH + andMaskSize;
// Encode the icon headers
EncodeFileHeader();
@ -174,14 +174,14 @@ nsICOEncoder::AddImageFrame(const uint8_t* aData,
char* imageBuffer;
rv = mContainedEncoder->GetImageBuffer(&imageBuffer);
NS_ENSURE_SUCCESS(rv, rv);
memcpy(mImageBufferCurr, imageBuffer + bmp::FileHeader::LENGTH,
BMPImageBufferSize - bmp::FileHeader::LENGTH);
memcpy(mImageBufferCurr, imageBuffer + bmp::FILE_HEADER_LENGTH,
BMPImageBufferSize - bmp::FILE_HEADER_LENGTH);
// We need to fix the BMP height to be *2 for the AND mask
uint32_t fixedHeight = GetRealHeight() * 2;
NativeEndian::swapToLittleEndianInPlace(&fixedHeight, 1);
// The height is stored at an offset of 8 from the DIB header
memcpy(mImageBufferCurr + 8, &fixedHeight, sizeof(fixedHeight));
mImageBufferCurr += BMPImageBufferSize - bmp::FileHeader::LENGTH;
mImageBufferCurr += BMPImageBufferSize - bmp::FILE_HEADER_LENGTH;
// Calculate rowsize in DWORD's
uint32_t rowSize = ((GetRealWidth() + 31) / 32) * 4; // + 31 to round up