2015-10-14 02:08:06 +03:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
2012-05-21 15:12:37 +04:00
|
|
|
/* 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/. */
|
2001-11-03 10:10:51 +03:00
|
|
|
|
2015-04-06 02:22:00 +03:00
|
|
|
#ifndef mozilla_image_decoders_nsBMPDecoder_h
|
|
|
|
#define mozilla_image_decoders_nsBMPDecoder_h
|
2001-11-03 10:10:51 +03:00
|
|
|
|
2015-10-16 01:43:25 +03:00
|
|
|
#include "BMPHeaders.h"
|
2014-11-14 20:59:00 +03:00
|
|
|
#include "Decoder.h"
|
|
|
|
#include "gfxColor.h"
|
Bug 1204394 (part 1) - Using StreamingLexer in the BMP decoder. r=seth.
This patch is a major overhaul of nsBMPDecoder.
The patch improves the code in the following ways.
- It converts nsBMPDecoder to use StreamingLexer, which makes it much easier to
read.
- It adds a detailed comment about the BMP format at the top of
nsBMPDecoder.cpp.
- It fixes lots of inconsistent indenting.
- It moves |bihsize| from |mBFH| to |mBIH| to match the file format and common
sense. The avoids the need for the confusing LENGTH/INTERNAL_LENGTH
distinction.
- It renames most of the types in BMPFileHeader.h, so they have better names,
in StudlyCaps form, and within the new |bmp| namespace.
- It removes the BMP_HEADER_LENGTH struct and inlines its values directly into
the two places they were used.
- It removes the MOZ_LOG logging done on some of the failure cases. (Most
failure cases lacked logging so why bother with some?)
- It removes over 200 lines of code, despite the addition of the big format
comment.
The patch changes the way BMPs are decoded as follows.
- It adds stricter testing of the InfoHeader length, rejecting files with bad
values.
- It moves all header sanity checking that can lead to file rejection into the
metadata decode phase. (Previously, bpp/compression consistency checking did
not occur during a metadata decode.)
- It removes BMPINFOHEADER::ALPHABITFIELDS, which was (a) a weird WinCE-only
thing, and (b) we didn't actually allow it, and (c) we used the value 4
instead of 6(!).
- It rejects the previously-accepted compression==RLE4 && bpp=1 combination
because it doesn't make sense.
- It removes a fudge in RLE absolute mode handling that permitted one pixel too
many in a row but only if the row's width was odd(!)
- It now rejects a file with a negative gap between the color table and the
pixel data.
The patch leaves the following problems unaddressed.
- If bpp==32 we totally ignore compression==BITFIELDS and treat it like
compression=RGB.
- Transparency as specified in WinBMPv{4,5} isn't handled at all.
These will be fixed in follow-ups.
All these changes affect (for the better) the results of the following tests
that will be added in part 2:
- g/pal8v4.bmp
- g/pal8v5.bmp
- q/pal8os2sp.bmp
- q/pal8os2v2.bmp
- q/pal8os2v2-16.bmp
- b/badheadersize.bmp
- b/badpalettesize.bmp
- b/badrle.bmp
--HG--
extra : rebase_source : 8ddc2f5fccce6998348097ff9f0a1072d273cdf4
2015-10-09 08:47:56 +03:00
|
|
|
#include "StreamingLexer.h"
|
2015-10-27 17:47:51 +03:00
|
|
|
#include "mozilla/UniquePtr.h"
|
2010-08-23 06:30:46 +04:00
|
|
|
|
|
|
|
namespace mozilla {
|
2012-01-06 20:02:27 +04:00
|
|
|
namespace image {
|
2010-08-12 23:58:25 +04:00
|
|
|
|
2015-10-14 02:43:18 +03:00
|
|
|
namespace bmp {
|
|
|
|
|
2015-10-16 01:43:25 +03:00
|
|
|
/// 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)
|
|
|
|
{}
|
|
|
|
};
|
|
|
|
|
2015-10-14 02:43:18 +03:00
|
|
|
/// An entry in the color table.
|
|
|
|
struct ColorTableEntry {
|
|
|
|
uint8_t mRed;
|
|
|
|
uint8_t mGreen;
|
|
|
|
uint8_t mBlue;
|
|
|
|
};
|
|
|
|
|
2015-10-14 06:01:02 +03:00
|
|
|
/// All the color-related bitfields for 16bpp and 32bpp images. We use this
|
|
|
|
/// even for older format BMPs that don't have explicit bitfields.
|
|
|
|
class BitFields {
|
|
|
|
class Value {
|
|
|
|
friend class BitFields;
|
|
|
|
|
|
|
|
uint32_t mMask; // The mask for the value.
|
|
|
|
uint8_t mRightShift; // The amount to right-shift after masking.
|
|
|
|
uint8_t mBitWidth; // The width (in bits) of the value.
|
|
|
|
|
|
|
|
/// Sets the mask (and thus the right-shift and bit-width as well).
|
|
|
|
void Set(uint32_t aMask);
|
|
|
|
|
|
|
|
public:
|
2015-10-14 07:20:10 +03:00
|
|
|
Value()
|
|
|
|
{
|
|
|
|
mMask = 0;
|
|
|
|
mRightShift = 0;
|
|
|
|
mBitWidth = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns true if this channel is used. Only used for alpha.
|
|
|
|
bool IsPresent() const { return mMask != 0x0; }
|
|
|
|
|
2015-10-14 06:01:02 +03:00
|
|
|
/// Extracts the single color value from the multi-color value.
|
|
|
|
uint8_t Get(uint32_t aVal) const;
|
|
|
|
|
2015-10-14 07:20:10 +03:00
|
|
|
/// Like Get(), but specially for alpha.
|
|
|
|
uint8_t GetAlpha(uint32_t aVal, bool& aHasAlphaOut) const;
|
|
|
|
|
|
|
|
/// Specialized versions of Get() for when the bit-width is 5 or 8.
|
|
|
|
/// (They will assert if called and the bit-width is not 5 or 8.)
|
2015-10-14 06:01:02 +03:00
|
|
|
uint8_t Get5(uint32_t aVal) const;
|
2015-10-14 07:20:10 +03:00
|
|
|
uint8_t Get8(uint32_t aVal) const;
|
2015-10-14 06:01:02 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
public:
|
|
|
|
/// The individual color channels.
|
|
|
|
Value mRed;
|
|
|
|
Value mGreen;
|
|
|
|
Value mBlue;
|
2015-10-14 07:20:10 +03:00
|
|
|
Value mAlpha;
|
2015-10-14 06:01:02 +03:00
|
|
|
|
|
|
|
/// Set bitfields to the standard 5-5-5 16bpp values.
|
|
|
|
void SetR5G5B5();
|
|
|
|
|
2015-10-14 07:20:10 +03:00
|
|
|
/// Set bitfields to the standard 8-8-8 32bpp values.
|
|
|
|
void SetR8G8B8();
|
|
|
|
|
2015-10-14 06:01:02 +03:00
|
|
|
/// Test if bitfields have the standard 5-5-5 16bpp values.
|
|
|
|
bool IsR5G5B5() const;
|
|
|
|
|
2015-10-14 07:20:10 +03:00
|
|
|
/// Test if bitfields have the standard 8-8-8 32bpp values.
|
|
|
|
bool IsR8G8B8() const;
|
|
|
|
|
|
|
|
/// Read the bitfields from a header. The reading of the alpha mask is
|
|
|
|
/// optional.
|
|
|
|
void ReadFromHeader(const char* aData, bool aReadAlpha);
|
2015-10-14 06:01:02 +03:00
|
|
|
|
|
|
|
/// Length of the bitfields structure in the BMP file.
|
2015-10-14 02:43:18 +03:00
|
|
|
static const size_t LENGTH = 12;
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace bmp
|
|
|
|
|
2010-08-14 08:09:49 +04:00
|
|
|
class RasterImage;
|
|
|
|
|
2015-10-14 02:08:06 +03:00
|
|
|
/// Decoder for BMP-Files, as used by Windows and OS/2.
|
2014-11-14 20:59:00 +03:00
|
|
|
|
2010-08-23 06:30:46 +04:00
|
|
|
class nsBMPDecoder : public Decoder
|
2001-11-03 10:10:51 +03:00
|
|
|
{
|
|
|
|
public:
|
2015-10-14 02:08:06 +03:00
|
|
|
~nsBMPDecoder();
|
2001-11-03 10:10:51 +03:00
|
|
|
|
2018-02-28 21:34:52 +03:00
|
|
|
DecoderType GetType() const override { return DecoderType::BMP; }
|
|
|
|
|
2017-07-22 14:50:31 +03:00
|
|
|
/// @return true if this BMP is a valid ICO resource.
|
|
|
|
bool IsValidICOResource() const override { return true; }
|
|
|
|
|
2015-10-14 02:08:06 +03:00
|
|
|
/// Obtains the internal output image buffer.
|
2015-10-16 03:38:32 +03:00
|
|
|
uint32_t* GetImageData() { return reinterpret_cast<uint32_t*>(mImageData); }
|
|
|
|
|
|
|
|
/// Obtains the length of the internal output image buffer.
|
2015-10-14 02:08:06 +03:00
|
|
|
size_t GetImageDataLength() const { return mImageDataLength; }
|
2014-11-14 20:59:00 +03:00
|
|
|
|
2015-10-14 02:08:06 +03:00
|
|
|
/// Obtains the size of the compressed image resource.
|
|
|
|
int32_t GetCompressedImageSize() const;
|
2014-11-14 20:59:00 +03:00
|
|
|
|
2015-10-16 01:43:31 +03:00
|
|
|
/// Mark this BMP as being within an ICO file. Only used for testing purposes
|
|
|
|
/// because the ICO-specific constructor does this marking automatically.
|
2015-10-14 07:20:10 +03:00
|
|
|
void SetIsWithinICO() { mIsWithinICO = true; }
|
|
|
|
|
|
|
|
/// Did the BMP file have alpha data of any kind? (Only use this after the
|
|
|
|
/// bitmap has been fully decoded.)
|
|
|
|
bool HasTransparency() const { return mDoesHaveTransparency; }
|
2015-09-09 08:07:09 +03:00
|
|
|
|
2016-07-16 08:27:12 +03:00
|
|
|
LexerResult DoDecode(SourceBufferIterator& aIterator,
|
|
|
|
IResumable* aOnResume) override;
|
2016-07-11 10:38:54 +03:00
|
|
|
nsresult BeforeFinishInternal() override;
|
|
|
|
nsresult FinishInternal() override;
|
2010-08-23 06:30:46 +04:00
|
|
|
|
2001-11-03 10:10:51 +03:00
|
|
|
private:
|
2015-10-14 02:08:06 +03:00
|
|
|
friend class DecoderFactory;
|
|
|
|
|
|
|
|
enum class State {
|
|
|
|
FILE_HEADER,
|
|
|
|
INFO_HEADER_SIZE,
|
|
|
|
INFO_HEADER_REST,
|
|
|
|
BITFIELDS,
|
|
|
|
COLOR_TABLE,
|
|
|
|
GAP,
|
2016-02-13 01:58:34 +03:00
|
|
|
AFTER_GAP,
|
2015-10-14 02:08:06 +03:00
|
|
|
PIXEL_ROW,
|
|
|
|
RLE_SEGMENT,
|
|
|
|
RLE_DELTA,
|
2015-10-28 11:30:20 +03:00
|
|
|
RLE_ABSOLUTE
|
2015-10-14 02:08:06 +03:00
|
|
|
};
|
|
|
|
|
2016-07-03 06:22:06 +03:00
|
|
|
// This is the constructor used for normal BMP images.
|
2015-10-16 01:43:31 +03:00
|
|
|
explicit nsBMPDecoder(RasterImage* aImage);
|
|
|
|
|
2016-07-03 06:22:06 +03:00
|
|
|
// This is the constructor used for BMP resources in ICO images.
|
2015-10-16 01:43:31 +03:00
|
|
|
nsBMPDecoder(RasterImage* aImage, uint32_t aDataOffset);
|
|
|
|
|
|
|
|
// Helper constructor called by the other two.
|
|
|
|
nsBMPDecoder(RasterImage* aImage, State aState, size_t aLength);
|
|
|
|
|
2015-10-16 03:38:32 +03:00
|
|
|
int32_t AbsoluteHeight() const { return abs(mH.mHeight); }
|
|
|
|
|
2015-10-16 01:43:31 +03:00
|
|
|
uint32_t* RowBuffer();
|
|
|
|
|
|
|
|
void FinishRow();
|
|
|
|
|
2015-10-14 02:08:06 +03:00
|
|
|
LexerTransition<State> ReadFileHeader(const char* aData, size_t aLength);
|
|
|
|
LexerTransition<State> ReadInfoHeaderSize(const char* aData, size_t aLength);
|
|
|
|
LexerTransition<State> ReadInfoHeaderRest(const char* aData, size_t aLength);
|
|
|
|
LexerTransition<State> ReadBitfields(const char* aData, size_t aLength);
|
|
|
|
LexerTransition<State> ReadColorTable(const char* aData, size_t aLength);
|
|
|
|
LexerTransition<State> SkipGap();
|
2016-02-13 01:58:34 +03:00
|
|
|
LexerTransition<State> AfterGap();
|
2015-10-14 02:08:06 +03:00
|
|
|
LexerTransition<State> ReadPixelRow(const char* aData);
|
|
|
|
LexerTransition<State> ReadRLESegment(const char* aData);
|
|
|
|
LexerTransition<State> ReadRLEDelta(const char* aData);
|
|
|
|
LexerTransition<State> ReadRLEAbsolute(const char* aData, size_t aLength);
|
|
|
|
|
|
|
|
StreamingLexer<State> mLexer;
|
|
|
|
|
2015-10-16 01:43:25 +03:00
|
|
|
bmp::Header mH;
|
2015-10-14 02:08:06 +03:00
|
|
|
|
2015-10-14 07:20:10 +03:00
|
|
|
// If the BMP is within an ICO file our treatment of it differs slightly.
|
|
|
|
bool mIsWithinICO;
|
|
|
|
|
2015-10-14 02:08:06 +03:00
|
|
|
bmp::BitFields mBitFields;
|
|
|
|
|
2015-10-14 06:01:24 +03:00
|
|
|
// Might the image have transparency? Determined from the headers during
|
|
|
|
// metadata decode. (Does not guarantee the image actually has transparency.)
|
|
|
|
bool mMayHaveTransparency;
|
|
|
|
|
2015-10-14 07:20:10 +03:00
|
|
|
// Does the image have transparency? Determined during full decoding, so only
|
|
|
|
// use this after that has been completed.
|
|
|
|
bool mDoesHaveTransparency;
|
|
|
|
|
2015-10-14 02:08:06 +03:00
|
|
|
uint32_t mNumColors; // The number of used colors, i.e. the number of
|
|
|
|
// entries in mColors, if it's present.
|
2015-10-27 17:47:51 +03:00
|
|
|
UniquePtr<bmp::ColorTableEntry[]> mColors; // The color table, if it's present.
|
2015-10-14 02:08:06 +03:00
|
|
|
uint32_t mBytesPerColor; // 3 or 4, depending on the format
|
|
|
|
|
|
|
|
// The number of bytes prior to the optional gap that have been read. This
|
|
|
|
// is used to find the start of the pixel data.
|
|
|
|
uint32_t mPreGapLength;
|
|
|
|
|
|
|
|
uint32_t mPixelRowSize; // The number of bytes per pixel row.
|
|
|
|
|
|
|
|
int32_t mCurrentRow; // Index of the row of the image that's currently
|
|
|
|
// being decoded: [height,1].
|
2015-11-16 07:31:07 +03:00
|
|
|
int32_t mCurrentPos; // Index into the current line. Used when
|
|
|
|
// doing RLE decoding and when filling in pixels
|
|
|
|
// for truncated files.
|
2015-10-14 02:08:06 +03:00
|
|
|
|
|
|
|
// Only used in RLE_ABSOLUTE state: the number of pixels to read.
|
|
|
|
uint32_t mAbsoluteModeNumPixels;
|
2001-11-03 10:10:51 +03:00
|
|
|
};
|
|
|
|
|
2012-01-06 20:02:27 +04:00
|
|
|
} // namespace image
|
2010-08-23 06:30:46 +04:00
|
|
|
} // namespace mozilla
|
|
|
|
|
2015-04-06 02:22:00 +03:00
|
|
|
#endif // mozilla_image_decoders_nsBMPDecoder_h
|