private void InitFromStream (Stream stream)
{
ushort entry_count;
CursorEntry ce;
uint largest;
//read the cursor header
if (stream == null || stream.Length == 0)
throw new ArgumentException ("The argument 'stream' must be a picture that can be used as a cursor", "stream");
BinaryReader reader = new BinaryReader (stream);
cursor_dir = new CursorDir ();
cursor_dir.idReserved = reader.ReadUInt16();
cursor_dir.idType = reader.ReadUInt16();
if (cursor_dir.idReserved != 0 || !(cursor_dir.idType == 2 || cursor_dir.idType == 1))
throw new ArgumentException ("Invalid Argument, format error", "stream");
entry_count = reader.ReadUInt16();
cursor_dir.idCount = entry_count;
cursor_dir.idEntries = new CursorEntry[entry_count];
cursor_data = new CursorImage[entry_count];
//now read in the CursorEntry structures
for (int i=0; i < entry_count; i++){
ce = new CursorEntry();
ce.width = reader.ReadByte();
ce.height = reader.ReadByte();
ce.colorCount = reader.ReadByte();
ce.reserved = reader.ReadByte();
ce.xHotspot = reader.ReadUInt16();
ce.yHotspot = reader.ReadUInt16();
if (cursor_dir.idType == 1) {
ce.xHotspot = (ushort)(ce.width / 2);
ce.yHotspot = (ushort)(ce.height / 2);
}
ce.sizeInBytes = reader.ReadUInt32();
ce.fileOffset = reader.ReadUInt32();
cursor_dir.idEntries[i] = ce;
}
// If we have more than one pick the largest cursor
largest = 0;
for (int j = 0; j < entry_count; j++){
if (cursor_dir.idEntries[j].sizeInBytes >= largest) {
largest = cursor_dir.idEntries[j].sizeInBytes;
this.id = (ushort)j;
this.size.Height = cursor_dir.idEntries[j].height;
this.size.Width = cursor_dir.idEntries[j].width;
}
}
//now read in the cursor data
for (int j = 0; j < entry_count; j++) {
CursorImage curdata;
CursorInfoHeader cih;
byte[] buffer;
BinaryReader cih_reader;
int num_colors;
int cursor_height;
int bytes_per_line;
int xor_size;
int and_size;
curdata = new CursorImage();
cih = new CursorInfoHeader();
stream.Seek (cursor_dir.idEntries[j].fileOffset, SeekOrigin.Begin);
buffer = new byte [cursor_dir.idEntries[j].sizeInBytes];
stream.Read (buffer, 0, buffer.Length);
cih_reader = new BinaryReader(new MemoryStream(buffer));
cih.biSize = cih_reader.ReadUInt32 ();
if (cih.biSize != 40) {
throw new ArgumentException ("Invalid cursor file", "stream");
}
cih.biWidth = cih_reader.ReadInt32 ();
cih.biHeight = cih_reader.ReadInt32 ();
cih.biPlanes = cih_reader.ReadUInt16 ();
cih.biBitCount = cih_reader.ReadUInt16 ();
cih.biCompression = cih_reader.ReadUInt32 ();
cih.biSizeImage = cih_reader.ReadUInt32 ();
cih.biXPelsPerMeter = cih_reader.ReadInt32 ();
cih.biYPelsPerMeter = cih_reader.ReadInt32 ();
cih.biClrUsed = cih_reader.ReadUInt32 ();
cih.biClrImportant = cih_reader.ReadUInt32 ();
curdata.cursorHeader = cih;
//Read the number of colors used and corresponding memory occupied by
//color table. Fill this memory chunk into rgbquad[]
switch (cih.biBitCount){
case 1: num_colors = 2; break;
case 4: num_colors = 16; break;
case 8: num_colors = 256; break;
default: num_colors = 0; break;
}
curdata.cursorColors = new uint[num_colors];
for (int i = 0; i < num_colors; i++) {
curdata.cursorColors[i] = cih_reader.ReadUInt32 ();
}
//XOR mask is immediately after ColorTable and its size is
//icon height* no. of bytes per line
//cursor height is half of BITMAPINFOHEADER.biHeight, since it contains
//both XOR as well as AND mask bytes
cursor_height = cih.biHeight/2;
//bytes per line should should be uint aligned
bytes_per_line = ((((cih.biWidth * cih.biPlanes * cih.biBitCount)+ 31)>>5)<<2);
//Determine the XOR array Size
xor_size = bytes_per_line * cursor_height;
curdata.cursorXOR = new byte[xor_size];
for (int i = 0; i < xor_size; i++) {
curdata.cursorXOR[i] = cih_reader.ReadByte();
}
//Determine the AND array size
and_size = (int)(cih_reader.BaseStream.Length - cih_reader.BaseStream.Position);
curdata.cursorAND = new byte[and_size];
for (int i = 0; i < and_size; i++) {
curdata.cursorAND[i] = cih_reader.ReadByte();
}
cursor_data[j] = curdata;
cih_reader.Close();
}
reader.Close();
}