OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright 2006 The Android Open Source Project | 2 * Copyright 2006 The Android Open Source Project |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkColorPriv.h" | 8 #include "SkColorPriv.h" |
9 #include "SkImageDecoder.h" | 9 #include "SkImageDecoder.h" |
10 #include "SkStream.h" | 10 #include "SkStream.h" |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
75 SkImageDecoder::Result SkICOImageDecoder::onDecode(SkStream* stream, SkBitmap* b m, Mode mode) | 75 SkImageDecoder::Result SkICOImageDecoder::onDecode(SkStream* stream, SkBitmap* b m, Mode mode) |
76 { | 76 { |
77 SkAutoMalloc autoMal; | 77 SkAutoMalloc autoMal; |
78 const size_t length = SkCopyStreamToStorage(&autoMal, stream); | 78 const size_t length = SkCopyStreamToStorage(&autoMal, stream); |
79 if (0 == length) { | 79 if (0 == length) { |
80 return kFailure; | 80 return kFailure; |
81 } | 81 } |
82 | 82 |
83 unsigned char* buf = (unsigned char*)autoMal.get(); | 83 unsigned char* buf = (unsigned char*)autoMal.get(); |
84 | 84 |
85 // Check that the buffer is large enough to read the directory header | |
86 if (length < 6) { | |
scroggo
2015/03/12 13:25:54
Why not merge this with the earlier check? We did
| |
87 return kFailure; | |
88 } | |
85 //these should always be the same - should i use for error checking? - what about files that have some | 89 //these should always be the same - should i use for error checking? - what about files that have some |
86 //incorrect values, but still decode properly? | 90 //incorrect values, but still decode properly? |
87 int reserved = read2Bytes(buf, 0); // 0 | 91 int reserved = read2Bytes(buf, 0); // 0 |
88 int type = read2Bytes(buf, 2); // 1 | 92 int type = read2Bytes(buf, 2); // 1 |
89 if (reserved != 0 || type != 1) { | 93 if (reserved != 0 || type != 1) { |
90 return kFailure; | 94 return kFailure; |
91 } | 95 } |
92 | 96 |
93 int count = read2Bytes(buf, 4); | 97 int count = read2Bytes(buf, 4); |
98 // Check that there are directory entries | |
99 if (count < 1) { | |
100 return kFailure; | |
101 } | |
94 | 102 |
95 //need to at least have enough space to hold the initial table of info | 103 // Check that buffer is large enough to read directory entries. |
104 // We are guaranteed that count is at least 1. We might as well assume | |
105 // count is 1 because this deprecated decoder only looks at the first | |
106 // directory entry. | |
96 if (length < (size_t)(6 + count*16)) { | 107 if (length < (size_t)(6 + count*16)) { |
97 return kFailure; | 108 return kFailure; |
98 } | 109 } |
99 | 110 |
100 //skip ahead to the correct header | 111 //skip ahead to the correct header |
101 //commented out lines are not used, but if i switch to other read method, ne ed to know how many to skip | 112 //commented out lines are not used, but if i switch to other read method, ne ed to know how many to skip |
102 //otherwise, they could be used for error checking | 113 //otherwise, they could be used for error checking |
103 int w = readByte(buf, 6); | 114 int w = readByte(buf, 6); |
104 int h = readByte(buf, 7); | 115 int h = readByte(buf, 7); |
105 int colorCount = readByte(buf, 8); | 116 int colorCount = readByte(buf, 8); |
106 //int reservedToo = readByte(buf, 9 + choice*16); //0 | 117 //int reservedToo = readByte(buf, 9 + choice*16); //0 |
107 //int planes = read2Bytes(buf, 10 + choice*16); //1 - but often 0 | 118 //int planes = read2Bytes(buf, 10 + choice*16); //1 - but often 0 |
108 //int fakeBitCount = read2Bytes(buf, 12 + choice*16); //should be real - usu ally 0 | 119 //int fakeBitCount = read2Bytes(buf, 12 + choice*16); //should be real - usu ally 0 |
109 const size_t size = read4Bytes(buf, 14); //matters? | 120 const size_t size = read4Bytes(buf, 14); //matters? |
110 const size_t offset = read4Bytes(buf, 18); | 121 const size_t offset = read4Bytes(buf, 18); |
111 // promote the sum to 64-bits to avoid overflow | 122 // promote the sum to 64-bits to avoid overflow |
123 // Check that buffer is large enough to read image data | |
112 if (offset > length || size > length || ((uint64_t)offset + size) > length) { | 124 if (offset > length || size > length || ((uint64_t)offset + size) > length) { |
113 return kFailure; | 125 return kFailure; |
114 } | 126 } |
115 | 127 |
116 // Check to see if this is a PNG image inside the ICO | 128 // Check to see if this is a PNG image inside the ICO |
117 { | 129 { |
118 SkMemoryStream subStream(buf + offset, size, false); | 130 SkMemoryStream subStream(buf + offset, size, false); |
119 SkAutoTDelete<SkImageDecoder> otherDecoder(SkImageDecoder::Factory(&subS tream)); | 131 SkAutoTDelete<SkImageDecoder> otherDecoder(SkImageDecoder::Factory(&subS tream)); |
120 if (otherDecoder.get() != NULL) { | 132 if (otherDecoder.get() != NULL) { |
121 // Disallow nesting ICO files within one another | 133 // Disallow nesting ICO files within one another |
(...skipping 10 matching lines...) Expand all Loading... | |
132 if (result != kFailure) { | 144 if (result != kFailure) { |
133 return result; | 145 return result; |
134 } | 146 } |
135 } | 147 } |
136 } | 148 } |
137 | 149 |
138 //int infoSize = read4Bytes(buf, offset); //40 | 150 //int infoSize = read4Bytes(buf, offset); //40 |
139 //int width = read4Bytes(buf, offset+4); //should == w | 151 //int width = read4Bytes(buf, offset+4); //should == w |
140 //int height = read4Bytes(buf, offset+8); //should == 2*h | 152 //int height = read4Bytes(buf, offset+8); //should == 2*h |
141 //int planesToo = read2Bytes(buf, offset+12); //should == 1 (does it ?) | 153 //int planesToo = read2Bytes(buf, offset+12); //should == 1 (does it ?) |
154 | |
155 // Check that buffer is large enough to read the bit depth | |
156 if (length < offset + 16) { | |
157 return kFailure; | |
158 } | |
142 int bitCount = read2Bytes(buf, offset+14); | 159 int bitCount = read2Bytes(buf, offset+14); |
143 | 160 |
144 void (*placePixel)(const int pixelNo, const unsigned char* buf, | 161 void (*placePixel)(const int pixelNo, const unsigned char* buf, |
145 const int xorOffset, int& x, int y, const int w, | 162 const int xorOffset, int& x, int y, const int w, |
146 SkBitmap* bm, int alphaByte, int m, int shift, SkPMColor* colors) = NULL ; | 163 SkBitmap* bm, int alphaByte, int m, int shift, SkPMColor* colors) = NULL ; |
147 switch (bitCount) | 164 switch (bitCount) |
148 { | 165 { |
149 case 1: | 166 case 1: |
150 placePixel = &editPixelBit1; | 167 placePixel = &editPixelBit1; |
151 colorCount = 2; | 168 colorCount = 2; |
(...skipping 21 matching lines...) Expand all Loading... | |
173 | 190 |
174 //these should all be zero, but perhaps are not - need to check | 191 //these should all be zero, but perhaps are not - need to check |
175 //int compression = read4Bytes(buf, offset+16); //0 | 192 //int compression = read4Bytes(buf, offset+16); //0 |
176 //int imageSize = read4Bytes(buf, offset+20); //0 - sometimes has a value | 193 //int imageSize = read4Bytes(buf, offset+20); //0 - sometimes has a value |
177 //int xPixels = read4Bytes(buf, offset+24); //0 | 194 //int xPixels = read4Bytes(buf, offset+24); //0 |
178 //int yPixels = read4Bytes(buf, offset+28); //0 | 195 //int yPixels = read4Bytes(buf, offset+28); //0 |
179 //int colorsUsed = read4Bytes(buf, offset+32) //0 - might have an ac tual value though | 196 //int colorsUsed = read4Bytes(buf, offset+32) //0 - might have an ac tual value though |
180 //int colorsImportant = read4Bytes(buf, offset+36); //0 | 197 //int colorsImportant = read4Bytes(buf, offset+36); //0 |
181 | 198 |
182 int begin = SkToInt(offset + 40); | 199 int begin = SkToInt(offset + 40); |
200 // Check that the buffer is large enough to read the color table | |
201 int bytesPerColor = 4; | |
scroggo
2015/03/12 13:25:54
This can be inlined, since it's only used once. (M
msarett
2015/03/12 15:58:52
Sure. FWIW, 4 shows up in the code later. We cou
| |
202 if (length < begin + bytesPerColor*colorCount) { | |
203 return kFailure; | |
204 } | |
205 | |
183 //this array represents the colortable | 206 //this array represents the colortable |
184 //if i allow other types of bitmaps, it may actually be used as a part of th e bitmap | 207 //if i allow other types of bitmaps, it may actually be used as a part of th e bitmap |
185 SkPMColor* colors = NULL; | 208 SkPMColor* colors = NULL; |
186 int blue, green, red; | 209 int blue, green, red; |
187 if (colorCount) | 210 if (colorCount) |
188 { | 211 { |
189 colors = new SkPMColor[colorCount]; | 212 colors = new SkPMColor[colorCount]; |
190 for (int j = 0; j < colorCount; j++) | 213 for (int j = 0; j < colorCount; j++) |
191 { | 214 { |
192 //should this be a function - maybe a #define? | 215 //should this be a function - maybe a #define? |
(...skipping 28 matching lines...) Expand all Loading... | |
221 delete[] colors; | 244 delete[] colors; |
222 return kSuccess; | 245 return kSuccess; |
223 } | 246 } |
224 | 247 |
225 if (!this->allocPixelRef(bm, NULL)) | 248 if (!this->allocPixelRef(bm, NULL)) |
226 { | 249 { |
227 delete[] colors; | 250 delete[] colors; |
228 return kFailure; | 251 return kFailure; |
229 } | 252 } |
230 | 253 |
254 // The AND mask comes after the OR mask in the bmp. If we check that the | |
255 // largest AND offset is safe, it should mean all other buffer accesses | |
256 // will be at smaller indices and will therefore be safe. | |
257 int maxAndOffset = andOffset + ((andLineWidth*(h-1)+(w-1)) >> 3); | |
scroggo
2015/03/12 13:25:54
nit: This seems like it's the max offset of the al
msarett
2015/03/12 15:58:52
The AND mask is a 1 bit mask for each pixel indica
| |
258 if (length <= maxAndOffset) { | |
259 return kFailure; | |
260 } | |
261 | |
231 SkAutoLockPixels alp(*bm); | 262 SkAutoLockPixels alp(*bm); |
232 | 263 |
233 for (int y = 0; y < h; y++) | 264 for (int y = 0; y < h; y++) |
234 { | 265 { |
235 for (int x = 0; x < w; x++) | 266 for (int x = 0; x < w; x++) |
236 { | 267 { |
237 //U32* address = bm->getAddr32(x, y); | 268 //U32* address = bm->getAddr32(x, y); |
238 | 269 |
239 //check the alpha bit first, but pass it along to the function to fi gure out how to deal with it | 270 //check the alpha bit first, but pass it along to the function to fi gure out how to deal with it |
240 int andPixelNo = andLineWidth*(h-y-1)+x; | 271 int andPixelNo = andLineWidth*(h-y-1)+x; |
241 //only need to get a new alphaByte when x %8 == 0 | 272 //only need to get a new alphaByte when x %8 == 0 |
242 //but that introduces an if and a mod - probably much slower | 273 //but that introduces an if and a mod - probably much slower |
243 //that's ok, it's just a read of an array, not a stream | 274 //that's ok, it's just a read of an array, not a stream |
244 int alphaByte = readByte(buf, andOffset + (andPixelNo >> 3)); | 275 int alphaByte = readByte(buf, andOffset + (andPixelNo >> 3)); |
245 int shift = 7 - (andPixelNo & 0x7); | 276 int shift = 7 - (andPixelNo & 0x7); |
246 int m = 1 << shift; | 277 int m = 1 << shift; |
247 | 278 |
248 int pixelNo = lineWidth*(h-y-1)+x; | 279 int pixelNo = lineWidth*(h-y-1)+x; |
249 placePixel(pixelNo, buf, xorOffset, x, y, w, bm, alphaByte, m, shift , colors); | 280 placePixel(pixelNo, buf, xorOffset, x, y, w, bm, alphaByte, m, shift , colors); |
scroggo
2015/03/12 13:25:54
Here's the part where I get nervous. We pass buf t
msarett
2015/03/12 15:58:52
The XOR offset SHOULD always be less than the AND
| |
250 | 281 |
251 } | 282 } |
252 } | 283 } |
253 | 284 |
254 delete [] colors; | 285 delete [] colors; |
255 //ensure we haven't read off the end? | 286 //ensure we haven't read off the end? |
256 //of course this doesn't help us if the andOffset was a lie... | 287 //of course this doesn't help us if the andOffset was a lie... |
257 //return andOffset + (andLineWidth >> 3) <= length; | 288 //return andOffset + (andLineWidth >> 3) <= length; |
258 return kSuccess; | 289 return kSuccess; |
259 } //onDecode | 290 } //onDecode |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
374 static SkImageDecoder_DecodeReg gReg(sk_libico_dfactory); | 405 static SkImageDecoder_DecodeReg gReg(sk_libico_dfactory); |
375 | 406 |
376 static SkImageDecoder::Format get_format_ico(SkStreamRewindable* stream) { | 407 static SkImageDecoder::Format get_format_ico(SkStreamRewindable* stream) { |
377 if (is_ico(stream)) { | 408 if (is_ico(stream)) { |
378 return SkImageDecoder::kICO_Format; | 409 return SkImageDecoder::kICO_Format; |
379 } | 410 } |
380 return SkImageDecoder::kUnknown_Format; | 411 return SkImageDecoder::kUnknown_Format; |
381 } | 412 } |
382 | 413 |
383 static SkImageDecoder_FormatReg gFormatReg(get_format_ico); | 414 static SkImageDecoder_FormatReg gFormatReg(get_format_ico); |
OLD | NEW |