1 
2 /*
3  * Copyright 2006 The Android Open Source Project
4  *
5  * Use of this source code is governed by a BSD-style license that can be
6  * found in the LICENSE file.
7  */
8 
9 
10 #include "SkImageDecoder.h"
11 #include "SkColor.h"
12 #include "SkColorPriv.h"
13 #include "SkMath.h"
14 #include "SkStream.h"
15 #include "SkTemplates.h"
16 #include "SkUtils.h"
17 
18 class SkWBMPImageDecoder : public SkImageDecoder {
19 public:
getFormat() const20     Format getFormat() const override {
21         return kWBMP_Format;
22     }
23 
24 protected:
25     Result onDecode(SkStream* stream, SkBitmap* bm, Mode) override;
26 
27 private:
28     typedef SkImageDecoder INHERITED;
29 };
30 
read_byte(SkStream * stream,uint8_t * data)31 static bool read_byte(SkStream* stream, uint8_t* data)
32 {
33     return stream->read(data, 1) == 1;
34 }
35 
read_mbf(SkStream * stream,int * value)36 static bool read_mbf(SkStream* stream, int* value)
37 {
38     int n = 0;
39     uint8_t data;
40     do {
41         if (!read_byte(stream, &data)) {
42             return false;
43         }
44         n = (n << 7) | (data & 0x7F);
45     } while (data & 0x80);
46 
47     *value = n;
48     return true;
49 }
50 
51 struct wbmp_head {
52     int fWidth;
53     int fHeight;
54 
initwbmp_head55     bool init(SkStream* stream)
56     {
57         uint8_t data;
58 
59         if (!read_byte(stream, &data) || data != 0) { // unknown type
60             return false;
61         }
62         if (!read_byte(stream, &data) || (data & 0x9F)) { // skip fixed header
63             return false;
64         }
65         if (!read_mbf(stream, &fWidth) || (unsigned)fWidth > 0xFFFF) {
66             return false;
67         }
68         if (!read_mbf(stream, &fHeight) || (unsigned)fHeight > 0xFFFF) {
69             return false;
70         }
71         return fWidth != 0 && fHeight != 0;
72     }
73 };
74 
expand_bits_to_bytes(uint8_t dst[],const uint8_t src[],int bits)75 static void expand_bits_to_bytes(uint8_t dst[], const uint8_t src[], int bits)
76 {
77     int bytes = bits >> 3;
78 
79     for (int i = 0; i < bytes; i++) {
80         unsigned mask = *src++;
81         dst[0] = (mask >> 7) & 1;
82         dst[1] = (mask >> 6) & 1;
83         dst[2] = (mask >> 5) & 1;
84         dst[3] = (mask >> 4) & 1;
85         dst[4] = (mask >> 3) & 1;
86         dst[5] = (mask >> 2) & 1;
87         dst[6] = (mask >> 1) & 1;
88         dst[7] = (mask >> 0) & 1;
89         dst += 8;
90     }
91 
92     bits &= 7;
93     if (bits > 0) {
94         unsigned mask = *src;
95         do {
96             *dst++ = (mask >> 7) & 1;
97             mask <<= 1;
98         } while (--bits != 0);
99     }
100 }
101 
onDecode(SkStream * stream,SkBitmap * decodedBitmap,Mode mode)102 SkImageDecoder::Result SkWBMPImageDecoder::onDecode(SkStream* stream, SkBitmap* decodedBitmap,
103                                                     Mode mode)
104 {
105     wbmp_head   head;
106 
107     if (!head.init(stream)) {
108         return kFailure;
109     }
110 
111     int width = head.fWidth;
112     int height = head.fHeight;
113 
114     decodedBitmap->setInfo(SkImageInfo::Make(width, height,
115                                              kIndex_8_SkColorType, kOpaque_SkAlphaType));
116 
117     if (SkImageDecoder::kDecodeBounds_Mode == mode) {
118         return kSuccess;
119     }
120 
121     const SkPMColor colors[] = { SK_ColorBLACK, SK_ColorWHITE };
122     SkColorTable* ct = SkNEW_ARGS(SkColorTable, (colors, 2));
123     SkAutoUnref   aur(ct);
124 
125     if (!this->allocPixelRef(decodedBitmap, ct)) {
126         return kFailure;
127     }
128 
129     SkAutoLockPixels alp(*decodedBitmap);
130 
131     uint8_t* dst = decodedBitmap->getAddr8(0, 0);
132     // store the 1-bit valuess at the end of our pixels, so we won't stomp
133     // on them before we're read them. Just trying to avoid a temp allocation
134     size_t srcRB = SkAlign8(width) >> 3;
135     size_t srcSize = height * srcRB;
136     uint8_t* src = dst + decodedBitmap->getSize() - srcSize;
137     if (stream->read(src, srcSize) != srcSize) {
138         return kFailure;
139     }
140 
141     for (int y = 0; y < height; y++)
142     {
143         expand_bits_to_bytes(dst, src, width);
144         dst += decodedBitmap->rowBytes();
145         src += srcRB;
146     }
147 
148     return kSuccess;
149 }
150 
151 ///////////////////////////////////////////////////////////////////////////////
152 DEFINE_DECODER_CREATOR(WBMPImageDecoder);
153 ///////////////////////////////////////////////////////////////////////////////
154 
sk_wbmp_dfactory(SkStreamRewindable * stream)155 static SkImageDecoder* sk_wbmp_dfactory(SkStreamRewindable* stream) {
156     wbmp_head   head;
157 
158     if (head.init(stream)) {
159         return SkNEW(SkWBMPImageDecoder);
160     }
161     return NULL;
162 }
163 
get_format_wbmp(SkStreamRewindable * stream)164 static SkImageDecoder::Format get_format_wbmp(SkStreamRewindable* stream) {
165     wbmp_head head;
166     if (head.init(stream)) {
167         return SkImageDecoder::kWBMP_Format;
168     }
169     return SkImageDecoder::kUnknown_Format;
170 }
171 
172 static SkImageDecoder_DecodeReg gDReg(sk_wbmp_dfactory);
173 static SkImageDecoder_FormatReg gFormatReg(get_format_wbmp);
174