#FEATURE
authorClaus Gittinger <cg@exept.de>
Fri, 04 Mar 2016 19:28:50 +0100
changeset 3579 94a3b7222275
parent 3578 6bd3a34492f9
child 3580 2bf7c5d62cf6
#FEATURE class: WindowsIconReader changed: #fromWindowsBMPStream:alreadyRead: #loadRLECompressedBMP4From:into: robustness: protect against unreasonable values in header.
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