# HG changeset patch # User Claus Gittinger # Date 1457116130 -3600 # Node ID 94a3b7222275b462e0170ae0e70534c9fca6ee4e # Parent 6bd3a34492f9f5d3203fab788c1168fbcaf978ff #FEATURE class: WindowsIconReader changed: #fromWindowsBMPStream:alreadyRead: #loadRLECompressedBMP4From:into: robustness: protect against unreasonable values in header. diff -r 6bd3a34492f9 -r 94a3b7222275 WindowsIconReader.st --- a/WindowsIconReader.st Fri Mar 04 19:12:00 2016 +0100 +++ b/WindowsIconReader.st Fri Mar 04 19:28:50 2016 +0100 @@ -453,7 +453,7 @@ "/ got odd count aByteArray at:dstIndex put:clr1. x := x + 1. - self halt. + "/ self halt. ]. ] ifFalse:[ "/ cnt == 0: escape codes */ @@ -488,7 +488,7 @@ clr1 := aStream nextByte. aByteArray at:dstIndex put:clr1. x := x + 1. - self halt. + "/ self halt. ]. "/ odd count - padd @@ -848,186 +848,195 @@ header := ByteArray uninitializedNew:16r54. bytesAlreadyRead size > 0 ifTrue:[ - header replaceFrom:1 with:bytesAlreadyRead + header replaceFrom:1 with:bytesAlreadyRead ]. aStream nextBytes:(18-bytesAlreadyRead size) into:header startingAt:(1+bytesAlreadyRead size). iSize := header at:(16r0E + 1). (iSize == 40) ifTrue:[ "header-size" - "/ - "/ a Windows3.x BMP file - "/ - "/ 'WinIconReader [info]: Win3.x format' infoPrintCR. + "/ + "/ a Windows3.x BMP file + "/ + "/ 'WinIconReader [info]: Win3.x format' infoPrintCR. - aStream nextBytes:(40-4) into:header startingAt:19. + aStream nextBytes:(40-4) into:header startingAt:19. - width := header wordAt:(16r12 + 1) MSB:false. - height := header wordAt:(16r16 + 1) MSB:false. - inPlanes := header wordAt:(16r1A + 1) MSB:false. - inDepth := header wordAt:(16r1C + 1) MSB:false. - compression := header wordAt:(16r1E + 1) MSB:false. - imgSize := header doubleWordAt:(16r22 + 1) MSB:false. - resH := header doubleWordAt:(16r26 + 1) MSB:false. - resV := header doubleWordAt:(16r2A + 1) MSB:false. - numColor := header doubleWordAt:(16r2E + 1) MSB:false. - numImportantColor := header doubleWordAt:(16r32 + 1) MSB:false. - redMask := header doubleWordAt:(16r36 + 1) MSB:false. - greenMask := header doubleWordAt:(16r3A + 1) MSB:false. - blueMask := header doubleWordAt:(16r3E + 1) MSB:false. - alphaMask := header doubleWordAt:(16r42 + 1) MSB:false. + width := header wordAt:(16r12 + 1) MSB:false. + height := header wordAt:(16r16 + 1) MSB:false. + inPlanes := header wordAt:(16r1A + 1) MSB:false. + inDepth := header wordAt:(16r1C + 1) MSB:false. + compression := header wordAt:(16r1E + 1) MSB:false. + imgSize := header doubleWordAt:(16r22 + 1) MSB:false. + resH := header doubleWordAt:(16r26 + 1) MSB:false. + resV := header doubleWordAt:(16r2A + 1) MSB:false. + numColor := header doubleWordAt:(16r2E + 1) MSB:false. + numImportantColor := header doubleWordAt:(16r32 + 1) MSB:false. + redMask := header doubleWordAt:(16r36 + 1) MSB:false. + greenMask := header doubleWordAt:(16r3A + 1) MSB:false. + blueMask := header doubleWordAt:(16r3E + 1) MSB:false. + alphaMask := header doubleWordAt:(16r42 + 1) MSB:false. - numColor == 0 ifTrue:[ - " - some bmp-writers seem to leave this as zero (which is wrong) - " - inDepth <= 8 ifTrue:[ - numColor := 1 bitShift:inDepth. - "/ 'WinIconReader [warning]: missing nColor in header - assume ' infoPrint. numColor infoPrintCR - ] - ]. + numColor == 0 ifTrue:[ + " + some bmp-writers seem to leave this as zero (which is wrong) + " + inDepth <= 8 ifTrue:[ + numColor := 1 bitShift:inDepth. + "/ 'WinIconReader [warning]: missing nColor in header - assume ' infoPrint. numColor infoPrintCR + ] + ]. - numBytesPerColorInColormap := 4. - dataStart := header wordAt:(16r0A + 1) MSB:false + numBytesPerColorInColormap := 4. + dataStart := header wordAt:(16r0A + 1) MSB:false ] ifFalse:[ - ((iSize == 12) or:[iSize >= 64]) ifTrue:[ - "/ - "/ its an OS/2 BMP file - "/ - "/ 'WinIconReader [info]: OS/2 format' infoPrintCR. - aStream nextBytes:(iSize-4) into:header startingAt:19. + ((iSize == 12) or:[iSize >= 64]) ifTrue:[ + "/ + "/ its an OS/2 BMP file + "/ + "/ 'WinIconReader [info]: OS/2 format' infoPrintCR. + aStream nextBytes:(iSize-4) into:header startingAt:19. - numBytesPerColorInColormap := 3. - dataStart := nil. + numBytesPerColorInColormap := 3. + dataStart := nil. - iSize == 12 ifTrue:[ - width := header wordAt:(16r12 + 1) MSB:false. - height := header wordAt:(16r14 + 1) MSB:false. - inPlanes := header wordAt:(16r16 + 1) MSB:false. - inDepth := header wordAt:(16r18 + 1) MSB:false. - "/ dataStart := header wordAt:(16r0A + 1) MSB:false. - compression := 0. - ]. - iSize >= 64 ifTrue:[ - "/ - "/ its an OS/2 (vsn2) BMP file - "/ - width := header doubleWordAt:(16r12 + 1) MSB:false. - height := header doubleWordAt:(16r16 + 1) MSB:false. - inPlanes := header wordAt:(16r1A + 1) MSB:false. - inDepth := header wordAt:(16r1c + 1) MSB:false. - compression := header doubleWordAt:(16r1e + 1) MSB:false. - numColor := header doubleWordAt:(16r2E + 1) MSB:false. - numImportantColor := header doubleWordAt:(16r32 + 1) MSB:false. - dataStart := header wordAt:(16r0A + 1) MSB:false. - ]. - numColor := 1 bitShift:inDepth. - ] ifFalse:[ - ^ self fileFormatError:'unknown format'. - ]. + iSize == 12 ifTrue:[ + width := header wordAt:(16r12 + 1) MSB:false. + height := header wordAt:(16r14 + 1) MSB:false. + inPlanes := header wordAt:(16r16 + 1) MSB:false. + inDepth := header wordAt:(16r18 + 1) MSB:false. + "/ dataStart := header wordAt:(16r0A + 1) MSB:false. + compression := 0. + ]. + iSize >= 64 ifTrue:[ + "/ + "/ its an OS/2 (vsn2) BMP file + "/ + width := header doubleWordAt:(16r12 + 1) MSB:false. + height := header doubleWordAt:(16r16 + 1) MSB:false. + inPlanes := header wordAt:(16r1A + 1) MSB:false. + inDepth := header wordAt:(16r1c + 1) MSB:false. + compression := header doubleWordAt:(16r1e + 1) MSB:false. + numColor := header doubleWordAt:(16r2E + 1) MSB:false. + numImportantColor := header doubleWordAt:(16r32 + 1) MSB:false. + dataStart := header wordAt:(16r0A + 1) MSB:false. + ]. + numColor := 1 bitShift:inDepth. + ] ifFalse:[ + ^ self fileFormatError:'unknown format'. + ]. ]. - + width > 10000 ifTrue:[ + ^ self fileFormatError:'unreasonable width'. + ]. + height > 10000 ifTrue:[ + ^ self fileFormatError:'unreasonable height'. + ]. + self reportDimension. numColor ~~ 0 ifTrue:[ - "read the colormap - notice: its in BGR order (sigh)" + "read the colormap - notice: its in BGR order (sigh)" - colorMap := self - readColorMap:numColor - numBytesPerColor:numBytesPerColorInColormap - from:aStream. + numColor > (2 raisedTo:inDepth) ifTrue:[ + ^ self fileFormatError:'unreasonable colormap size'. + ]. + colorMap := self + readColorMap:numColor + numBytesPerColor:numBytesPerColorInColormap + from:aStream. - numColor > (1 bitShift:inDepth) ifTrue:[ - 'funny number of colors in image' infoPrintCR. - numColor := 1 bitShift:inDepth. - colorMap := colorMap copyTo:numColor. - ]. + numColor > (1 bitShift:inDepth) ifTrue:[ + 'funny number of colors in image' infoPrintCR. + numColor := 1 bitShift:inDepth. + colorMap := colorMap copyTo:numColor. + ]. ]. "/ check for valid compression compression ~~ 0 ifTrue:[ - "/ some compression - compression == 1 ifTrue:[ - "/ RLE8 - must be depth-8 - inDepth ~~ 8 ifTrue:[ - ^ self fileFormatError:'RLE8 compression only supported with depth8 images'. - ]. - ]. - compression == 2 ifTrue:[ - "/ RLE4 - must be depth-4 - inDepth ~~ 4 ifTrue:[ - ^ self fileFormatError:'RLE4 compression only supported with depth4 images'. - ]. - ]. - compression == 3 ifTrue:[ - "/ BITFIELDS - must be depth-16 or 32 - ((inDepth ~~ 16) and:[inDepth ~~ 32]) ifTrue:[ - ^ self fileFormatError:'BITFIELDS compression only supported with depth16/32 images'. - ]. - ]. - compression >= 4 ifTrue:[ - ^ self fileFormatError:'unsupported compression'. - ]. + "/ some compression + compression == 1 ifTrue:[ + "/ RLE8 - must be depth-8 + inDepth ~~ 8 ifTrue:[ + ^ self fileFormatError:'RLE8 compression only supported with depth8 images'. + ]. + ]. + compression == 2 ifTrue:[ + "/ RLE4 - must be depth-4 + inDepth ~~ 4 ifTrue:[ + ^ self fileFormatError:'RLE4 compression only supported with depth4 images'. + ]. + ]. + compression == 3 ifTrue:[ + "/ BITFIELDS - must be depth-16 or 32 + ((inDepth ~~ 16) and:[inDepth ~~ 32]) ifTrue:[ + ^ self fileFormatError:'BITFIELDS compression only supported with depth16/32 images'. + ]. + ]. + compression >= 4 ifTrue:[ + ^ self fileFormatError:'unsupported compression'. + ]. ]. inPlanes ~~ 1 ifTrue:[ - ^ self fileFormatError:'only 1 plane images supported'. + ^ self fileFormatError:'only 1 plane images supported'. ]. dataStart notNil ifTrue:[ - aStream position:dataStart. + aStream position:dataStart. ]. inDepth <= 8 ifTrue:[ - samplesPerPixel := 1. - bitsPerSample := Array with:inDepth. - photometric := #palette. + samplesPerPixel := 1. + bitsPerSample := Array with:inDepth. + photometric := #palette. ] ifFalse:[ - inDepth == 16 ifTrue:[ - photometric := #palette. - samplesPerPixel := 3. - bitsPerSample := #(5 5 5). - colorMap := FixedPalette - redShift:10 redMask:16r1f - greenShift:5 greenMask:16r1f - blueShift:0 blueMask:16r1F. + inDepth == 16 ifTrue:[ + photometric := #palette. + samplesPerPixel := 3. + bitsPerSample := #(5 5 5). + colorMap := FixedPalette + redShift:10 redMask:16r1f + greenShift:5 greenMask:16r1f + blueShift:0 blueMask:16r1F. - ] ifFalse:[ - inDepth == 24 ifTrue:[ - photometric := #rgb. - samplesPerPixel := 3. - bitsPerSample := #(8 8 8). - ] ifFalse:[ - inDepth == 32 ifTrue:[ - photometric := #rgb. - samplesPerPixel := 4. - bitsPerSample := #(8 8 8 8). - ] ifFalse:[ - ^ self fileFormatError:'unsupported depth'. - ] - ] - ] + ] ifFalse:[ + inDepth == 24 ifTrue:[ + photometric := #rgb. + samplesPerPixel := 3. + bitsPerSample := #(8 8 8). + ] ifFalse:[ + inDepth == 32 ifTrue:[ + photometric := #rgb. + samplesPerPixel := 4. + bitsPerSample := #(8 8 8 8). + ] ifFalse:[ + ^ self fileFormatError:'unsupported depth'. + ] + ] + ] ]. inDepth == 24 ifTrue:[ - bytesPerRow := width * 3 + bytesPerRow := width * 3 ] ifFalse:[ - inDepth == 16 ifTrue:[ - bytesPerRow := width * 2 - ] ifFalse:[ - inDepth == 32 ifTrue:[ - bytesPerRow := width * 4 - ] ifFalse:[ - bytesPerRow := self bytesPerRow - ]. - ]. + inDepth == 16 ifTrue:[ + bytesPerRow := width * 2 + ] ifFalse:[ + inDepth == 32 ifTrue:[ + bytesPerRow := width * 4 + ] ifFalse:[ + bytesPerRow := self bytesPerRow + ]. + ]. ]. data := ByteArray uninitializedNew:(height * bytesPerRow). "/ read & possibly decompress (self loadBMPWidth:width height:height depth:inDepth from:aStream into:data) ifFalse:[ - self fileFormatError:('read/decompression error'). - ^ nil + self fileFormatError:('read/decompression error'). + ^ nil ]. ^ self image