1 /*****************************************************************************/ 2 // SGITranslator 3 // Written by Stephan Aßmus <stippi@yellowbites.com> 4 // derived from GIMP SGI plugin by Michael Sweet 5 // 6 // SGIImage.cpp 7 // 8 // SGI image file format library routines. 9 // 10 // Formed into a class SGIImage, adopted to Be API and modified to use 11 // BPositionIO, optimizations for buffered reading. 12 // 13 // 14 // Copyright (c) 2003 OpenBeOS Project 15 // Portions Copyright 1997-1998 Michael Sweet (mike@easysw.com) 16 // 17 // Permission is hereby granted, free of charge, to any person obtaining a 18 // copy of this software and associated documentation files (the "Software"), 19 // to deal in the Software without restriction, including without limitation 20 // the rights to use, copy, modify, merge, publish, distribute, sublicense, 21 // and/or sell copies of the Software, and to permit persons to whom the 22 // Software is furnished to do so, subject to the following conditions: 23 // 24 // The above copyright notice and this permission notice shall be included 25 // in all copies or substantial portions of the Software. 26 // 27 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 28 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 29 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 30 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 31 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 32 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 33 // DEALINGS IN THE SOFTWARE. 34 /*****************************************************************************/ 35 36 #include <malloc.h> 37 #include <stdio.h> 38 #include <string.h> 39 40 #include <ByteOrder.h> 41 #include <DataIO.h> 42 #include <TranslationErrors.h> 43 44 #include "SGIImage.h" 45 46 const char kSGICopyright[] = ""B_UTF8_COPYRIGHT" 1997-1998 Michael Sweet <mike@easysw.com>"; 47 48 // constructor 49 SGIImage::SGIImage() 50 : fStream(NULL), 51 fMode(0), 52 fBytesPerChannel(0), 53 fCompression(0), 54 fWidth(0), 55 fHeight(0), 56 fChannelCount(0), 57 fFirstRowOffset(0), 58 fNextRowOffset(0), 59 fOffsetTable(NULL), 60 fLengthTable(NULL), 61 fARLERow(NULL), 62 fARLEOffset(0), 63 fARLELength(0) 64 { 65 } 66 67 // destructor 68 SGIImage::~SGIImage() 69 { 70 Unset(); 71 } 72 73 // InitCheck 74 status_t 75 SGIImage::InitCheck() const 76 { 77 if (fStream) 78 return B_OK; 79 return B_NO_INIT; 80 } 81 82 // SetTo 83 // open an SGI image file for reading 84 // 85 // stream the input stream 86 status_t 87 SGIImage::SetTo(BPositionIO* stream) 88 { 89 if (!stream) 90 return B_BAD_VALUE; 91 92 fStream = stream; 93 stream->Seek(0, SEEK_SET); 94 95 int16 magic = _ReadShort(); 96 if (magic != SGI_MAGIC) { 97 fStream = NULL; 98 return B_NO_TRANSLATOR; 99 } 100 101 fMode = SGI_READ; 102 103 fCompression = _ReadChar(); 104 fBytesPerChannel = _ReadChar(); 105 _ReadShort(); // Dimensions 106 fWidth = _ReadShort(); 107 fHeight = _ReadShort(); 108 fChannelCount = _ReadShort(); 109 // _ReadLong(); // Minimum pixel 110 // _ReadLong(); // Maximum pixel 111 112 if (fCompression) { 113 // this stream is compressed; read the scanline tables... 114 115 fStream->Seek(512, SEEK_SET); 116 117 fOffsetTable = (int32**)calloc(fChannelCount, sizeof(int32*)); 118 fOffsetTable[0] = (int32*)calloc(fHeight * fChannelCount, sizeof(int32)); 119 for (uint32 i = 1; i < fChannelCount; i++) 120 fOffsetTable[i] = fOffsetTable[0] + i * fHeight; 121 122 for (uint32 i = 0; i < fChannelCount; i++) 123 for (uint16 j = 0; j < fHeight; j++) 124 fOffsetTable[i][j] = _ReadLong(); 125 126 fLengthTable = (int32**)calloc(fChannelCount, sizeof(int32*)); 127 fLengthTable[0] = (int32*)calloc(fHeight * fChannelCount, sizeof(int32)); 128 129 for (int32 i = 1; i < fChannelCount; i ++) 130 fLengthTable[i] = fLengthTable[0] + i * fHeight; 131 132 for (uint32 i = 0; i < fChannelCount; i++) 133 for (uint16 j = 0; j < fHeight; j++) 134 fLengthTable[i][j] = _ReadLong(); 135 136 } 137 return B_OK; 138 } 139 140 // SetTo 141 // open an SGI image file for writing 142 // 143 // stream the output stream 144 // width number of pixels in a row 145 // height number of rows 146 // channels number of channels per pixel 147 // bytesPerChannel number of bytes per channel 148 // compression compression mode 149 status_t 150 SGIImage::SetTo(BPositionIO* stream, 151 uint16 width, uint16 height, 152 uint16 channels, uint32 bytesPerChannel, 153 uint32 compression) 154 { 155 // sanity checks 156 if (!stream || 157 width < 1 || height < 1 || channels < 1 || 158 bytesPerChannel < 1 || bytesPerChannel > 2 || 159 compression < SGI_COMP_NONE || compression > SGI_COMP_ARLE) 160 return B_BAD_VALUE; 161 162 fStream = stream; 163 fMode = SGI_WRITE; 164 165 _WriteShort(SGI_MAGIC); 166 _WriteChar((fCompression = compression) != 0); 167 _WriteChar(fBytesPerChannel = bytesPerChannel); 168 _WriteShort(3); // Dimensions 169 _WriteShort(fWidth = width); 170 _WriteShort(fHeight = height); 171 _WriteShort(fChannelCount = channels); 172 173 if (fBytesPerChannel == 1) { 174 _WriteLong(0); // Minimum pixel 175 _WriteLong(255); // Maximum pixel 176 } else { 177 _WriteLong(-32768); // Minimum pixel 178 _WriteLong(32767); // Maximum pixel 179 } 180 _WriteLong(0); // Reserved 181 182 char name[80]; // Name of file in image header 183 memset(name, 0, sizeof(name)); 184 sprintf(name, "OpenBeOS SGITranslator"); 185 fStream->Write(name, sizeof(name)); 186 187 // fill the rest of the image header with zeros 188 for (int32 i = 0; i < 102; i++) 189 _WriteLong(0); 190 191 switch (fCompression) { 192 case SGI_COMP_NONE : // No compression 193 // This file is uncompressed. To avoid problems with 194 // sparse files, we need to write blank pixels for the 195 // entire image... 196 197 /* if (fBytesPerChannel == 1) { 198 for (int32 i = fWidth * fHeight * fChannelCount; i > 0; i --) 199 _WriteChar(0); 200 } else { 201 for (int32 i = fWidth * fHeight * fChannelCount; i > 0; i --) 202 _WriteShort(0); 203 }*/ 204 break; 205 206 case SGI_COMP_ARLE: // Aggressive RLE 207 fARLERow = (uint16*)calloc(fWidth, sizeof(uint16)); 208 fARLEOffset = 0; 209 // FALL THROUGH 210 case SGI_COMP_RLE : // Run-Length Encoding 211 // This file is compressed; write the (blank) scanline tables... 212 213 // for (int32 i = 2 * fHeight * fChannelCount; i > 0; i--) 214 // _WriteLong(0); 215 fStream->Seek(2 * fHeight * fChannelCount * sizeof(int32), SEEK_CUR); 216 217 fFirstRowOffset = fStream->Position(); 218 fNextRowOffset = fStream->Position(); 219 220 // allocate and read offset table 221 fOffsetTable = (int32**)calloc(fChannelCount, sizeof(int32*)); 222 fOffsetTable[0] = (int32*)calloc(fHeight * fChannelCount, sizeof(int32)); 223 224 for (int32 i = 1; i < fChannelCount; i ++) 225 fOffsetTable[i] = fOffsetTable[0] + i * fHeight; 226 227 // allocate and read length table 228 fLengthTable = (int32**)calloc(fChannelCount, sizeof(int32*)); 229 fLengthTable[0] = (int32*)calloc(fHeight * fChannelCount, sizeof(int32)); 230 231 for (int32 i = 1; i < fChannelCount; i ++) 232 fLengthTable[i] = fLengthTable[0] + i * fHeight; 233 break; 234 } 235 return B_OK; 236 } 237 238 // Unset 239 // 240 // if in write mode, writes final information to the stream 241 status_t 242 SGIImage::Unset() 243 { 244 status_t ret = InitCheck(); // return status 245 if (ret >= B_OK) { 246 247 if (fMode == SGI_WRITE && fCompression != SGI_COMP_NONE) { 248 // write the scanline offset table to the file... 249 250 fStream->Seek(512, SEEK_SET); 251 252 /* off_t* offset = fOffsetTable[0]; 253 for (int32 i = fHeight * fChannelCount; i > 0; i--) { 254 if ((ret = _WriteLong(offset[0])) < B_OK) 255 break; 256 offset++; 257 }*/ 258 259 int32 size = fHeight * fChannelCount * sizeof(int32); 260 swap_data(B_INT32_TYPE, fOffsetTable[0], size, B_SWAP_HOST_TO_BENDIAN); 261 ret = fStream->Write(fOffsetTable[0], size); 262 263 if (ret >= B_OK) { 264 265 /* int32* length = fLengthTable[0]; 266 for (int32 i = fHeight * fChannelCount; i > 0; i--) { 267 if ((ret = _WriteLong(length[0])) < B_OK) 268 break; 269 length++; 270 }*/ 271 272 swap_data(B_INT32_TYPE, fLengthTable[0], size, B_SWAP_HOST_TO_BENDIAN); 273 ret = fStream->Write(fLengthTable[0], size); 274 275 } 276 } 277 278 if (fOffsetTable != NULL) { 279 free(fOffsetTable[0]); 280 free(fOffsetTable); 281 fOffsetTable = NULL; 282 } 283 284 if (fLengthTable != NULL) { 285 free(fLengthTable[0]); 286 free(fLengthTable); 287 fLengthTable = NULL; 288 } 289 290 if (fARLERow) { 291 free(fARLERow); 292 fARLERow = NULL; 293 } 294 295 fStream = NULL; 296 } 297 return ret; 298 } 299 300 // ReadRow 301 // 302 // reads a row of image data from the stream 303 // 304 // row pointer to buffer (row of pixels) to read 305 // y index (line number) of this row 306 // z which channel to read 307 status_t 308 SGIImage::ReadRow(void* row, int32 y, int32 z) 309 { 310 // sanitiy checks 311 if (row == NULL || 312 y < 0 || y >= fHeight || 313 z < 0 || z >= fChannelCount) 314 return B_BAD_VALUE; 315 316 317 status_t ret = B_ERROR; 318 319 switch (fCompression) { 320 case SGI_COMP_NONE: { 321 // seek to the image row 322 // optimize buffering by only seeking if necessary... 323 324 off_t offset = 512 + (y + z * fHeight) * fWidth * fBytesPerChannel; 325 fStream->Seek(offset, SEEK_SET); 326 327 uint32 bytes = fWidth * fBytesPerChannel; 328 //printf("reading %ld bytes 8 Bit uncompressed row: %ld, channel: %ld\n", bytes, y, z); 329 ret = fStream->Read(row, bytes); 330 331 break; 332 } 333 case SGI_COMP_RLE: { 334 int32 offset = fOffsetTable[z][y]; 335 int32 rleLength = fLengthTable[z][y]; 336 fStream->Seek(offset, SEEK_SET); 337 uint8* rleBuffer = new uint8[rleLength]; 338 fStream->Read(rleBuffer, rleLength); 339 340 if (fBytesPerChannel == 1) { 341 //printf("reading 8 Bit RLE compressed row: %ld, channel: %ld\n", y, z); 342 // ret = _ReadRLE8((uint8*)row, fWidth); 343 ret = _ReadRLE8((uint8*)row, rleBuffer, fWidth); 344 } else { 345 //printf("reading 16 Bit RLE compressed row: %ld, channel: %ld\n", y, z); 346 // ret = _ReadRLE16((uint16*)row, fWidth); 347 if ((ret = swap_data(B_INT16_TYPE, rleBuffer, rleLength, B_SWAP_BENDIAN_TO_HOST)) >= B_OK) 348 ret = _ReadRLE16((uint16*)row, (uint16*)rleBuffer, fWidth); 349 } 350 delete[] rleBuffer; 351 break; 352 } 353 } 354 return ret; 355 } 356 357 // WriteRow 358 // 359 // writes a row of image data to the stream 360 // 361 // row pointer to buffer (row of pixels) to write 362 // y index (line number) of this row 363 // z which channel to write 364 status_t 365 SGIImage::WriteRow(void* row, int32 y, int32 z) 366 { 367 // sanitiy checks 368 if (row == NULL || 369 y < 0 || y >= fHeight || 370 z < 0 || z >= fChannelCount) 371 return B_BAD_VALUE; 372 373 int32 x; // x coordinate 374 int32 offset; // stream offset 375 376 status_t ret = B_ERROR; 377 378 switch (fCompression) { 379 case SGI_COMP_NONE: { 380 // Seek to the image row 381 382 offset = 512 + (y + z * fHeight) * fWidth * fBytesPerChannel; 383 fStream->Seek(offset, SEEK_SET); 384 385 uint32 bytes = fWidth * fBytesPerChannel; 386 //printf("writing %ld bytes %ld byte/channel uncompressed row: %ld, channel: %ld\n", bytes, fBytesPerChannel, y, z); 387 ret = fStream->Write(row, bytes); 388 /* if (fBytesPerChannel == 1) { 389 for (x = fWidth; x > 0; x--) { 390 _WriteChar(*row); 391 row++; 392 } 393 } else { 394 for (x = fWidth; x > 0; x--) { 395 _WriteShort(*row); 396 row++; 397 } 398 }*/ 399 break; 400 } 401 case SGI_COMP_ARLE: 402 if (fOffsetTable[z][y] != 0) 403 return B_ERROR; 404 405 // First check the last row written... 406 407 if (fARLEOffset > 0) { 408 if (fBytesPerChannel == 1) { 409 uint8* arleRow = (uint8*)fARLERow; 410 uint8* src = (uint8*)row; 411 for (x = 0; x < fWidth; x++) 412 if (*src++ != *arleRow++) 413 break; 414 } else { 415 uint16* arleRow = (uint16*)fARLERow; 416 uint16* src = (uint16*)row; 417 for (x = 0; x < fWidth; x++) 418 if (*src++ != *arleRow++) 419 break; 420 } 421 422 if (x == fWidth) { 423 fOffsetTable[z][y] = fARLEOffset; 424 fLengthTable[z][y] = fARLELength; 425 return B_OK; 426 } 427 } 428 429 // If that didn't match, search all the previous rows... 430 431 fStream->Seek(fFirstRowOffset, SEEK_SET); 432 433 if (fBytesPerChannel == 1) { 434 do { 435 fARLEOffset = fStream->Position(); 436 437 uint8* arleRow = (uint8*)fARLERow; 438 if ((fARLELength = _ReadRLE8(arleRow, fWidth)) < B_OK) { 439 x = 0; 440 break; 441 } 442 443 uint8* src = (uint8*)row; 444 for (x = 0; x < fWidth; x++) 445 if (*src++ != *arleRow++) 446 break; 447 } while (x < fWidth); 448 } else { 449 do { 450 fARLEOffset = fStream->Position(); 451 452 uint16* arleRow = (uint16*)fARLERow; 453 if ((fARLELength = _ReadRLE16(arleRow, fWidth)) < B_OK) { 454 x = 0; 455 break; 456 } 457 458 uint16* src = (uint16*)row; 459 for (x = 0; x < fWidth; x++) 460 if (*src++ != *arleRow++) 461 break; 462 } while (x < fWidth); 463 } 464 465 if (x == fWidth) { 466 fOffsetTable[z][y] = fARLEOffset; 467 fLengthTable[z][y] = fARLELength; 468 return B_OK; 469 } else 470 fStream->Seek(0, SEEK_END); // seek to end of stream 471 // FALL THROUGH! 472 case SGI_COMP_RLE : 473 if (fOffsetTable[z][y] != 0) 474 return B_ERROR; 475 476 offset = fOffsetTable[z][y] = fNextRowOffset; 477 478 if (offset != fStream->Position()) 479 fStream->Seek(offset, SEEK_SET); 480 481 //printf("writing %d pixels %ld byte/channel RLE row: %ld, channel: %ld\n", fWidth, fBytesPerChannel, y, z); 482 483 if (fBytesPerChannel == 1) 484 x = _WriteRLE8((uint8*)row, fWidth); 485 else 486 x = _WriteRLE16((uint16*)row, fWidth); 487 488 if (fCompression == SGI_COMP_ARLE) { 489 fARLEOffset = offset; 490 fARLELength = x; 491 memcpy(fARLERow, row, fWidth * fBytesPerChannel); 492 } 493 494 fNextRowOffset = fStream->Position(); 495 fLengthTable[z][y] = x; 496 497 return x; 498 default: 499 break; 500 } 501 502 return ret; 503 } 504 505 // _ReadLong 506 // 507 // reads 4 bytes from the stream and 508 // returns a 32-bit big-endian integer 509 int32 510 SGIImage::_ReadLong() const 511 { 512 int32 n; 513 if (fStream->Read(&n, 4) == 4) { 514 return B_BENDIAN_TO_HOST_INT32(n); 515 } else 516 return 0; 517 } 518 519 // _ReadShort 520 // 521 // reads 2 bytes from the stream and 522 // returns a 16-bit big-endian integer 523 int16 524 SGIImage::_ReadShort() const 525 { 526 int16 n; 527 if (fStream->Read(&n, 2) == 2) { 528 return B_BENDIAN_TO_HOST_INT16(n); 529 } else 530 return 0; 531 } 532 533 // _ReadChar 534 // 535 // reads 1 byte from the stream and 536 // returns it 537 int8 538 SGIImage::_ReadChar() const 539 { 540 int8 b; 541 ssize_t read = fStream->Read(&b, 1); 542 if (read == 1) 543 return b; 544 else if (read < B_OK) 545 return (int8)read; 546 return (int8)B_ERROR; 547 } 548 549 // _WriteLong 550 // 551 // writes a 32-bit big-endian integer to the stream 552 status_t 553 SGIImage::_WriteLong(int32 n) const 554 { 555 int32 bigN = B_HOST_TO_BENDIAN_INT32(n); 556 ssize_t written = fStream->Write(&bigN, sizeof(int32)); 557 if (written == sizeof(int32)) 558 return B_OK; 559 if (written < B_OK) 560 return written; 561 return B_ERROR; 562 } 563 564 // _WriteShort 565 // 566 // writes a 16-bit big-endian integer to the stream 567 status_t 568 SGIImage::_WriteShort(uint16 n) const 569 { 570 uint16 bigN = B_HOST_TO_BENDIAN_INT16(n); 571 ssize_t written = fStream->Write(&bigN, sizeof(uint16)); 572 if (written == sizeof(uint16)) 573 return B_OK; 574 if (written < B_OK) 575 return written; 576 return B_ERROR; 577 } 578 579 // _WriteChar 580 // 581 // writes one byte to the stream 582 status_t 583 SGIImage::_WriteChar(int8 n) const 584 { 585 ssize_t written = fStream->Write(&n, sizeof(int8)); 586 if (written == sizeof(int8)) 587 return B_OK; 588 if (written < B_OK) 589 return written; 590 return B_ERROR; 591 } 592 593 // _ReadRLE8 594 // 595 // reads 8-bit RLE data into provided buffer 596 // 597 // row pointer to buffer for one row 598 // numPixels number of pixels that fit into row buffer 599 ssize_t 600 SGIImage::_ReadRLE8(uint8* row, int32 numPixels) const 601 { 602 int32 ch; // current charater 603 uint32 count; // RLE count 604 uint32 length = 0; // number of bytes read 605 606 uint32 bufferSize = 1024; 607 uint8* buffer = new uint8[bufferSize]; 608 uint32 bufferPos = bufferSize; 609 610 status_t ret = B_OK; 611 612 while (numPixels > 0) { 613 614 // fetch another buffer if we need to 615 if (bufferPos >= bufferSize) { 616 ret = fStream->Read(buffer, bufferSize); 617 if (ret < B_OK) 618 break; 619 else 620 bufferPos = 0; 621 } 622 623 ch = buffer[bufferPos ++]; 624 length ++; 625 626 count = ch & 127; 627 if (count == 0) 628 break; 629 630 if (ch & 128) { 631 for (uint32 i = 0; i < count; i++) { 632 633 // fetch another buffer if we need to 634 if (bufferPos >= bufferSize) { 635 ret = fStream->Read(buffer, bufferSize); 636 if (ret < B_OK) { 637 delete[] buffer; 638 return ret; 639 } else 640 bufferPos = 0; 641 } 642 643 *row = buffer[bufferPos ++]; 644 row ++; 645 numPixels --; 646 length ++; 647 } 648 } else { 649 650 // fetch another buffer if we need to 651 if (bufferPos >= bufferSize) { 652 ret = fStream->Read(buffer, bufferSize); 653 if (ret < B_OK) { 654 delete[] buffer; 655 return ret; 656 } else 657 bufferPos = 0; 658 } 659 660 ch = buffer[bufferPos ++]; 661 length ++; 662 for (uint32 i = 0; i < count; i++) { 663 *row = ch; 664 row ++; 665 numPixels --; 666 } 667 } 668 } 669 delete[] buffer; 670 671 return (numPixels > 0 ? ret : length); 672 } 673 674 // _ReadRLE8 675 // 676 // reads 8-bit RLE data into provided buffer 677 // 678 // row pointer to buffer for one row 679 // numPixels number of pixels that fit into row buffer 680 ssize_t 681 SGIImage::_ReadRLE8(uint8* row, uint8* rleBuffer, int32 numPixels) const 682 { 683 int32 ch; // current charater 684 uint32 count; // RLE count 685 uint32 length = 0; // number of bytes read 686 687 while (numPixels > 0) { 688 689 ch = *rleBuffer ++; 690 length ++; 691 692 count = ch & 127; 693 if (count == 0) 694 break; 695 696 if (ch & 128) { 697 for (uint32 i = 0; i < count; i++) { 698 699 *row = *rleBuffer ++; 700 row ++; 701 numPixels --; 702 length ++; 703 } 704 } else { 705 706 ch = *rleBuffer ++; 707 length ++; 708 for (uint32 i = 0; i < count; i++) { 709 *row = ch; 710 row ++; 711 numPixels --; 712 } 713 } 714 } 715 716 return (numPixels > 0 ? B_ERROR : length); 717 } 718 /*ssize_t 719 SGIImage::_ReadRLE8(uint8* row, int32 numPixels) const 720 { 721 int32 ch; // current charater 722 uint32 count; // RLE count 723 uint32 length = 0; // number of bytes read 724 725 while (numPixels > 0) { 726 ch = _ReadChar(); 727 length ++; 728 729 count = ch & 127; 730 if (count == 0) 731 break; 732 733 if (ch & 128) { 734 for (uint32 i = 0; i < count; i++) { 735 *row = _ReadChar(); 736 row ++; 737 numPixels --; 738 length ++; 739 } 740 } else { 741 ch = _ReadChar(); 742 length ++; 743 for (uint32 i = 0; i < count; i++) { 744 *row = ch; 745 row ++; 746 numPixels --; 747 } 748 } 749 } 750 return (numPixels > 0 ? B_ERROR : length); 751 }*/ 752 753 // read_and_swap 754 status_t 755 read_and_swap(BPositionIO* stream, int16* buffer, uint32 size) 756 { 757 status_t ret = stream->Read(buffer, size); 758 if (ret >= B_OK) 759 return swap_data(B_INT16_TYPE, buffer, ret, B_SWAP_BENDIAN_TO_HOST); 760 return ret; 761 } 762 763 // _ReadRLE16 764 // 765 // reads 16-bit RLE data into provided buffer 766 // 767 // row pointer to buffer for one row 768 // numPixels number of pixels that fit into row buffer 769 ssize_t 770 SGIImage::_ReadRLE16(uint16* row, int32 numPixels) const 771 { 772 int32 ch; // current character 773 uint32 count; // RLE count 774 uint32 length = 0; // number of bytes read... 775 776 uint32 bufferSize = 1024; 777 int16* buffer = new int16[bufferSize]; 778 uint32 bufferPos = bufferSize; 779 status_t ret = B_OK; 780 781 while (numPixels > 0) { 782 783 // fetch another buffer if we need to 784 if (bufferPos >= bufferSize) { 785 ret = read_and_swap(fStream, buffer, bufferSize * 2); 786 if (ret < B_OK) 787 break; 788 bufferPos = 0; 789 } 790 791 ch = buffer[bufferPos ++]; 792 length ++; 793 794 count = ch & 127; 795 if (count == 0) 796 break; 797 798 if (ch & 128) { 799 for (uint32 i = 0; i < count; i++) { 800 801 // fetch another buffer if we need to 802 if (bufferPos >= bufferSize) { 803 ret = read_and_swap(fStream, buffer, bufferSize * 2); 804 if (ret < B_OK) { 805 delete[] buffer; 806 return ret; 807 } else 808 bufferPos = 0; 809 } 810 811 *row = B_HOST_TO_BENDIAN_INT16(buffer[bufferPos ++]); 812 row++; 813 numPixels--; 814 length++; 815 } 816 } else { 817 818 // fetch another buffer if we need to 819 if (bufferPos >= bufferSize) { 820 ret = read_and_swap(fStream, buffer, bufferSize * 2); 821 if (ret < B_OK) { 822 delete[] buffer; 823 return ret; 824 } else 825 bufferPos = 0; 826 } 827 828 ch = B_HOST_TO_BENDIAN_INT16(buffer[bufferPos ++]); 829 length ++; 830 for (uint32 i = 0; i < count; i++) { 831 *row = ch; 832 row++; 833 numPixels--; 834 } 835 } 836 } 837 delete[] buffer; 838 return (numPixels > 0 ? ret : length * 2); 839 } 840 841 // _ReadRLE16 842 // 843 // reads 16-bit RLE data into provided buffer 844 // 845 // row pointer to buffer for one row 846 // numPixels number of pixels that fit into row buffer 847 ssize_t 848 SGIImage::_ReadRLE16(uint16* row, uint16* rleBuffer, int32 numPixels) const 849 { 850 int32 ch; // current character 851 uint32 count; // RLE count 852 uint32 length = 0; // number of bytes read... 853 854 while (numPixels > 0) { 855 856 ch = *rleBuffer ++; 857 length ++; 858 859 count = ch & 127; 860 if (count == 0) 861 break; 862 863 if (ch & 128) { 864 for (uint32 i = 0; i < count; i++) { 865 866 *row = B_HOST_TO_BENDIAN_INT16(*rleBuffer ++); 867 row++; 868 numPixels--; 869 length++; 870 } 871 } else { 872 873 ch = B_HOST_TO_BENDIAN_INT16(*rleBuffer ++); 874 length ++; 875 for (uint32 i = 0; i < count; i++) { 876 *row = ch; 877 row++; 878 numPixels--; 879 } 880 } 881 } 882 return (numPixels > 0 ? B_ERROR : length * 2); 883 } 884 885 // _WriteRLE8 886 // 887 // writes 8-bit RLE data into the stream 888 // 889 // row pointer to buffer for one row 890 // numPixels number of pixels that fit into row buffer 891 ssize_t 892 SGIImage::_WriteRLE8(uint8* row, int32 numPixels) const 893 { 894 int32 length = 0; // length of output line 895 int32 count; // number of repeated/non-repeated pixels 896 int32 i; // looping var 897 uint8* start; // start of sequence 898 uint16 repeat; // repeated pixel 899 900 901 for (int32 x = numPixels; x > 0;) { 902 start = row; 903 row += 2; 904 x -= 2; 905 906 while (x > 0 && (row[-2] != row[-1] || row[-1] != row[0])) { 907 row++; 908 x--; 909 } 910 911 row -= 2; 912 x += 2; 913 914 count = row - start; 915 while (count > 0) { 916 i = count > 126 ? 126 : count; 917 count -= i; 918 919 if (_WriteChar(128 | i) == EOF) 920 return EOF; 921 length ++; 922 923 while (i > 0) { 924 if (_WriteChar(*start) == EOF) 925 return EOF; 926 start ++; 927 i --; 928 length ++; 929 } 930 } 931 932 if (x <= 0) 933 break; 934 935 start = row; 936 repeat = row[0]; 937 938 row ++; 939 x --; 940 941 while (x > 0 && *row == repeat) { 942 row ++; 943 x --; 944 } 945 946 count = row - start; 947 while (count > 0) { 948 i = count > 126 ? 126 : count; 949 count -= i; 950 951 if (_WriteChar(i) == EOF) 952 return EOF; 953 length ++; 954 955 if (_WriteChar(repeat) == EOF) 956 return (-1); 957 length ++; 958 } 959 } 960 961 length ++; 962 963 if (_WriteChar(0) == EOF) 964 return EOF; 965 else 966 return length; 967 } 968 969 970 // _WriteRLE16 971 // 972 // writes 16-bit RLE data into the stream 973 // 974 // row pointer to buffer for one row 975 // numPixels number of pixels that fit into row buffer 976 ssize_t 977 SGIImage::_WriteRLE16(uint16* row, int32 numPixels) const 978 { 979 int32 length = 0; // length of output line 980 int32 count; // number of repeated/non-repeated pixels 981 int32 i; // looping var 982 int32 x; // looping var 983 uint16* start; // start of sequence 984 uint16 repeat; // repeated pixel 985 986 987 for (x = numPixels; x > 0;) { 988 start = row; 989 row += 2; 990 x -= 2; 991 992 while (x > 0 && (row[-2] != row[-1] || row[-1] != row[0])) { 993 row ++; 994 x --; 995 } 996 997 row -= 2; 998 x += 2; 999 1000 count = row - start; 1001 while (count > 0) { 1002 i = count > 126 ? 126 : count; 1003 count -= i; 1004 1005 if (_WriteShort(128 | i) == EOF) 1006 return EOF; 1007 length ++; 1008 1009 while (i > 0) { 1010 if (_WriteShort(*start) == EOF) 1011 return EOF; 1012 start ++; 1013 i --; 1014 length ++; 1015 } 1016 } 1017 1018 if (x <= 0) 1019 break; 1020 1021 start = row; 1022 repeat = row[0]; 1023 1024 row ++; 1025 x --; 1026 1027 while (x > 0 && *row == repeat) { 1028 row ++; 1029 x --; 1030 } 1031 1032 count = row - start; 1033 while (count > 0) { 1034 i = count > 126 ? 126 : count; 1035 count -= i; 1036 1037 if (_WriteShort(i) == EOF) 1038 return EOF; 1039 length ++; 1040 1041 if (_WriteShort(repeat) == EOF) 1042 return EOF; 1043 length ++; 1044 } 1045 } 1046 1047 length ++; 1048 1049 if (_WriteShort(0) == EOF) 1050 return EOF; 1051 else 1052 return (2 * length); 1053 } 1054 1055 1056