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