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 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
69 return (w + 1) << 2; | 69 return (w + 1) << 2; |
70 } | 70 } |
71 // Otherwise return 0, which will allow it to be calculated automatically. | 71 // Otherwise return 0, which will allow it to be calculated automatically. |
72 return 0; | 72 return 0; |
73 } | 73 } |
74 | 74 |
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 // Check that the buffer is large enough to read the directory header |
80 if (length < 6) { | |
80 return kFailure; | 81 return kFailure; |
81 } | 82 } |
82 | 83 |
83 unsigned char* buf = (unsigned char*)autoMal.get(); | 84 unsigned char* buf = (unsigned char*)autoMal.get(); |
84 | 85 |
85 //these should always be the same - should i use for error checking? - what about files that have some | 86 //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? | 87 //incorrect values, but still decode properly? |
87 int reserved = read2Bytes(buf, 0); // 0 | 88 int reserved = read2Bytes(buf, 0); // 0 |
88 int type = read2Bytes(buf, 2); // 1 | 89 int type = read2Bytes(buf, 2); // 1 |
89 if (reserved != 0 || type != 1) { | 90 if (reserved != 0 || type != 1) { |
90 return kFailure; | 91 return kFailure; |
91 } | 92 } |
92 | 93 |
93 int count = read2Bytes(buf, 4); | 94 int count = read2Bytes(buf, 4); |
95 // Check that there are directory entries | |
96 if (count < 1) { | |
97 return kFailure; | |
98 } | |
94 | 99 |
95 //need to at least have enough space to hold the initial table of info | 100 // Check that buffer is large enough to read directory entries. |
101 // We are guaranteed that count is at least 1. We might as well assume | |
102 // count is 1 because this deprecated decoder only looks at the first | |
103 // directory entry. | |
96 if (length < (size_t)(6 + count*16)) { | 104 if (length < (size_t)(6 + count*16)) { |
97 return kFailure; | 105 return kFailure; |
98 } | 106 } |
99 | 107 |
100 //skip ahead to the correct header | 108 //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 | 109 //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 | 110 //otherwise, they could be used for error checking |
103 int w = readByte(buf, 6); | 111 int w = readByte(buf, 6); |
104 int h = readByte(buf, 7); | 112 int h = readByte(buf, 7); |
113 SkASSERT(w >= 0 && h >= 0); | |
scroggo
2015/03/12 21:19:29
Is this because readByte is guaranteed to return a
msarett
2015/03/12 22:18:22
It is because readByte is guaranteed to return a n
scroggo
2015/03/13 13:43:12
Ah, got it, because buf is defined as pointer to u
| |
105 int colorCount = readByte(buf, 8); | 114 int colorCount = readByte(buf, 8); |
106 //int reservedToo = readByte(buf, 9 + choice*16); //0 | 115 //int reservedToo = readByte(buf, 9 + choice*16); //0 |
107 //int planes = read2Bytes(buf, 10 + choice*16); //1 - but often 0 | 116 //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 | 117 //int fakeBitCount = read2Bytes(buf, 12 + choice*16); //should be real - usu ally 0 |
109 const size_t size = read4Bytes(buf, 14); //matters? | 118 const size_t size = read4Bytes(buf, 14); //matters? |
110 const size_t offset = read4Bytes(buf, 18); | 119 const size_t offset = read4Bytes(buf, 18); |
111 // promote the sum to 64-bits to avoid overflow | 120 // promote the sum to 64-bits to avoid overflow |
121 // Check that buffer is large enough to read image data | |
112 if (offset > length || size > length || ((uint64_t)offset + size) > length) { | 122 if (offset > length || size > length || ((uint64_t)offset + size) > length) { |
113 return kFailure; | 123 return kFailure; |
114 } | 124 } |
115 | 125 |
116 // Check to see if this is a PNG image inside the ICO | 126 // Check to see if this is a PNG image inside the ICO |
117 { | 127 { |
118 SkMemoryStream subStream(buf + offset, size, false); | 128 SkMemoryStream subStream(buf + offset, size, false); |
119 SkAutoTDelete<SkImageDecoder> otherDecoder(SkImageDecoder::Factory(&subS tream)); | 129 SkAutoTDelete<SkImageDecoder> otherDecoder(SkImageDecoder::Factory(&subS tream)); |
120 if (otherDecoder.get() != NULL) { | 130 if (otherDecoder.get() != NULL) { |
121 // Disallow nesting ICO files within one another | 131 // Disallow nesting ICO files within one another |
(...skipping 10 matching lines...) Expand all Loading... | |
132 if (result != kFailure) { | 142 if (result != kFailure) { |
133 return result; | 143 return result; |
134 } | 144 } |
135 } | 145 } |
136 } | 146 } |
137 | 147 |
138 //int infoSize = read4Bytes(buf, offset); //40 | 148 //int infoSize = read4Bytes(buf, offset); //40 |
139 //int width = read4Bytes(buf, offset+4); //should == w | 149 //int width = read4Bytes(buf, offset+4); //should == w |
140 //int height = read4Bytes(buf, offset+8); //should == 2*h | 150 //int height = read4Bytes(buf, offset+8); //should == 2*h |
141 //int planesToo = read2Bytes(buf, offset+12); //should == 1 (does it ?) | 151 //int planesToo = read2Bytes(buf, offset+12); //should == 1 (does it ?) |
152 | |
153 // For ico images, only a byte is used to store each dimension | |
msarett
2015/03/12 15:58:52
The original decoder does not make this check. I
scroggo
2015/03/12 21:19:29
If images in the wild use 0 to mean 256, we should
msarett
2015/03/12 22:18:22
This is how images in the wild are stored. I will
| |
154 // 0 is used to represent 256 | |
155 if (w == 0) { | |
156 w = 256; | |
157 } | |
158 if (h == 0) { | |
159 h = 256; | |
160 } | |
161 | |
162 // Check that buffer is large enough to read the bit depth | |
163 if (length < offset + 16) { | |
164 return kFailure; | |
165 } | |
142 int bitCount = read2Bytes(buf, offset+14); | 166 int bitCount = read2Bytes(buf, offset+14); |
143 | 167 |
144 void (*placePixel)(const int pixelNo, const unsigned char* buf, | 168 void (*placePixel)(const int pixelNo, const unsigned char* buf, |
145 const int xorOffset, int& x, int y, const int w, | 169 const int xorOffset, int& x, int y, const int w, |
146 SkBitmap* bm, int alphaByte, int m, int shift, SkPMColor* colors) = NULL ; | 170 SkBitmap* bm, int alphaByte, int m, int shift, SkPMColor* colors) = NULL ; |
147 switch (bitCount) | 171 switch (bitCount) |
148 { | 172 { |
149 case 1: | 173 case 1: |
150 placePixel = &editPixelBit1; | 174 placePixel = &editPixelBit1; |
151 colorCount = 2; | 175 colorCount = 2; |
(...skipping 21 matching lines...) Expand all Loading... | |
173 | 197 |
174 //these should all be zero, but perhaps are not - need to check | 198 //these should all be zero, but perhaps are not - need to check |
175 //int compression = read4Bytes(buf, offset+16); //0 | 199 //int compression = read4Bytes(buf, offset+16); //0 |
176 //int imageSize = read4Bytes(buf, offset+20); //0 - sometimes has a value | 200 //int imageSize = read4Bytes(buf, offset+20); //0 - sometimes has a value |
177 //int xPixels = read4Bytes(buf, offset+24); //0 | 201 //int xPixels = read4Bytes(buf, offset+24); //0 |
178 //int yPixels = read4Bytes(buf, offset+28); //0 | 202 //int yPixels = read4Bytes(buf, offset+28); //0 |
179 //int colorsUsed = read4Bytes(buf, offset+32) //0 - might have an ac tual value though | 203 //int colorsUsed = read4Bytes(buf, offset+32) //0 - might have an ac tual value though |
180 //int colorsImportant = read4Bytes(buf, offset+36); //0 | 204 //int colorsImportant = read4Bytes(buf, offset+36); //0 |
181 | 205 |
182 int begin = SkToInt(offset + 40); | 206 int begin = SkToInt(offset + 40); |
207 // Check that the buffer is large enough to read the color table | |
208 // For bmp-in-icos, there should be 4 bytes per color | |
209 if (length < begin + 4*colorCount) { | |
210 return kFailure; | |
211 } | |
212 | |
183 //this array represents the colortable | 213 //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 | 214 //if i allow other types of bitmaps, it may actually be used as a part of th e bitmap |
185 SkPMColor* colors = NULL; | 215 SkPMColor* colors = NULL; |
186 int blue, green, red; | 216 int blue, green, red; |
187 if (colorCount) | 217 if (colorCount) |
188 { | 218 { |
189 colors = new SkPMColor[colorCount]; | 219 colors = new SkPMColor[colorCount]; |
190 for (int j = 0; j < colorCount; j++) | 220 for (int j = 0; j < colorCount; j++) |
191 { | 221 { |
192 //should this be a function - maybe a #define? | 222 //should this be a function - maybe a #define? |
(...skipping 28 matching lines...) Expand all Loading... | |
221 delete[] colors; | 251 delete[] colors; |
222 return kSuccess; | 252 return kSuccess; |
223 } | 253 } |
224 | 254 |
225 if (!this->allocPixelRef(bm, NULL)) | 255 if (!this->allocPixelRef(bm, NULL)) |
226 { | 256 { |
227 delete[] colors; | 257 delete[] colors; |
228 return kFailure; | 258 return kFailure; |
229 } | 259 } |
230 | 260 |
261 // The AND mask is a 1-bit alpha mask for each pixel that comes after the | |
262 // OR mask in the bmp. If we check that the largest AND offset is safe, | |
msarett
2015/03/12 15:58:52
This is a type I meant XOR not OR. Will fix in ne
| |
263 // it should mean all other buffer accesses will be at smaller indices and | |
264 // will therefore be safe. | |
265 int maxAndOffset = andOffset + ((andLineWidth*(h-1)+(w-1)) >> 3); | |
266 if (length <= maxAndOffset) { | |
267 return kFailure; | |
268 } | |
269 | |
270 // Here we assert that all reads from the buffer using the XOR offset are | |
271 // less than the AND offset. This should be guaranteed based on the above | |
272 // calculations. | |
273 SkDEBUGCODE( | |
scroggo
2015/03/12 21:19:29
nit: Typically we use SkDEBUGCODE for one line. Fo
msarett
2015/03/12 22:18:22
Done.
| |
274 int maxPixelNum = lineWidth*(h-1)+w-1; | |
275 int maxByte; | |
276 switch (bitCount) { | |
277 case 1: | |
278 maxByte = maxPixelNum >> 3; | |
279 break; | |
280 case 4: | |
281 maxByte = maxPixelNum >> 1; | |
282 break; | |
283 case 8: | |
284 maxByte = maxPixelNum; | |
285 break; | |
286 case 24: | |
287 maxByte = maxPixelNum * 3 + 2; | |
288 break; | |
289 case 32: | |
290 maxByte = maxPixelNum * 4 + 3; | |
291 break; | |
292 default: | |
293 SkASSERT(false); | |
294 return kFailure; | |
scroggo
2015/03/12 21:19:29
This is strange. We (sort of) do something differe
msarett
2015/03/12 22:18:22
Yes we should never reach here. I will defer to y
scroggo
2015/03/13 13:43:12
I think it's fine as is.
| |
295 } | |
296 int maxXOROffset = xorOffset + maxByte; | |
297 ); | |
298 SkASSERT(maxXOROffset < andOffset); | |
scroggo
2015/03/12 21:19:29
Can you include this inside the SkDEBUGCODE/SK_DEB
msarett
2015/03/12 22:18:22
Yes that will make it easier to understand.
| |
299 | |
231 SkAutoLockPixels alp(*bm); | 300 SkAutoLockPixels alp(*bm); |
232 | 301 |
233 for (int y = 0; y < h; y++) | 302 for (int y = 0; y < h; y++) |
234 { | 303 { |
235 for (int x = 0; x < w; x++) | 304 for (int x = 0; x < w; x++) |
236 { | 305 { |
237 //U32* address = bm->getAddr32(x, y); | 306 //U32* address = bm->getAddr32(x, y); |
238 | 307 |
239 //check the alpha bit first, but pass it along to the function to fi gure out how to deal with it | 308 //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; | 309 int andPixelNo = andLineWidth*(h-y-1)+x; |
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
374 static SkImageDecoder_DecodeReg gReg(sk_libico_dfactory); | 443 static SkImageDecoder_DecodeReg gReg(sk_libico_dfactory); |
375 | 444 |
376 static SkImageDecoder::Format get_format_ico(SkStreamRewindable* stream) { | 445 static SkImageDecoder::Format get_format_ico(SkStreamRewindable* stream) { |
377 if (is_ico(stream)) { | 446 if (is_ico(stream)) { |
378 return SkImageDecoder::kICO_Format; | 447 return SkImageDecoder::kICO_Format; |
379 } | 448 } |
380 return SkImageDecoder::kUnknown_Format; | 449 return SkImageDecoder::kUnknown_Format; |
381 } | 450 } |
382 | 451 |
383 static SkImageDecoder_FormatReg gFormatReg(get_format_ico); | 452 static SkImageDecoder_FormatReg gFormatReg(get_format_ico); |
OLD | NEW |