PageRenderTime 107ms CodeModel.GetById 15ms app.highlight 82ms RepoModel.GetById 1ms app.codeStats 1ms

/decoders/image/bmp.d

http://github.com/wilkie/djehuty
D | 1846 lines | 940 code | 385 blank | 521 comment | 264 complexity | 98d58d2825126fe70afc3836bd996343 MD5 | raw file
   1module decoders.image.bmp;
   2
   3import graphics.bitmap;
   4
   5import core.stream;
   6import core.string;
   7import core.definitions;
   8
   9import decoders.image.decoder;
  10import decoders.decoder;
  11
  12
  13// Section: Codecs/Image
  14
  15private {
  16	align(2) struct _djehuty_image_bitmap_file_header {
  17		ushort bfType;
  18		uint bfSize;
  19		ushort bfReserved1;
  20		ushort bfReserved2;
  21		uint bfOffBits;
  22	}
  23
  24	align(2) struct _djehuty_image_bitmap_info_header {
  25		uint  biWidth;
  26		int  biHeight;
  27		ushort biPlanes;
  28		ushort biBitCount;
  29		uint biCompression;
  30		uint biSizeImage;
  31		int  biXPelsPerMeter;
  32		int  biYPelsPerMeter;
  33		uint biClrUsed;
  34		uint biClrImportant;
  35	}
  36
  37	align(2) struct _djehuty_image_os2_1_bitmap_info_header {
  38		ushort  biWidth;
  39		ushort  biHeight;
  40		ushort  biPlanes;
  41		ushort  biBitCount;
  42	}
  43
  44	align(2) struct _djehuty_image_os2_2_bitmap_info_header {
  45		uint  biWidth;
  46		uint  biHeight;
  47		ushort  biPlanes;
  48		ushort  biBitCount;
  49		uint  biCompression;
  50		uint  biSizeImage;
  51		uint  biXPelsPerMeter;
  52		uint  biYPelsPerMeter;
  53		uint  biClrUsed;
  54		uint  biClrImportant;
  55
  56		/* extended os2 2.x stuff */
  57
  58		ushort  usUnits;
  59		ushort  usReserved;
  60		ushort  usRecording;
  61		ushort  usRendering;
  62		uint   cSize1;
  63		uint   cSize2;
  64		uint   ulColorEncoding;
  65		uint   ulIdentifier;
  66	}
  67}
  68
  69// Description: The BMP Codec
  70class BMPDecoder : ImageDecoder {
  71	override string name() {
  72		return "Bitmap";
  73	}
  74
  75	StreamData decode(Stream stream, ref Bitmap view) {
  76		ImageFrameDescription imageDesc;
  77		bool hasMultipleFrames;
  78
  79		uint* ptr;
  80		uint* ptr_max_line;
  81		uint* ptr_max;
  82		ulong ptr_len;
  83
  84
  85		for (;;) {
  86			switch (decoderState) {
  87			case BMP_STATE_INIT:
  88				//initial stuff
  89
  90				hasMultipleFrames = 0;
  91
  92				decoderState = BMP_STATE_READ_HEADERS;
  93
  94			case BMP_STATE_READ_HEADERS:
  95
  96				//reading the header
  97				if (!stream.read(&bf, 14)) { return StreamData.Required; }
  98
  99				// Check for 'BM' signature
 100				if (bf.bfType != 0x4D42) {
 101
 102					// Header is corrupt
 103					return StreamData.Invalid;
 104				}
 105
 106				decoderState = BMP_STATE_READ_BITMAP_SIZE;
 107				continue;
 108
 109			case BMP_STATE_READ_BITMAP_SIZE:
 110				//reading the bitmap size
 111
 112				if (!stream.read(&biSize, 4)) { return StreamData.Required; }
 113
 114				switch (biSize) {
 115				case 0x0C: // osx 1.0
 116					decoderState = BMP_STATE_READ_OSX_1;
 117					continue;
 118				case 0xF0: // osx 2.0
 119					decoderState = BMP_STATE_READ_OSX_2;
 120					continue;
 121				case 0x28: // windows
 122					decoderState = BMP_STATE_READ_WIN;
 123					continue;
 124				default:
 125					// Bitmap Version not supported
 126					return StreamData.Invalid;
 127				}
 128
 129			case BMP_STATE_READ_OSX_1:
 130				return StreamData.Complete;
 131
 132			case BMP_STATE_READ_OSX_2:
 133				return StreamData.Complete;
 134
 135	// WINDOWS BITMAP DECODING //
 136
 137			case BMP_STATE_READ_WIN:
 138
 139				//get the bitmap info header
 140				if (!stream.read(&bi, 36)) { return StreamData.Required; }
 141
 142				//get the windows color table
 143
 144				switch(bi.biBitCount) {
 145				case 1:
 146					decoderState = BMP_STATE_READ_WIN_PALETTE;
 147					decoderNextState = BMP_STATE_DECODE_WIN_1BPP;
 148					paletteNumColors = 2;
 149					break;
 150				case 2:
 151					decoderState = BMP_STATE_READ_WIN_PALETTE;
 152					decoderNextState = BMP_STATE_DECODE_WIN_2BPP;
 153					paletteNumColors = 4;
 154					break;
 155				case 4:
 156					decoderState = BMP_STATE_READ_WIN_PALETTE;
 157					decoderNextState = BMP_STATE_DECODE_WIN_4BPP;
 158					paletteNumColors = 16;
 159					break;
 160				case 8:
 161					decoderState = BMP_STATE_READ_WIN_PALETTE;
 162					decoderNextState = BMP_STATE_DECODE_WIN_8BPP;
 163					paletteNumColors = 256;
 164					break;
 165				case 16:
 166					decoderState = BMP_STATE_DECODE_WIN_16BPP;
 167					paletteNumColors = 0;
 168					break;
 169				case 24:
 170					decoderState = BMP_STATE_DECODE_WIN_24BPP;
 171					paletteNumColors = 0;
 172					break;
 173				case 32:
 174					decoderState = BMP_STATE_DECODE_WIN_32BPP;
 175					paletteNumColors = 0;
 176					break;
 177				default:
 178
 179					// invalid format
 180
 181					return StreamData.Invalid;
 182
 183				}
 184
 185				continue;
 186
 187
 188
 189
 190
 191
 192
 193
 194			case BMP_STATE_READ_WIN_PALETTE:
 195
 196				// get the amount we need
 197
 198				//read from the file the palette information
 199				if (bi.biClrUsed == 0) {
 200					bi.biClrUsed = paletteNumColors;
 201				}
 202
 203				//read from the file the palette information
 204				if(!stream.read(&palette, (bi.biClrUsed * 4))) { return StreamData.Required; }
 205
 206				for (uint i=0; i<paletteNumColors; i++) {
 207					palette[i] |= 0xFF000000;
 208				}
 209
 210				decoderState = decoderNextState;
 211
 212
 213				continue;
 214
 215
 216
 217
 218
 219
 220	// WINDOWS 1BPP BITMAPS //
 221
 222
 223			case BMP_STATE_DECODE_WIN_1BPP:
 224				//////OutputDebugStringA("bmp - windows - 1 bpp - 2 colors\n");
 225
 226				//skip further padding, skip to image data, according to header
 227				if (bf.bfOffBits - (54 + (bi.biClrUsed * 4)) > 0) {
 228					if(!stream.skip(bf.bfOffBits - (54 + (bi.biClrUsed * 4)) ) ) { return StreamData.Required; }
 229				}
 230
 231				//Calculate the bytes each row will take
 232				//within the file's bitmap data
 233				bytesPerRow = cast(uint)((cast(float)bi.biWidth / 8) + 0.5);
 234				bytesForPadding = 0;
 235				if (bytesPerRow & 0x3) {
 236					//pad bytes per row
 237					bytesForPadding = (4 - (bytesPerRow & 0x3));
 238					bytesPerRow += bytesForPadding;
 239				}
 240
 241				if (bi.biCompression == 0) { // rgb
 242					//calculate the getLength of the bitmap data
 243					bitmapDataLen = bytesPerRow * bi.biHeight;
 244				}
 245				else {
 246					////OutputDebugStringA("bmp - invalid compression format\n");
 247					return StreamData.Invalid;
 248				}
 249
 250				//create the bitmap's buffer
 251				view.create(bi.biWidth, bi.biHeight);
 252
 253				ptrLine = 0;
 254				ptrPos = 0;
 255				fileDataToSkip = 0;
 256
 257				decoderState = BMP_STATE_RENDER_WIN_1BPP;
 258
 259
 260			case BMP_STATE_RENDER_WIN_1BPP:
 261				//////OutputDebugStringA("bmp - rendering stream input - 1bpp\n");
 262
 263				// TAKE ALL BYTES FROM STREAM
 264				// IF WE FINISH, WE CAN return StreamData.Complete
 265
 266				view.lockBuffer(cast(void**)&ptr_max, ptr_len);
 267
 268				ptr = ptr_max + (ptr_len / 4);
 269
 270				ptr -= (bi.biWidth * (ptrLine + 1));
 271				ptr_max_line = ptr + bi.biWidth;
 272
 273				ptr_max += bi.biWidth;
 274
 275				ptr += ptrPos;
 276
 277				// LOAD FILEDATA WITH PART OF THE STREAM
 278				// CHUNKS AT A TIME
 279				for (;;) {
 280					if (stream.remaining == 0) {
 281						view.unlockBuffer();
 282						return StreamData.Required;
 283					}
 284
 285					fileData = new ubyte[cast(uint)stream.remaining];
 286					fileDataCurPtr = fileDataPtr = fileData.ptr;
 287					fileDataEndPtr = fileDataCurPtr + stream.readAny(fileData.ptr, cast(uint)stream.remaining);
 288
 289					if (fileDataCurPtr + fileDataToSkip >= fileDataEndPtr) {
 290						//////OutputDebugStringA("bmp - rendering error - not enough information\n");
 291						//////OutputDebugStringA("bmp - skipping data across page\n");
 292						fileDataToSkip -= (fileDataEndPtr - fileDataCurPtr);
 293						view.unlockBuffer();
 294						delete fileData;
 295						return StreamData.Complete;
 296					}
 297					else if (fileDataToSkip > 0) {
 298						fileDataCurPtr += fileDataToSkip;
 299						fileDataToSkip = 0;
 300					}
 301
 302					// we start from the bottom of the bitmap and work our way up
 303					// ptr_max == ORIGINAL POINTER GIVEN BY LOCK BUFFER
 304					// ptr == WORKS ITS WAY FROM END OF BITMAP TO FRONT
 305
 306					// GO THROUGH AND RENDER TO THE BITMAP
 307					// AS MUCH AS POSSIBLE
 308					for (;fileDataCurPtr < fileDataEndPtr;) {
 309						for (;;) {
 310							// FIRST PIXEL
 311							ptr[0] = palette[fileDataCurPtr[0] >> 7];
 312
 313							ptr++;
 314							ptrPos++;
 315
 316							if (ptr == ptr_max_line) { break; }
 317
 318							// SECOND PIXEL
 319							ptr[0] = palette[(fileDataCurPtr[0] >> 6) & 0x1];
 320
 321							ptr++;
 322							ptrPos++;
 323
 324							if (ptr == ptr_max_line) { break; }
 325
 326							// THIRD PIXEL
 327							ptr[0] = palette[(fileDataCurPtr[0] >> 5) & 0x1];
 328
 329							ptr++;
 330							ptrPos++;
 331
 332							if (ptr == ptr_max_line) { break; }
 333
 334							// FOURTH PIXEL
 335							ptr[0] = palette[(fileDataCurPtr[0] >> 4) & 0x1];
 336
 337							ptr++;
 338							ptrPos++;
 339
 340							if (ptr == ptr_max_line) { break; }
 341
 342							// FIFTH PIXEL
 343							ptr[0] = palette[(fileDataCurPtr[0] >> 3) & 0x1];
 344
 345							ptr++;
 346							ptrPos++;
 347
 348							if (ptr == ptr_max_line) { break; }
 349
 350							// SIXTH PIXEL
 351							ptr[0] = palette[(fileDataCurPtr[0] >> 2) & 0x1];
 352
 353							ptr++;
 354							ptrPos++;
 355
 356							if (ptr == ptr_max_line) { break; }
 357
 358							// SEVENTH PIXEL
 359							ptr[0] = palette[(fileDataCurPtr[0] >> 1) & 0x1];
 360
 361							ptr++;
 362							ptrPos++;
 363
 364							if (ptr == ptr_max_line) { break; }
 365
 366							// EIGHTH PIXEL
 367							ptr[0] = palette[fileDataCurPtr[0] & 0x1];
 368
 369							ptr++;
 370							ptrPos++;
 371
 372							if (ptr == ptr_max_line) { break; }
 373
 374							// MOVE BUFFER POINTER
 375
 376							fileDataCurPtr++;
 377
 378							if (fileDataCurPtr == fileDataEndPtr) {
 379								break;
 380							}
 381						}
 382
 383						if (ptr == ptr_max_line) {
 384							if (ptr == ptr_max) {
 385								view.unlockBuffer();
 386								delete fileData;
 387								return StreamData.Complete;
 388							}
 389
 390							ptrLine++;
 391							ptrPos = 0;
 392
 393							ptr -= (bi.biWidth * 2);
 394							ptr_max_line -= (bi.biWidth);
 395
 396							fileDataCurPtr++;
 397
 398							fileDataToSkip = bytesForPadding;
 399
 400							if (fileDataCurPtr == fileDataEndPtr) {
 401								break;
 402							}
 403
 404							if (fileDataCurPtr + fileDataToSkip >= fileDataEndPtr) {
 405								fileDataToSkip -= (fileDataEndPtr - fileDataCurPtr);
 406								break;
 407							}
 408							else {
 409								fileDataCurPtr += fileDataToSkip;
 410								fileDataToSkip = 0;
 411							}
 412						}
 413
 414						if (fileDataCurPtr == fileDataEndPtr) {
 415							break;
 416						}
 417
 418					}
 419				}
 420
 421	// WINDOWS 2BPP BITMAPS //
 422
 423			case BMP_STATE_DECODE_WIN_2BPP:
 424				////OutputDebugStringA("bmp - windows - 2 bpp - 4 colors\n");
 425
 426				//skip further padding, skip to image data, according to header
 427				if (bf.bfOffBits - (54 + (bi.biClrUsed * 4)) > 0) {
 428					if(!stream.skip(bf.bfOffBits - (54 + (bi.biClrUsed * 4)) ) ) { return StreamData.Required; }
 429				}
 430
 431				//Calculate the bytes each row will take
 432				//within the file's bitmap data
 433				bytesPerRow = cast(uint)((cast(float)bi.biWidth / 4) + 0.5);
 434				bytesForPadding = 0;
 435				if (bytesPerRow & 0x3) {
 436					//pad bytes per row
 437					bytesForPadding = (4 - (bytesPerRow & 0x3));
 438					bytesPerRow += bytesForPadding;
 439				}
 440
 441				if (bi.biCompression == 0) { // rgb
 442					//calculate the getLength of the bitmap data
 443					bitmapDataLen = bytesPerRow * bi.biHeight;
 444				}
 445				else {
 446					////OutputDebugStringA("bmp - invalid compression format\n");
 447					return StreamData.Invalid;
 448				}
 449
 450				//create the bitmap's buffer
 451				view.create(bi.biWidth, bi.biHeight);
 452
 453				ptrLine = 0;
 454				ptrPos = 0;
 455				fileDataToSkip = 0;
 456
 457				decoderState = BMP_STATE_RENDER_WIN_2BPP;
 458
 459			case BMP_STATE_RENDER_WIN_2BPP:
 460				////OutputDebugStringA("bmp - rendering stream input - 2bpp\n");
 461
 462				// TAKE ALL BYTES FROM STREAM
 463				// IF WE FINISH, WE CAN return StreamData.Complete
 464
 465				view.lockBuffer(cast(void**)&ptr_max, ptr_len);
 466
 467				ptr = ptr_max + (ptr_len / 4);
 468
 469				ptr -= (bi.biWidth * (ptrLine + 1));
 470				ptr_max_line = ptr + bi.biWidth;
 471
 472				ptr_max += bi.biWidth;
 473
 474				ptr += ptrPos;
 475
 476				// LOAD FILEDATA WITH PART OF THE STREAM
 477				// CHUNKS AT A TIME
 478				for (;;) {
 479					if (stream.remaining() == 0) {
 480						view.unlockBuffer();
 481						return StreamData.Required;
 482					}
 483
 484					fileData = new ubyte[cast(uint)stream.remaining];
 485					fileDataCurPtr = fileDataPtr = fileData.ptr;
 486					fileDataEndPtr = fileDataCurPtr + stream.readAny(fileData.ptr, cast(uint)stream.remaining);
 487
 488					if (fileDataCurPtr + fileDataToSkip >= fileDataEndPtr) {
 489						//////OutputDebugStringA("bmp - rendering error - not enough information\n");
 490						//////OutputDebugStringA("bmp - skipping data across page\n");
 491						fileDataToSkip -= (fileDataEndPtr - fileDataCurPtr);
 492						view.unlockBuffer();
 493						delete fileData;
 494						return StreamData.Complete;
 495					}
 496					else if (fileDataToSkip > 0) {
 497						fileDataCurPtr += fileDataToSkip;
 498						fileDataToSkip = 0;
 499					}
 500
 501					// we start from the bottom of the bitmap and work our way up
 502					// ptr_max == ORIGINAL POINTER GIVEN BY LOCK BUFFER
 503					// ptr == WORKS ITS WAY FROM END OF BITMAP TO FRONT
 504
 505					// GO THROUGH AND RENDER TO THE BITMAP
 506					// AS MUCH AS POSSIBLE
 507					for (;fileDataCurPtr < fileDataEndPtr;) {
 508						for (;;) {
 509							// FIRST PIXEL
 510							ptr[0] = palette[fileDataCurPtr[0] >> 6];
 511
 512							ptr++;
 513							ptrPos++;
 514
 515							if (ptr == ptr_max_line) { break; }
 516
 517							// SECOND PIXEL
 518							ptr[0] = palette[(fileDataCurPtr[0] >> 4) & 0x7];
 519
 520							ptr++;
 521							ptrPos++;
 522
 523							if (ptr == ptr_max_line) { break; }
 524
 525							// THIRD PIXEL
 526							ptr[0] = palette[(fileDataCurPtr[0] >> 2) & 0x7];
 527
 528							ptr++;
 529							ptrPos++;
 530
 531							if (ptr == ptr_max_line) { break; }
 532
 533							// FOURTH PIXEL
 534							ptr[0] = palette[fileDataCurPtr[0] & 0x7];
 535
 536							ptr++;
 537							ptrPos++;
 538
 539							if (ptr == ptr_max_line) { break; }
 540
 541							// MOVE BUFFER POINTER
 542
 543							fileDataCurPtr++;
 544
 545							if (fileDataCurPtr == fileDataEndPtr) {
 546								break;
 547							}
 548						}
 549
 550						if (ptr == ptr_max_line) {
 551							//////OutputDebugStringA("bmp - rendered line\n");
 552							if (ptr == ptr_max) {
 553								//////OutputDebugStringA("bmp - rendering complete\n");
 554								view.unlockBuffer();
 555								delete fileData;
 556								return StreamData.Complete;
 557							}
 558
 559							ptrLine++;
 560							ptrPos = 0;
 561
 562							ptr -= (bi.biWidth * 2);
 563							ptr_max_line -= (bi.biWidth);
 564
 565							fileDataCurPtr++;
 566
 567							fileDataToSkip = bytesForPadding;
 568
 569							if (fileDataCurPtr == fileDataEndPtr) {
 570								break;
 571							}
 572
 573							//////OutputDebugString(String(fileDataToSkip) + S("\n"));
 574
 575							if (fileDataCurPtr + fileDataToSkip >= fileDataEndPtr) {
 576								fileDataToSkip -= (fileDataEndPtr - fileDataCurPtr);
 577								break;
 578							}
 579							else {
 580								fileDataCurPtr += fileDataToSkip;
 581								fileDataToSkip = 0;
 582							}
 583						}
 584
 585						if (fileDataCurPtr == fileDataEndPtr) {
 586							break;
 587						}
 588					}
 589				}
 590
 591	// WINDOWS 4BPP BITMAPS, RGB AND RLE COMPRESSED //
 592
 593			case BMP_STATE_DECODE_WIN_4BPP:
 594				////OutputDebugStringA("bmp - windows - 4 bpp - 16 colors\n");
 595
 596				//skip further padding, skip to image data, according to header
 597				if (bf.bfOffBits - (54 + (bi.biClrUsed * 4)) > 0) {
 598					if(!stream.skip(bf.bfOffBits - (54 + (bi.biClrUsed * 4)) ) ) { return StreamData.Required; }
 599				}
 600
 601				//Calculate the bytes each row will take
 602				//within the file's bitmap data
 603				bytesPerRow = cast(uint)((cast(float)bi.biWidth / 2) + 0.5);
 604				bytesForPadding = 0;
 605				if (bytesPerRow & 0x3) {
 606					//pad bytes per row
 607					bytesForPadding = (4 - (bytesPerRow & 0x3));
 608					bytesPerRow += bytesForPadding;
 609				}
 610
 611				if (bi.biCompression == 2) { // rle-4
 612					//calculate the getLength of the bitmap data
 613					bitmapDataLen = bi.biSizeImage;
 614
 615					decoderSubState = 0;
 616				}
 617				else if (bi.biCompression == 0) { // rgb
 618					//calculate the getLength of the bitmap data
 619					bitmapDataLen = bytesPerRow * bi.biHeight;
 620				}
 621				else {
 622					////OutputDebugStringA("bmp - invalid compression format\n");
 623				}
 624
 625				//create the bitmap's buffer
 626				view.create(bi.biWidth, bi.biHeight);
 627
 628				ptrLine = 0;
 629				ptrPos = 0;
 630				fileDataToSkip = 0;
 631
 632				decoderState = BMP_STATE_RENDER_WIN_4BPP;
 633
 634			case BMP_STATE_RENDER_WIN_4BPP:
 635				//////OutputDebugStringA("bmp - rendering stream input - 4bpp\n");
 636
 637				// TAKE ALL BYTES FROM STREAM
 638				// IF WE FINISH, WE CAN return StreamData.Complete
 639
 640				view.lockBuffer(cast(void**)&ptr_max, ptr_len);
 641
 642				ptr = ptr_max + (ptr_len / 4);
 643
 644				ptr -= (bi.biWidth * (ptrLine + 1));
 645				ptr_max_line = ptr + bi.biWidth;
 646
 647				ptr_max += bi.biWidth;
 648
 649				ptr += ptrPos;
 650
 651				// LOAD FILEDATA WITH PART OF THE STREAM
 652				// CHUNKS AT A TIME
 653				for (;;) {
 654					if (stream.remaining == 0) {
 655						view.unlockBuffer();
 656						return StreamData.Required;
 657					}
 658
 659					fileData = new ubyte[cast(uint)stream.remaining];
 660					fileDataCurPtr = fileDataPtr = fileData.ptr;
 661					fileDataEndPtr = fileDataCurPtr + stream.readAny(fileData.ptr, cast(uint)stream.remaining);
 662
 663					if (fileDataCurPtr + fileDataToSkip >= fileDataEndPtr) {
 664						//////OutputDebugStringA("bmp - rendering error - not enough information\n");
 665						//////OutputDebugStringA("bmp - skipping data across page\n");
 666						fileDataToSkip -= (fileDataEndPtr - fileDataCurPtr);
 667						view.unlockBuffer();
 668						delete fileData;
 669						return StreamData.Complete;
 670					}
 671					else if (fileDataToSkip > 0) {
 672						fileDataCurPtr += fileDataToSkip;
 673						fileDataToSkip = 0;
 674					}
 675
 676					// we start from the bottom of the bitmap and work our way up
 677					// ptr_max == ORIGINAL POINTER GIVEN BY LOCK BUFFER
 678					// ptr == WORKS ITS WAY FROM END OF BITMAP TO FRONT
 679
 680					if (bi.biCompression == 0) {
 681						// GO THROUGH AND RENDER TO THE BITMAP
 682						// AS MUCH AS POSSIBLE
 683						for (;fileDataCurPtr < fileDataEndPtr;) {
 684							for (;;) {
 685								// FIRST PIXEL
 686								ptr[0] = palette[fileDataCurPtr[0] >> 4];
 687
 688								ptr++;
 689								ptrPos++;
 690
 691								if (ptr == ptr_max_line) { break; }
 692
 693								// SECOND PIXEL
 694								ptr[0] = palette[fileDataCurPtr[0] & 0xF];
 695
 696								ptr++;
 697								ptrPos++;
 698
 699								if (ptr == ptr_max_line) { break; }
 700
 701								// MOVE BUFFER POINTER
 702
 703								fileDataCurPtr++;
 704
 705								if (fileDataCurPtr == fileDataEndPtr) {
 706									break;
 707								}
 708							}
 709
 710							if (ptr == ptr_max_line) {
 711								//////OutputDebugStringA("bmp - rendered line\n");
 712								if (ptr == ptr_max) {
 713									//////OutputDebugStringA("bmp - rendering complete\n");
 714									view.unlockBuffer();
 715									delete fileData;
 716									return StreamData.Complete;
 717								}
 718
 719								ptrLine++;
 720								ptrPos = 0;
 721
 722								ptr -= (bi.biWidth * 2);
 723								ptr_max_line -= (bi.biWidth);
 724
 725								fileDataCurPtr++;
 726
 727								fileDataToSkip = bytesForPadding;
 728
 729								if (fileDataCurPtr == fileDataEndPtr) {
 730									break;
 731								}
 732
 733								//////OutputDebugString(String(fileDataToSkip) + S("\n"));
 734
 735								if (fileDataCurPtr + fileDataToSkip >= fileDataEndPtr) {
 736									fileDataToSkip -= (fileDataEndPtr - fileDataCurPtr);
 737									break;
 738								}
 739								else {
 740									fileDataCurPtr += fileDataToSkip;
 741									fileDataToSkip = 0;
 742								}
 743							}
 744
 745							if (fileDataCurPtr == fileDataEndPtr) {
 746								break;
 747							}
 748
 749						}
 750
 751					}
 752					else // rle - 4
 753					{
 754						//calculate pointers
 755
 756						// LOOP
 757						// {
 758						//    STATE 0:
 759						//        GET FIRST CODE
 760						//    STATE 1: RLE NORMAL
 761						//        GET CODE
 762						//        RENDER
 763						//    STATE 2: ESCAPE
 764						//        GET CODE
 765						//          FILL IN LINE  (EOL)
 766						//          FILL IN IMAGE (EOB)
 767						//          SWITCH TO DELTA
 768						//          SWITCH TO ABSOLUTE
 769						//    STATE 3: DELTA
 770						//        GET CODES
 771						//        REPOSITION
 772						//    STATE 4: ABSOLUTE
 773						//        RENDER
 774						// }
 775
 776					}
 777				}
 778
 779				//view.unlockBuffer();
 780
 781				//if (bi.biCompression == 0)
 782				//{
 783					//Bitmaps store data from bottom to top...
 784					//The bitmap buffer, however, stores from
 785					//top to bottom...take that into
 786					//consideration when Reading this code
 787					//for (; ((ptr + bi.biWidth) <= ptrmax); )
 788					//{
 789					//	for (;;)
 790					//	{
 791					//		if (i >= width) { break; }
 792					//		ptr[i] = palette[fileDataCurPtr[a] >> 4];
 793					//		i++;
 794					//		if (i >= width) { break; }
 795					//		ptr[i] = palette[fileDataCurPtr[a] & 0xF];
 796					//		i++;
 797					//		a++;
 798					//	}
 799
 800						//progress a line
 801					//	ptr += width;
 802
 803						//digress a line
 804					//	fileDataEndPtr -= bytesPerRow;
 805					//	fileDataCurPtr = fileDataEndPtr;
 806					//}
 807				//}
 808
 809				//find expected minimum file size - bitmapDataLen + headers + color tables
 810				//fileSize = bitmapDataLen;
 811
 812				//if (stream.getLength() < fileSize)
 813				//{
 814					//do not continue
 815				//	////OutputDebugStringA("bmp - unexpected size\n");
 816					//return StreamData.Invalid;
 817				//}
 818
 819				//if there is a corrupt header, do not continue
 820				//if (bf.bfOffBits <= 54)
 821				//{
 822				//	////OutputDebugStringA("bmp - corrupt header\n");
 823				//	return StreamData.Invalid;
 824				//}
 825
 826				//skip further padding
 827				//if (stream.getLength() - (bitmapDataLen + 54 + (bi.biClrUsed * 4)) > 0)
 828				//{
 829				//	stream.skip(stream.getLength() - (bitmapDataLen + 54 + (bi.biClrUsed * 4)));
 830				//}
 831
 832				//allocate the bitmap data
 833				//fileDataPtr = new UInt8[bitmapDataLen];
 834
 835				//read from the file the bitmap data
 836				//stream.read(fileDataPtr, bitmapDataLen);
 837
 838				//calculate pointers
 839				/*fileDataEndPtr = fileDataPtr + bitmapDataLen - bytesPerRow;
 840				fileDataCurPtr = fileDataEndPtr;
 841
 842				//retrieve a pointer to a bitmap buffer
 843				view.lockBuffer((void**)&ptr, ptrlen);
 844
 845				//calculate the buffer's bound
 846				ptrmax = (ptr + (ptrlen/4));
 847
 848				//This loop will paint to the buffer
 849				//using information from the file
 850
 851				if (bi.biCompression == 2) //BI_RLE4
 852				{
 853					//calculate pointers
 854					fileDataEndPtr = fileDataPtr + bitmapDataLen;
 855					fileDataCurPtr = fileDataPtr;
 856
 857					ptrmax -= width;
 858					UInt32* ptr_cur = ptrmax;
 859					for (; ptr_cur >= ptr; )
 860					{
 861						UInt8 lenByte;
 862						//goes through a row
 863						for (i=0; i < width; )
 864						{
 865							//get getLength byte
 866							lenByte = fileDataCurPtr[0];
 867
 868							fileDataCurPtr++;
 869							if (fileDataCurPtr == fileDataEndPtr) { break; }
 870
 871							if (lenByte == 0)
 872							{
 873								//escape sequence or absolute mode
 874
 875								lenByte = fileDataCurPtr[0];
 876
 877								fileDataCurPtr++;
 878								if (fileDataCurPtr == fileDataEndPtr) { break; }
 879
 880								if (lenByte < 3)
 881								{
 882									//encoded mode
 883									if (lenByte == 0)
 884									{
 885										//end of line
 886										//paint black pixels
 887										//to the rest of the line and continue
 888										if (i!=0)
 889										{
 890											for ( ; i < width; i++)
 891											{
 892												ptr_cur[i] = 0;
 893											}
 894											break;
 895										}
 896									}
 897									else if (lenByte == 1)
 898									{
 899										//end of bitmap
 900										//paint black pixels
 901										//to the rest of the bitmap and exit
 902										for (; ptr_cur >= ptr; )
 903										{
 904											for ( ; i < width; i++)
 905											{
 906												ptr_cur[i] = 0;
 907											}
 908
 909											//digress a line
 910											ptrmax-=width;
 911											ptr_cur=ptrmax;
 912
 913											i = 0;
 914										}
 915										break;
 916									}
 917									else
 918									{
 919										//delta
 920										//next two bytes are horiz and vert offsets to new pixel
 921
 922										lenByte = fileDataCurPtr[0];
 923
 924										fileDataCurPtr++;
 925										if (fileDataCurPtr == fileDataEndPtr) { break; }
 926
 927										a = fileDataCurPtr[0];
 928
 929										fileDataCurPtr++;
 930										if (fileDataCurPtr == fileDataEndPtr) { break; }
 931
 932										//lenByte is the horizontal offset
 933										//a is the vertical offset
 934
 935										//for vertical offsets, we decrease or increase
 936										//the ptr_cur;
 937										ptr_cur += (width * (UInt8)(a));
 938										ptr_cur += (lenByte);
 939									}
 940								}
 941								else
 942								{
 943									//absolute mode
 944									//lenByte is the number of colors that follow is normal format
 945									//this must be padded to multiple of four
 946
 947									a = lenByte;
 948
 949									//decode
 950									for ( ; ; )
 951									{
 952										ptr_cur[i] = palette[fileDataCurPtr[0] >> 4];
 953
 954										i++;
 955										if (i>=width) { break; }
 956
 957										a--;
 958										if (a <= 0) { break; }
 959
 960										ptr_cur[i] = palette[fileDataCurPtr[0] & 0xF];
 961
 962										i++;
 963										if (i>=width) { break; }
 964
 965										a--;
 966										if (a <= 0) { break; }
 967
 968										fileDataCurPtr++;
 969										if (fileDataCurPtr >= fileDataEndPtr) { break; }
 970									}
 971
 972									fileDataCurPtr++;
 973									if (fileDataCurPtr >= fileDataEndPtr) { break; }
 974
 975									//realign to a word boundary
 976									if ((lenByte/2) & 0x01)
 977									{
 978										fileDataCurPtr++ ;
 979										if (fileDataCurPtr >= fileDataEndPtr) { break; }
 980									}
 981								}
 982							}
 983							else
 984							{
 985								//run the getLength of lenByte, and paint the pixel
 986								//of the index that many times onto the buffer
 987								for ( ; ; )
 988								{
 989									ptr_cur[i] = palette[fileDataCurPtr[0] >> 4];
 990
 991									i++;
 992									if (i>=width) { break; }
 993
 994									lenByte--;
 995									if (lenByte <= 0) { break; }
 996
 997									ptr_cur[i] = palette[fileDataCurPtr[0] & 0xF];
 998
 999									i++;
1000									if (i>=width) { break; }
1001
1002									lenByte--;
1003									if (lenByte <= 0) { break; }
1004								}
1005
1006								fileDataCurPtr++;
1007								if (fileDataCurPtr >= fileDataEndPtr) { break; }
1008							}
1009						}
1010
1011						//digress a line
1012						ptrmax-=width;
1013						ptr_cur=ptrmax;
1014					}
1015				}
1016				else
1017				{
1018					//Bitmaps store data from bottom to top...
1019					//The bitmap buffer, however, stores from
1020					//top to bottom...take that into
1021					//consideration when Reading this code
1022					for (; ((ptr + width) <= ptrmax); )
1023					{
1024						//goes through a row
1025						i = 0;
1026						a = 0;
1027
1028						for (;;)
1029						{
1030							if (i >= width) { break; }
1031							ptr[i] = palette[fileDataCurPtr[a] >> 4];
1032							i++;
1033							if (i >= width) { break; }
1034							ptr[i] = palette[fileDataCurPtr[a] & 0xF];
1035							i++;
1036
1037							a++;
1038						}
1039
1040						//progress a line
1041						ptr += width;
1042
1043						//digress a line
1044						fileDataEndPtr -= bytesPerRow;
1045						fileDataCurPtr = fileDataEndPtr;
1046					}
1047				}
1048
1049				//unlock the buffer, so the view can refresh
1050				view.unlockBuffer();
1051
1052				*/
1053
1054//				return StreamData.Complete;
1055
1056	// WINDOWS 8BPP BITMAPS, RGB AND RLE COMPRESSED //
1057
1058			case BMP_STATE_DECODE_WIN_8BPP:
1059				////OutputDebugStringA("bmp - windows - 8 bpp - 256 colors\n");
1060
1061				//skip further padding, skip to image data, according to header
1062				if (bf.bfOffBits - (54 + (bi.biClrUsed * 4)) > 0) {
1063					if(!stream.skip(bf.bfOffBits - (54 + (bi.biClrUsed * 4)) ) ) { return StreamData.Required; }
1064				}
1065
1066				//Calculate the bytes each row will take
1067				//within the file's bitmap data
1068				bytesPerRow = bi.biWidth;
1069				if (bytesPerRow & 0x3) {
1070					//pad bytes per row
1071					bytesPerRow += (4 - (bytesPerRow & 0x3));
1072				}
1073
1074				if (bi.biCompression == 1) { // rle-8
1075					//calculate the getLength of the bitmap data
1076					bitmapDataLen = bi.biSizeImage;
1077
1078					decoderSubState = 0;
1079				}
1080				else if (bi.biCompression == 0) { // rgb
1081					//calculate the getLength of the bitmap data
1082					bitmapDataLen = bytesPerRow * bi.biHeight;
1083				}
1084				else {
1085					////OutputDebugStringA("bmp - invalid compression format\n");
1086				}
1087
1088				//create the bitmap's buffer
1089				view.create(bi.biWidth, bi.biHeight);
1090
1091				ptrLine = 0;
1092				ptrPos = 0;
1093				fileDataToSkip = 0;
1094
1095				decoderState = BMP_STATE_RENDER_WIN_8BPP;
1096
1097			case BMP_STATE_RENDER_WIN_8BPP:
1098
1099				//////OutputDebugStringA("bmp - rendering stream input - 8bpp\n");
1100
1101				// TAKE ALL BYTES FROM STREAM
1102				// IF WE FINISH, WE CAN return StreamData.Complete
1103
1104				// GET THE BITMAP DATA AND GO TO THE NEXT POSITION
1105				// TO RENDER TO
1106				view.lockBuffer(cast(void**)&ptr_max, ptr_len);
1107
1108				ptr = ptr_max + (ptr_len / 4);
1109
1110				ptr -= (bi.biWidth * (ptrLine + 1));
1111				ptr_max_line = ptr + bi.biWidth;
1112
1113				ptr_max += bi.biWidth;
1114
1115				ptr += ptrPos;
1116
1117				// LOAD FILEDATA WITH PART OF THE STREAM
1118				// CHUNKS AT A TIME
1119				for (;;) {
1120					if (stream.remaining == 0) {
1121						view.unlockBuffer();
1122						return StreamData.Required;
1123					}
1124
1125					fileData = new ubyte[cast(uint)stream.remaining];
1126					fileDataCurPtr = fileDataPtr = fileData.ptr;
1127					fileDataEndPtr = fileDataCurPtr + stream.readAny(fileData.ptr, cast(uint)stream.remaining);
1128
1129					if (fileDataCurPtr + fileDataToSkip >= fileDataEndPtr) {
1130						//////OutputDebugStringA("bmp - rendering error - not enough information\n");
1131						//////OutputDebugStringA("bmp - skipping data across page\n");
1132						fileDataToSkip -= (fileDataEndPtr - fileDataCurPtr);
1133						view.unlockBuffer();
1134						delete fileData;
1135						return StreamData.Complete;
1136					}
1137					else if (fileDataToSkip > 0) {
1138						fileDataCurPtr += fileDataToSkip;
1139						fileDataToSkip = 0;
1140					}
1141
1142					// we start from the bottom of the bitmap and work our way up
1143					// ptr_max == ORIGINAL POINTER GIVEN BY LOCK BUFFER
1144					// ptr == WORKS ITS WAY FROM END OF BITMAP TO FRONT
1145
1146					if (bi.biCompression == 0) {
1147						// GO THROUGH AND RENDER TO THE BITMAP
1148						// AS MUCH AS POSSIBLE
1149						for (;;) {
1150							ptr[0] = palette[fileDataCurPtr[0]];
1151
1152							ptr++;
1153							ptrPos++;
1154							fileDataCurPtr++;
1155
1156							if (ptr == ptr_max_line) {
1157								//////OutputDebugStringA("bmp - rendered line\n");
1158								if (ptr == ptr_max) {
1159									////OutputDebugStringA("bmp - rendering complete\n");
1160									view.unlockBuffer();
1161									delete fileData;
1162									return StreamData.Complete;
1163								}
1164
1165								ptrLine++;
1166								ptrPos = 0;
1167
1168								ptr -= (bi.biWidth * 2);
1169								ptr_max_line -= (bi.biWidth);
1170
1171								fileDataToSkip = bytesPerRow - bi.biWidth;
1172
1173								if (fileDataCurPtr + fileDataToSkip >= fileDataEndPtr) {
1174									fileDataToSkip -= (fileDataEndPtr - fileDataCurPtr);
1175									break;
1176								}
1177								else {
1178									fileDataCurPtr += fileDataToSkip;
1179									fileDataToSkip = 0;
1180								}
1181							}
1182
1183							if (fileDataCurPtr == fileDataEndPtr) {
1184								break;
1185							}
1186						}
1187					}
1188					else { // rle - 8
1189						//calculate pointers
1190
1191						// LOOP
1192						// {
1193						//    STATE 0:
1194						//        GET FIRST CODE
1195						//    STATE 1: RLE NORMAL
1196						//        GET CODE
1197						//        RENDER
1198						//    STATE 2: ESCAPE
1199						//        GET CODE
1200						//          FILL IN LINE  (EOL)
1201						//          FILL IN IMAGE (EOB)
1202						//          SWITCH TO DELTA
1203						//          SWITCH TO ABSOLUTE
1204						//    STATE 3: DELTA
1205						//        GET CODES
1206						//        REPOSITION
1207						//    STATE 4: ABSOLUTE
1208						//        RENDER
1209						// }
1210						for (;fileDataCurPtr < fileDataEndPtr;) {
1211							switch(decoderSubState) {
1212							case 0:
1213
1214								// GET CODE
1215
1216								byteData = fileDataCurPtr[0];
1217
1218								if (byteData == 0) {
1219									// ESCAPE SEQUENCE
1220									decoderSubState = 2;
1221								}
1222								else {
1223									// JUST RENDER DATA OUT
1224									decoderSubState = 1;
1225								}
1226
1227								fileDataCurPtr++;
1228								if (fileDataCurPtr == fileDataEndPtr) { break; }
1229
1230								break;
1231							case 1:
1232
1233								//////OutputDebugStringA("bmp - rle - state: RENDER\n");
1234
1235								// RENDER RLE DATA
1236
1237								//run the getLength of lenByte, and paint the pixel
1238								//of the index that many times onto the buffer
1239								for ( ; (byteData > 0); ) {
1240									ptr[0] = palette[fileDataCurPtr[0]];
1241									ptr++;
1242									ptrPos++;
1243									byteData--;
1244
1245									if (ptr == ptr_max_line) {
1246										if (ptr == ptr_max) {
1247											////OutputDebugStringA("bmp - from render - rendering complete\n");
1248											view.unlockBuffer();
1249											delete fileData;
1250											return StreamData.Complete;
1251										}
1252
1253										ptrLine++;
1254										ptrPos = 0;
1255
1256										ptr -= (bi.biWidth * 2);
1257										ptr_max_line -= (bi.biWidth);
1258									}
1259								}
1260
1261								// GO BACK TO RETRIEVAL OF CODE
1262								decoderSubState = 0;
1263
1264								fileDataCurPtr++;
1265								if (fileDataCurPtr >= fileDataEndPtr) { break; }
1266
1267								break;
1268							case 2:
1269
1270								// HANDLE ESCAPE SEQUENCES
1271								byteData = fileDataCurPtr[0];
1272
1273								if (byteData < 3) {
1274									if (byteData == 0) {
1275										// END OF LINE ENCODING
1276										if (ptrPos!=0) {
1277											for ( ; ; ) {
1278												ptr[0] = 0;
1279												ptr++;
1280												ptrPos++;
1281
1282												if (ptr == ptr_max_line) {
1283													//////OutputDebugStringA("bmp - rendered line\n");
1284													if (ptr == ptr_max) {
1285														////OutputDebugStringA("bmp - rendering complete\n");
1286														view.unlockBuffer();
1287														delete fileData;
1288														return StreamData.Complete;
1289													}
1290
1291													ptrLine++;
1292													ptrPos = 0;
1293
1294													ptr -= (bi.biWidth * 2);
1295													ptr_max_line -= (bi.biWidth);
1296
1297													break;
1298												}
1299											}
1300										}
1301
1302										// BACK TO GETTING A CODE
1303										decoderSubState = 0;
1304									}
1305									else if (byteData == 1) {
1306										// END OF BITMAP ENCODING
1307										//end of bitmap
1308										//paint black pixels
1309										//to the rest of the bitmap and exit
1310										for (;;) {
1311											for ( ; ; ) {
1312												ptr[0] = 0;
1313												ptr++;
1314												ptrPos++;
1315
1316												if (ptr == ptr_max_line) {
1317													//////OutputDebugStringA("bmp - rendered line\n");
1318													if (ptr == ptr_max) {
1319														////OutputDebugStringA("bmp - rendering complete\n");
1320														view.unlockBuffer();
1321														delete fileData;
1322														return StreamData.Complete;
1323													}
1324
1325													ptrLine++;
1326													ptrPos = 0;
1327
1328													ptr -= (bi.biWidth * 2);
1329													ptr_max_line -= (bi.biWidth);
1330												}
1331											}
1332										}
1333
1334										// BACK TO GETTING A CODE
1335										//decoderSubState = 0;
1336									}
1337									else { //if (byteData == 2)
1338										// DELTA ENCODING
1339										decoderSubState = 7;
1340									}
1341								}
1342								else {
1343									//ABSOLUTE MODE
1344									byteCounter = byteData;
1345									decoderSubState = 3;
1346								}
1347
1348								fileDataCurPtr++;
1349								if (fileDataCurPtr >= fileDataEndPtr) { break; }
1350
1351								break;
1352							case 3:
1353
1354								// ABSOLUTE MODE
1355
1356								// BYTE DATA IS THE AMOUNT OF BYTES TO READ
1357
1358								//decode
1359								for ( ; (byteCounter>0) && (ptr < ptr_max_line);  ) {
1360									ptr[0] = palette[fileDataCurPtr[0]];
1361									ptrPos++;
1362									ptr++;
1363									byteCounter--;
1364
1365									if (ptr == ptr_max_line) {
1366										//////OutputDebugStringA("bmp - rendered line\n");
1367										if (ptr == ptr_max) {
1368											view.unlockBuffer();
1369											return StreamData.Complete;
1370										}
1371
1372										ptrLine++;
1373										ptrPos = 0;
1374
1375										ptr -= (bi.biWidth * 2);
1376										ptr_max_line -= (bi.biWidth);
1377									}
1378
1379									fileDataCurPtr++;
1380									if (fileDataCurPtr >= fileDataEndPtr) { break; }
1381								}
1382
1383								if (byteCounter == 0) {
1384									// BACK TO GETTING A CODE
1385									decoderSubState = 0;
1386
1387									//realign to a word boundary
1388									fileDataToSkip = (byteData & 0x01);
1389
1390									if (fileDataCurPtr + fileDataToSkip >= fileDataEndPtr) {
1391										fileDataToSkip -= (fileDataEndPtr - fileDataCurPtr);
1392
1393										//ensure we drop out of loop
1394										fileDataCurPtr = fileDataEndPtr;
1395										break;
1396									}
1397									else {
1398										fileDataCurPtr += fileDataToSkip;
1399										fileDataToSkip = 0;
1400									}
1401								}
1402
1403								break;
1404							case 7:
1405
1406								////OutputDebugStringA("bmp - rle - state: DELTA\n");
1407								// DELTA MODE
1408
1409								// BACK TO GETTING A CODE
1410								decoderSubState = 0;
1411
1412								break;
1413							case 5:
1414								break;
1415							case 6:
1416								break;
1417							default: break;
1418							}
1419						}
1420					}
1421				}
1422
1423				//view.unlockBuffer();
1424				//break;
1425
1426
1427	// WINDOWS 16BPP BITMAPS, 5-6-5 AND 5-5-5 AND others //
1428
1429			case BMP_STATE_DECODE_WIN_16BPP:
1430				////OutputDebugStringA("bmp - windows - 16 bpp\n");
1431				return StreamData.Complete;
1432
1433	// WINDOWS 24BPP BITMAPS //
1434
1435			case BMP_STATE_DECODE_WIN_24BPP:
1436				////OutputDebugStringA("bmp - windows - 24 bpp - true color\n");
1437
1438				//skip further padding, skip to image data, according to header
1439				if (bf.bfOffBits - (54) > 0) {
1440					if(!stream.skip(bf.bfOffBits - (54) ) ) { return StreamData.Required; }
1441				}
1442
1443				//Calculate the bytes each row will take
1444				//within the file's bitmap data
1445				bytesForPadding=0;
1446				bytesPerRow = bi.biWidth*3;
1447				if (bytesPerRow & 0x3) {
1448					//pad bytes per row
1449					bytesForPadding = (4 - (bytesPerRow & 0x3));
1450					bytesPerRow += bytesForPadding;
1451				}
1452
1453				if (bi.biCompression == 0) { // rgb
1454					//calculate the getLength of the bitmap data
1455					bitmapDataLen = bytesPerRow * bi.biHeight;
1456				}
1457				else {
1458					////OutputDebugStringA("bmp - invalid compression format\n");
1459					return StreamData.Invalid;
1460				}
1461
1462				//create the bitmap's buffer
1463				view.create(bi.biWidth, bi.biHeight);
1464
1465				ptrLine = 0;
1466				ptrPos = 0;
1467				fileDataToSkip = 0;
1468
1469				byteCounter = 0;
1470
1471				decoderState = BMP_STATE_RENDER_WIN_24BPP;
1472
1473			case BMP_STATE_RENDER_WIN_24BPP:
1474
1475				//////OutputDebugStringA("bmp - rendering stream input - 24bpp\n");
1476
1477				// TAKE ALL BYTES FROM STREAM
1478				// IF WE FINISH, WE CAN return StreamData.Complete
1479
1480				// GET THE BITMAP DATA AND GO TO THE NEXT POSITION
1481				// TO RENDER TO
1482
1483				view.lockBuffer(cast(void**)&ptr_max, ptr_len);
1484
1485				ptr = ptr_max + (ptr_len / 4);
1486
1487				ptr -= (bi.biWidth * (ptrLine + 1));
1488				ptr_max_line = ptr + bi.biWidth;
1489
1490				ptr_max += bi.biWidth;
1491
1492				ptr += ptrPos;
1493
1494				// LOAD FILEDATA WITH PART OF THE STREAM
1495				// CHUNKS AT A TIME
1496				for (;;) {
1497					if (stream.remaining == 0) {
1498						view.unlockBuffer();
1499						return StreamData.Required;
1500					}
1501
1502					fileData = new ubyte[cast(uint)bitmapDataLen];
1503					fileDataCurPtr = fileDataPtr = fileData.ptr;
1504					fileDataEndPtr = fileDataCurPtr + stream.readAny(fileData.ptr, cast(uint)bitmapDataLen);
1505
1506					if (fileDataCurPtr + fileDataToSkip >= fileDataEndPtr) {
1507						//////OutputDebugStringA("bmp - rendering error - not enough information\n");
1508						//////OutputDebugStringA("bmp - skipping data across page\n");
1509						fileDataToSkip -= (fileDataEndPtr - fileDataCurPtr);
1510						view.unlockBuffer();
1511						delete fileData;
1512						return StreamData.Complete;
1513					}
1514					else if (fileDataToSkip > 0) {
1515						fileDataCurPtr += fileDataToSkip;
1516						fileDataToSkip = 0;
1517					}
1518
1519					// we start from the bottom of the bitmap and work our way up
1520					// ptr_max == ORIGINAL POINTER GIVEN BY LOCK BUFFER
1521					// ptr == WORKS ITS WAY FROM END OF BITMAP TO FRONT
1522
1523
1524					// GO THROUGH AND RENDER TO THE BITMAP
1525					// AS MUCH AS POSSIBLE
1526					for (;fileDataCurPtr < fileDataEndPtr;) {
1527						if (((fileDataEndPtr - fileDataCurPtr) > 3) && byteCounter == 0) {
1528							ptr[0] = 0xFF000000 | ((cast(uint*)fileDataCurPtr)[0] & 0xFFFFFF);// | (fileDataCurPtr[1] << 8) | (fileDataCurPtr[2] << 16);
1529							fileDataCurPtr+=3;
1530
1531							ptr++;
1532							ptrPos++;
1533
1534							if (ptr == ptr_max_line) {
1535								if (ptr == ptr_max) {
1536									////OutputDebugStringA("bmp - rendering complete\n");
1537									view.unlockBuffer();
1538									delete fileData;
1539									return StreamData.Complete;
1540								}
1541
1542								ptrLine++;
1543								ptrPos = 0;
1544
1545								ptr -= (bi.biWidth * 2);
1546								ptr_max_line -= (bi.biWidth);
1547
1548								fileDataToSkip = bytesForPadding;
1549
1550								if (fileDataCurPtr + fileDataToSkip >= fileDataEndPtr) {
1551									fileDataToSkip -= (fileDataEndPtr - fileDataCurPtr);
1552									break;
1553								}
1554								else {
1555									fileDataCurPtr += fileDataToSkip;
1556									fileDataToSkip = 0;
1557								}
1558							}
1559						}
1560						else if (byteCounter == 0) {
1561							ptr[0] = 0xFF000000 | (fileDataCurPtr[0]);
1562							byteCounter++;
1563
1564							fileDataCurPtr++;
1565						}
1566						else if (byteCounter == 1) {
1567							ptr[0] |= (fileDataCurPtr[0] << 8);
1568							byteCounter++;
1569
1570							fileDataCurPtr++;
1571						}
1572						else {
1573							ptr[0] |= (fileDataCurPtr[0] << 16) ;
1574							byteCounter = 0;
1575
1576							ptr++;
1577							ptrPos++;
1578							fileDataCurPtr++;
1579
1580							if (ptr == ptr_max_line) {
1581								if (ptr == ptr_max) {
1582									////OutputDebugStringA("bmp - rendering complete\n");
1583									view.unlockBuffer();
1584									delete fileData;
1585									return StreamData.Complete;
1586								}
1587
1588								ptrLine++;
1589								ptrPos = 0;
1590
1591								ptr -= (bi.biWidth * 2);
1592								ptr_max_line -= (bi.biWidth);
1593
1594								fileDataToSkip = bytesForPadding;
1595
1596								if (fileDataCurPtr + fileDataToSkip >= fileDataEndPtr) {
1597									fileDataToSkip -= (fileDataEndPtr - fileDataCurPtr);
1598									break;
1599								}
1600								else {
1601									fileDataCurPtr += fileDataToSkip;
1602									fileDataToSkip = 0;
1603								}
1604							}
1605						}
1606					}
1607				}
1608
1609	// WINDOWS 32BPP BITMAPS //
1610
1611			case BMP_STATE_DECODE_WIN_32BPP:
1612				////OutputDebugStringA("bmp - windows - 32 bpp - true color\n");
1613
1614				//skip further padding, skip to image data, according to header
1615				if (bf.bfOffBits - (54) > 0) {
1616					if(!stream.skip(bf.bfOffBits - (54) ) ) { return StreamData.Required; }
1617				}
1618
1619				//Calculate the bytes each row will take
1620				//within the file's bitmap data
1621				bytesPerRow = bi.biWidth*4;
1622				bytesForPadding = 0;
1623
1624				if (bi.biCompression == 0 || bi.biCompression == 3) { // rgb
1625					//calculate the getLength of the bitmap data
1626					bitmapDataLen = bytesPerRow * bi.biHeight;
1627				}
1628				else {
1629					////OutputDebugStringA("bmp - invalid compression format\n");
1630					return StreamData.Invalid;
1631				}
1632
1633				//create the bitmap's buffer
1634				view.create(bi.biWidth, bi.biHeight);
1635
1636				ptrLine = 0;
1637				ptrPos = 0;
1638				fileDataToSkip = 0;
1639
1640				byteCounter = 0;
1641
1642				decoderState = BMP_STATE_RENDER_WIN_32BPP;
1643
1644			case BMP_STATE_RENDER_WIN_32BPP:
1645
1646				//////OutputDebugStringA("bmp - rendering stream input - 32bpp\n");
1647
1648				// TAKE ALL BYTES FROM STREAM
1649				// IF WE FINISH, WE CAN return StreamData.Complete
1650
1651				// GET THE BITMAP DATA AND GO TO THE NEXT POSITION
1652				// TO RENDER TO
1653				view.lockBuffer(cast(void**)&ptr_max, ptr_len);
1654
1655				ptr = ptr_max + (ptr_len / 4);
1656
1657				ptr -= (bi.biWidth * (ptrLine + 1));
1658				ptr_max_line = ptr + bi.biWidth;
1659
1660				ptr_max += bi.biWidth;
1661
1662				ptr += ptrPos;
1663
1664				// LOAD FILEDATA WITH PART OF THE STREAM
1665				// CHUNKS AT A TIME
1666				for (;;) {
1667					if (stream.remaining == 0) {
1668						view.unlockBuffer();
1669						return StreamData.Required;
1670					}
1671
1672					fileData = new ubyte[cast(uint)stream.remaining];
1673					fileDataCurPtr = fileDataPtr = fileData.ptr;
1674					fileDataEndPtr = fileDataCurPtr + stream.readAny(fileData.ptr, cast(uint)stream.remaining);
1675
1676					// we start from the bottom of the bitmap and work our way up
1677					// ptr_max == ORIGINAL POINTER GIVEN BY LOCK BUFFER
1678					// ptr == WORKS ITS WAY FROM END OF BITMAP TO FRONT
1679
1680
1681					// GO THROUGH AND RENDER TO THE BITMAP
1682					// AS MUCH AS POSSIBLE
1683					for (;fileDataCurPtr < fileDataEndPtr;) {
1684						if (((fileDataEndPtr - fileDataCurPtr) > 3) && byteCounter == 0) {
1685							ptr[0] = 0xFF000000 | ((cast(uint*)fileDataCurPtr)[0] & 0xFFFFFF);// | (fileDataCurPtr[1] << 8) | (fileDataCurPtr[2] << 16);
1686							fileDataCurPtr+=4;
1687
1688							ptr++;
1689							ptrPos++;
1690
1691							if (ptr == ptr_max_line) {
1692								if (ptr == ptr_max) {
1693									////OutputDebugStringA("bmp - rendering complete\n");
1694									view.unlockBuffer();
1695									delete fileData;
1696
1697									return StreamData.Complete;
1698								}
1699
1700								ptrLine++;
1701								ptrPos = 0;
1702
1703								ptr -= (bi.biWidth * 2);
1704								ptr_max_line -= (bi.biWidth);
1705
1706								fileDataToSkip = bytesForPadding;
1707
1708								if (fileDataCurPtr + fileDataToSkip >= fileDataEndPtr) {
1709									fileDataToSkip -= (fileDataEndPtr - fileDataCurPtr);
1710									break;
1711								}
1712								else {
1713									fileDataCurPtr += fileDataToSkip;
1714									fileDataToSkip = 0;
1715								}
1716							}
1717						}
1718						else if (byteCounter == 0) {
1719							ptr[0] = 0xFF000000 | (fileDataCurPtr[0]);
1720							byteCounter++;
1721
1722							fileDataCurPtr++;
1723						}
1724						else if (byteCounter == 1) {
1725							ptr[0] |= (fileDataCurPtr[0] << 8);
1726							byteCounter++;
1727
1728							fileDataCurPtr++;
1729						}
1730						else if (byteCounter == 2) {
1731							ptr[0] |= (fileDataCurPtr[0] << 16);
1732							byteCounter++;
1733
1734							fileDataCurPtr++;
1735						}
1736						else {
1737							//ptr[0] |= (fileDataCurPtr[0] << 16) ;
1738							byteCounter = 0;
1739
1740							ptr++;
1741							ptrPos++;
1742							fileDataCurPtr++;
1743
1744							if (ptr == ptr_max_line) {
1745								//////OutputDebugStringA("bmp - rendered line\n");
1746								if (ptr == ptr_max) {
1747									////OutputDebugStringA("bmp - rendering complete\n");
1748									view.unlockBuffer();
1749									delete fileData;
1750									return StreamData.Complete;
1751								}
1752
1753								ptrLine++;
1754								ptrPos = 0;
1755
1756								ptr -= (bi.biWidth * 2);
1757								ptr_max_line -= (bi.biWidth);
1758							}
1759						}
1760					}
1761				}
1762
1763				default:
1764					break;
1765			}
1766			break;
1767		}
1768
1769		return StreamData.Invalid;
1770	}
1771
1772private:
1773	static const auto BMP_STATE_INIT						= 0;
1774
1775	static const auto BMP_STATE_READ_HEADERS				= 1;
1776	static const auto BMP_STATE_READ_BITMAP_SIZE			= 2;
1777
1778	static const auto BMP_STATE_READ_OSX_1					= 3;
1779	static const auto BMP_STATE_READ_OSX_2					= 4;
1780	static const auto BMP_STATE_READ_WIN					= 5;
1781
1782	static const auto BMP_STATE_READ_WIN_PALETTE			= 6;
1783	static const auto BMP_STATE_READ_OSX_1_PALETTE			= 7;
1784	static const auto BMP_STATE_READ_OSX_2_PALETTE			= 8;
1785
1786	static const auto BMP_STATE_DECODE_WIN_1BPP			= 9;
1787	static const auto BMP_STATE_DECODE_WIN_2BPP			= 10;
1788	static const auto BMP_STATE_DECODE_WIN_4BPP			= 11;
1789	static const auto BMP_STATE_DECODE_WIN_8BPP			= 12;
1790	static const auto BMP_STATE_DECODE_WIN_16BPP			= 13;
1791	static const auto BMP_STATE_DECODE_WIN_24BPP			= 14;
1792	static const auto BMP_STATE_DECODE_WIN_32BPP			= 15;
1793
1794	static const auto BMP_STATE_RENDER_WIN_1BPP			= 16;
1795	static const auto BMP_STATE_RENDER_WIN_2BPP			= 17;
1796	static const auto BMP_STATE_RENDER_WIN_4BPP			= 18;
1797	static const auto BMP_STATE_RENDER_WIN_8BPP			= 19;
1798	static const auto BMP_STATE_RENDER_WIN_16BPP			= 20;
1799	static const auto BMP_STATE_RENDER_WIN_24BPP			= 21;
1800	static const auto BMP_STATE_RENDER_WIN_32BPP			= 22;
1801
1802	static const auto BMP_STATE_DECODE_OS2_1_1BPP			= 40;
1803
1804	static const auto BMP_STATE_DECODE_OS2_2_1BPP			= 80;
1805
1806
1807
1808
1809	static const ubyte _djehuty_convert_16_of_6_to_32[64] = (0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 45, 49, 53, 57, 61,
1810														65, 69, 73, 77, 81, 85, 89, 93, 97, 101, 105, 109, 113, 117, 121, 125,
1811														130, 134, 138, 142, 146, 150, 154, 158, 162, 166, 170, 174, 178, 182, 186,
1812														190, 194, 198, 202, 206, 210, 215, 219, 223, 227, 231, 235, 239, 243, 247, 251, 255);
1813
1814	static const ubyte _djehuty_convert_16_of_5_to_32[32] = (0, 8, 16, 25, 33, 41, 49, 58, 66, 74, 82, 90, 99, 107, 115, 123,
1815														132, 140, 148, 156, 165, 173, 181, 189, 197, 206, 214, 222, 230, 239, 247, 255);
1816protected:
1817
1818	_djehuty_image_bitmap_file_header bf;
1819	_djehuty_image_bitmap_info_header bi;
1820	_djehuty_image_os2_1_bitmap_info_header os2_1_bi;
1821	_djehuty_image_os2_2_bitmap_info_header os2_2_bi;
1822
1823	uint biSize;
1824
1825	uint paletteNumColors;
1826	uint palette[256];
1827
1828	int bytesPerRow;
1829	int bytesForPadding;
1830
1831	ubyte fileData[];
1832	ubyte* fileDataPtr;
1833	ubyte* fileDataEndPtr;
1834	ubyte* fileDataCurPtr;
1835	int fileDataToSkip;
1836
1837	uint ptrLine;		//the current scan line of the image (y)
1838	uint ptrPos;		//the current pixel of the line (x)
1839
1840	uint byteData;
1841	uint byteCounter;
1842
1843	ulong bitmapDataLen;
1844
1845	ulong fileSize;
1846}