Chromium Code Reviews| 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 |