1 /*
2  * Copyright (c) 2008, 2009, Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include "third_party/blink/renderer/platform/image-decoders/bmp/bmp_image_decoder.h"
32 
33 #include "third_party/blink/renderer/platform/image-decoders/bmp/bmp_image_reader.h"
34 #include "third_party/blink/renderer/platform/image-decoders/fast_shared_buffer_reader.h"
35 
36 namespace blink {
37 
38 // Number of bits in .BMP used to store the file header (doesn't match
39 // "sizeof(BMPImageDecoder::BitmapFileHeader)" since we omit some fields and
40 // don't pack).
41 static const size_t kSizeOfFileHeader = 14;
42 
BMPImageDecoder(AlphaOption alpha_option,const ColorBehavior & color_behavior,size_t max_decoded_bytes)43 BMPImageDecoder::BMPImageDecoder(AlphaOption alpha_option,
44                                  const ColorBehavior& color_behavior,
45                                  size_t max_decoded_bytes)
46     : ImageDecoder(alpha_option,
47                    ImageDecoder::kDefaultBitDepth,
48                    color_behavior,
49                    max_decoded_bytes),
50       decoded_offset_(0) {}
51 
52 BMPImageDecoder::~BMPImageDecoder() = default;
53 
OnSetData(SegmentReader * data)54 void BMPImageDecoder::OnSetData(SegmentReader* data) {
55   if (reader_)
56     reader_->SetData(data);
57 }
58 
SetFailed()59 bool BMPImageDecoder::SetFailed() {
60   reader_.reset();
61   return ImageDecoder::SetFailed();
62 }
63 
Decode(bool only_size)64 void BMPImageDecoder::Decode(bool only_size) {
65   if (Failed())
66     return;
67 
68   // If we couldn't decode the image but we've received all the data, decoding
69   // has failed.
70   if (!DecodeHelper(only_size) && IsAllDataReceived())
71     SetFailed();
72   // If we're done decoding the image, we don't need the BMPImageReader
73   // anymore.  (If we failed, |reader_| has already been cleared.)
74   else if (!frame_buffer_cache_.IsEmpty() &&
75            (frame_buffer_cache_.front().GetStatus() ==
76             ImageFrame::kFrameComplete))
77     reader_.reset();
78 }
79 
DecodeHelper(bool only_size)80 bool BMPImageDecoder::DecodeHelper(bool only_size) {
81   size_t img_data_offset = 0;
82   if ((decoded_offset_ < kSizeOfFileHeader) &&
83       !ProcessFileHeader(img_data_offset))
84     return false;
85 
86   if (!reader_) {
87     reader_ = std::make_unique<BMPImageReader>(this, decoded_offset_,
88                                                img_data_offset, false);
89     reader_->SetData(data_.get());
90   }
91 
92   if (!frame_buffer_cache_.IsEmpty())
93     reader_->SetBuffer(&frame_buffer_cache_.front());
94 
95   return reader_->DecodeBMP(only_size);
96 }
97 
ProcessFileHeader(size_t & img_data_offset)98 bool BMPImageDecoder::ProcessFileHeader(size_t& img_data_offset) {
99   // Read file header.
100   DCHECK(!decoded_offset_);
101   FastSharedBufferReader fast_reader(data_);
102   char buffer[kSizeOfFileHeader];
103   const char* file_header;
104   uint16_t file_type;
105   if (!GetFileType(fast_reader, buffer, file_header, file_type))
106     return false;
107 
108   // See if this is a bitmap filetype we understand.
109   enum {
110     BMAP = 0x424D,         // "BM"
111     BITMAPARRAY = 0x4241,  // "BA"
112     // The following additional OS/2 2.x header values (see
113     // http://www.fileformat.info/format/os2bmp/egff.htm ) aren't widely
114     // decoded, and are unlikely to be in much use.
115     /*
116     ICON = 0x4943,  // "IC"
117     POINTER = 0x5054,  // "PT"
118     COLORICON = 0x4349,  // "CI"
119     COLORPOINTER = 0x4350,  // "CP"
120     */
121   };
122   if (file_type == BITMAPARRAY) {
123     // Skip initial 14-byte header, try to read the first entry as a BMAP.
124     decoded_offset_ += kSizeOfFileHeader;
125     if (!GetFileType(fast_reader, buffer, file_header, file_type))
126       return false;
127   }
128   if (file_type != BMAP)
129     return SetFailed();
130 
131   img_data_offset = BMPImageReader::ReadUint32(&file_header[10]);
132   decoded_offset_ += kSizeOfFileHeader;
133   return true;
134 }
135 
GetFileType(const FastSharedBufferReader & fast_reader,char * buffer,const char * & file_header,uint16_t & file_type) const136 bool BMPImageDecoder::GetFileType(const FastSharedBufferReader& fast_reader,
137                                   char* buffer,
138                                   const char*& file_header,
139                                   uint16_t& file_type) const {
140   if (data_->size() - decoded_offset_ < kSizeOfFileHeader)
141     return false;
142   file_header = fast_reader.GetConsecutiveData(decoded_offset_,
143                                                kSizeOfFileHeader, buffer);
144   file_type = (file_header[0] << 8) | static_cast<uint8_t>(file_header[1]);
145   return true;
146 }
147 
148 }  // namespace blink
149