On Saturday 18 April 2009 20:33:36 kurmiashish at freenetproject.org wrote:
> Author: kurmiashish
> Date: 2009-04-18 19:33:36 +0000 (Sat, 18 Apr 2009)
> New Revision: 27016
> 
> Added:
>    trunk/freenet/src/freenet/clients/http/filter/BMPFilter.java
> Log:
> 
> 
> Added: trunk/freenet/src/freenet/clients/http/filter/BMPFilter.java
> ===================================================================
> --- trunk/freenet/src/freenet/clients/http/filter/BMPFilter.java              
>                 
(rev 0)
> +++ trunk/freenet/src/freenet/clients/http/filter/BMPFilter.java      
> 2009-04-18 
19:33:36 UTC (rev 27016)
> @@ -0,0 +1,201 @@
> +/* This code is part of Freenet. It is distributed under the GNU General
> + * Public License, version 2 (or at your option any later version). See
> + * http://www.gnu.org/ for further details of the GPL. */
> +package freenet.clients.http.filter;
> +
> +import java.io.BufferedInputStream;
> +import java.io.DataInputStream;
> +import java.io.IOException;
> +import java.io.InputStream;
> +import java.util.Arrays;
> +import java.util.HashMap;
> +
> +import freenet.l10n.L10n;
> +import freenet.support.HTMLNode;
> +import freenet.support.api.Bucket;
> +import freenet.support.api.BucketFactory;
> +import freenet.support.io.Closer;
> +
> +/**
> + * This class would verify whether the BMP header is valid or not
> + Reference:
> + http://www.fastgraph.com/help/bmp_header_format.html
> + http://en.wikipedia.org/wiki/BMP_file_format
> + */
> +public class BMPFilter implements ContentDataFilter {
> +
> +     
> +     static final byte[] bmpHeaderwindows =
> +             { (byte)'B', (byte)'M'};
> +     
> +             static final byte[] bmpHeaderos2bArray =
> +             { (byte)'B', (byte)'A'};
> +
> +             static final byte[] bmpHeaderos2cIcon =
> +             { (byte)'C', (byte)'I'};
> +
> +
> +             static final byte[] bmpHeaderos2cPointer =
> +             { (byte)'C', (byte)'P'};
> +
> +
> +             static final byte[] bmpHeaderos2Icon =
> +             { (byte)'I', (byte)'C'};
> +
> +
> +             static final byte[] bmpHeaderos2Pointer =
> +             { (byte)'P', (byte)'T'};
> +
> +
> +    private int unsignedByte(byte b)
> +    {
> +        if (b >= 0)
> +            return b;
> +        else
> +            return 256+b;
> +    }

Or bit-wise, (b & 0xFF)
> +
> +
> +  public int readInt(DataInputStream dis) throws IOException
> +  {
> +    int result;
> +    byte[] data = new byte[4];
> +
> +     result = dis.read(data);
> +     if (result < 0) // end of file reached
> +         throw new EOFException();
> +
> +     result = (unsignedByte(data[2]) << 16) | (unsignedByte(data[1]) << 
8) | unsignedByte(data[0]);
> +     result|=(unsignedByte(data[3]) << 24);
> +
> +     return result;
> +  }

Can you just use readFully() and then Fields.bytesToInt()?
See freenet/src/freenet/support/Fields.java. I think this is equivalent, try 
it. Is DataInputStream.readInt() the wrong endianness?
> +
> +
> +     public int readShort(DataInputStream dis) throws IOException
> +    {
> +        int result = dis.read();
> +        if (result < 0)// end of file reached
> +            throw new EOFException();
> +
> +        int r2 = is.read();
> +        if (r2 < 0)// end of file reached
> +            throw new EOFException();
> +
> +        return result | (r2*256);
> +    }

Same here.
> +
> +     
> +     public Bucket readFilter(Bucket data, BucketFactory bf, String charset, 
HashMap<String, String> otherParams,
> +             FilterCallback cb) throws DataFilterException, IOException {
> +             if(data.size() < 54) { // Size of the bmp header is 54
> +                     throwHeaderError(l10n("Too short file"), l10n("The file 
> is too short to 
contain a bmp header"));
> +             }
> +             InputStream is = data.getInputStream();
> +             BufferedInputStream bis = new BufferedInputStream(is);
> +             DataInputStream dis = new DataInputStream(bis);
> +             try {
> +                     
> +             byte[] StartWord = new byte[2];
> +             dis.readFully(StartWord);
> +             if((!Arrays.equals(StartWord, bmpHeaderwindows)) && 
(!Arrays.equals(StartWord, bmpHeaderos2bArray)) && (!Arrays.equals(StartWord, 
bmpHeaderos2cIcon)) && (!Arrays.equals(StartWord, bmpHeaderos2cPointer)) && 
(!Arrays.equals(StartWord, bmpHeaderos2Icon)) && (!Arrays.equals(StartWord, 
bmpHeaderos2Pointer))) {        //Checking the first word
> +                             throwHeaderError(l10n("Invalid start word"), 
> l10n("invalidHeader"));
> +             }
> +                     
> +                     
> +                     
> +             int fileSize = readInt(dis); // read total file size

Can you check this? Compare the total file size to bucket.size()? (Which is a 
long btw). Just as a general sanity check? These are useful to avoid problems 
with stuff being apparently valid as several different MIME types, but also 
because wierd extensions might mean something to browsers or other apps. Is 
it always set? You could only let through that many bytes, but that requires 
copying the data, which we don't want unless it is necessary...

> +             byte[] skipbytes=new byte[4];
> +             dis.readFully(skipbytes);
> +        int headerSize = readInt(dis); // read file header size or pixel 
offset
> +             if(headerSize<0) {
> +                                     throwHeaderError(l10n("Invalid 
> offset"), l10n("Image has invalid pixel 
offset of "+headerSize));
> +             }
> +             
> +
> +
> +             int size_bitmapinfoheader=readInt(dis);
> +             if(size_bitmapinfoheader!=40) {
> +                                     throwHeaderError(l10n("Invalid Bit Map 
> info header size"), l10n("Size 
of bitmap info header is not 40"));
> +             }
> +
> +
> +        int imageWidth = readInt(dis); // read width
> +        int imageHeight = readInt(dis); // read height
> +             if(imageWidth<0 || imageHeight<0) {
> +                                     throwHeaderError(l10n("Invalid 
> Dimensions"), l10n("The image has 
invalid width or height"));
> +             }
> +
> +
> +        
> +             int no_plane=readShort(dis);
> +             if(no_plane!=1) { // No of planes should be 1
> +                                     throwHeaderError(l10n("Invalid no of 
> plannes"), l10n("The image 
has "+no_plane+" planes"));
> +             }
> +                             
> +
> +        int bitDepth = readShort(dis);
> +             
> +             // Bit depth should be 1,2,4,8,16 or 32.
> +             if(bitDepth!=1 && bitDepth!=2 && bitDepth!=4 && bitDepth!=8 && 
bitDepth!=16 && bitDepth!=24 && bitDepth!=32) {
> +                                     throwHeaderError(l10n("Invalid bit 
> depth"), l10n("The bit depth field 
is set to"+bitDepth+". It is not of 1,2,4,8,16, and 32."));
> +             }
> +
> +             int compression_type=readInt(dis);
> +             if( !(compression_type>=0 && compression_type<=3) ) {
> +                                     throwHeaderError(l10n("Invalid 
> Compression type"), l10n("Compression 
type field is set to "+compression_type+" instead of 0-3"));
> +             }
> +                     
> +             int imagedatasize=readInt(dis);
> +             if(fileSize!=headerSize+imagedatasize) {
> +                                     throwHeaderError(l10n("Invalid File 
> size"), l10n("File size is not 
matching to headersize+ imagedatasize"));
> +             }
> +
> +             int horizontal_resolution=readInt(dis);
> +             int vertical_resolution=readInt(dis);
> +
> +             if(horizontal_resolution<0 || vertical_resolution<0) {
> +                             throwHeaderError(l10n("Invalid resolution"), 
> l10n("This image file has 
resolution of "+horizontal_resolution+"x"+vertical_resolution ));
> +             }
> +             if(compression_type==0) {
> +             // Verifying the file size w.r.t. image dimensions(width and 
> height), 
bitDepth with imagedatasize(including padding).
> +                     int 
> bytesperline=(int)Math.ceil((imageWidth*bitDepth)/8);
> +                     int paddingperline=0;
> +                     if(bytesperline%4!=0) {
> +                                             paddingperline=4-bytesperline%4;
> +                     }
> +                     int calculatedsize= 
(int)Math.ceil((imageWidth*imageHeight*bitDepth)/8)+paddingperline*imageHeight;
> +                     if(calculatedsize!=imagedatasize) {
> +                                     throwHeaderError(l10n("Invalid size of 
> image data"), l10n("The 
calculated image data size ("+calculatedsize+") is not matching with the 
actual size ("+imagedatasize+")" ));

You could maybe calculate an upper bound for other compression methods this 
way? The only real remaining issue is you don't check the fileSize afaics. 
Suggest you fix that and wire it in.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 835 bytes
Desc: This is a digitally signed message part.
URL: 
<https://emu.freenetproject.org/pipermail/devl/attachments/20090429/81e3e018/attachment.pgp>

Reply via email to