Image_files.cpp (20948B)
1 /* 2 =========================================================================== 3 4 Doom 3 BFG Edition GPL Source Code 5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 6 7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). 8 9 Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation, either version 3 of the License, or 12 (at your option) any later version. 13 14 Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>. 21 22 In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below. 23 24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. 25 26 =========================================================================== 27 */ 28 29 #pragma hdrstop 30 #include "../idlib/precompiled.h" 31 32 33 #include "tr_local.h" 34 35 /* 36 37 This file only has a single entry point: 38 39 void R_LoadImage( const char *name, byte **pic, int *width, int *height, bool makePowerOf2 ); 40 41 */ 42 43 /* 44 * Include file for users of JPEG library. 45 * You will need to have included system headers that define at least 46 * the typedefs FILE and size_t before you can include jpeglib.h. 47 * (stdio.h is sufficient on ANSI-conforming systems.) 48 * You may also wish to include "jerror.h". 49 */ 50 51 #include "jpeg-6/jpeglib.h" 52 53 // hooks from jpeg lib to our system 54 55 void jpg_Error( const char *fmt, ... ) { 56 va_list argptr; 57 char msg[2048]; 58 59 va_start (argptr,fmt); 60 vsprintf (msg,fmt,argptr); 61 va_end (argptr); 62 63 common->FatalError( "%s", msg ); 64 } 65 66 void jpg_Printf( const char *fmt, ... ) { 67 va_list argptr; 68 char msg[2048]; 69 70 va_start (argptr,fmt); 71 vsprintf (msg,fmt,argptr); 72 va_end (argptr); 73 74 common->Printf( "%s", msg ); 75 } 76 77 78 79 /* 80 ================ 81 R_WriteTGA 82 ================ 83 */ 84 void R_WriteTGA( const char *filename, const byte *data, int width, int height, bool flipVertical, const char * basePath ) { 85 byte *buffer; 86 int i; 87 int bufferSize = width*height*4 + 18; 88 int imgStart = 18; 89 90 idTempArray<byte> buf( bufferSize ); 91 buffer = (byte *)buf.Ptr(); 92 memset( buffer, 0, 18 ); 93 buffer[2] = 2; // uncompressed type 94 buffer[12] = width&255; 95 buffer[13] = width>>8; 96 buffer[14] = height&255; 97 buffer[15] = height>>8; 98 buffer[16] = 32; // pixel size 99 if ( !flipVertical ) { 100 buffer[17] = (1<<5); // flip bit, for normal top to bottom raster order 101 } 102 103 // swap rgb to bgr 104 for ( i=imgStart ; i<bufferSize ; i+=4 ) { 105 buffer[i] = data[i-imgStart+2]; // blue 106 buffer[i+1] = data[i-imgStart+1]; // green 107 buffer[i+2] = data[i-imgStart+0]; // red 108 buffer[i+3] = data[i-imgStart+3]; // alpha 109 } 110 111 fileSystem->WriteFile( filename, buffer, bufferSize, basePath ); 112 } 113 114 static void LoadTGA( const char *name, byte **pic, int *width, int *height, ID_TIME_T *timestamp ); 115 static void LoadJPG( const char *name, byte **pic, int *width, int *height, ID_TIME_T *timestamp ); 116 117 /* 118 ======================================================================== 119 120 TGA files are used for 24/32 bit images 121 122 ======================================================================== 123 */ 124 125 typedef struct _TargaHeader { 126 unsigned char id_length, colormap_type, image_type; 127 unsigned short colormap_index, colormap_length; 128 unsigned char colormap_size; 129 unsigned short x_origin, y_origin, width, height; 130 unsigned char pixel_size, attributes; 131 } TargaHeader; 132 133 134 /* 135 ========================================================= 136 137 TARGA LOADING 138 139 ========================================================= 140 */ 141 142 /* 143 ============= 144 LoadTGA 145 ============= 146 */ 147 static void LoadTGA( const char *name, byte **pic, int *width, int *height, ID_TIME_T *timestamp ) { 148 int columns, rows, numPixels, fileSize, numBytes; 149 byte *pixbuf; 150 int row, column; 151 byte *buf_p; 152 byte *buffer; 153 TargaHeader targa_header; 154 byte *targa_rgba; 155 156 if ( !pic ) { 157 fileSystem->ReadFile( name, NULL, timestamp ); 158 return; // just getting timestamp 159 } 160 161 *pic = NULL; 162 163 // 164 // load the file 165 // 166 fileSize = fileSystem->ReadFile( name, (void **)&buffer, timestamp ); 167 if ( !buffer ) { 168 return; 169 } 170 171 buf_p = buffer; 172 173 targa_header.id_length = *buf_p++; 174 targa_header.colormap_type = *buf_p++; 175 targa_header.image_type = *buf_p++; 176 177 targa_header.colormap_index = LittleShort ( *(short *)buf_p ); 178 buf_p += 2; 179 targa_header.colormap_length = LittleShort ( *(short *)buf_p ); 180 buf_p += 2; 181 targa_header.colormap_size = *buf_p++; 182 targa_header.x_origin = LittleShort ( *(short *)buf_p ); 183 buf_p += 2; 184 targa_header.y_origin = LittleShort ( *(short *)buf_p ); 185 buf_p += 2; 186 targa_header.width = LittleShort ( *(short *)buf_p ); 187 buf_p += 2; 188 targa_header.height = LittleShort ( *(short *)buf_p ); 189 buf_p += 2; 190 targa_header.pixel_size = *buf_p++; 191 targa_header.attributes = *buf_p++; 192 193 if ( targa_header.image_type != 2 && targa_header.image_type != 10 && targa_header.image_type != 3 ) { 194 common->Error( "LoadTGA( %s ): Only type 2 (RGB), 3 (gray), and 10 (RGB) TGA images supported\n", name ); 195 } 196 197 if ( targa_header.colormap_type != 0 ) { 198 common->Error( "LoadTGA( %s ): colormaps not supported\n", name ); 199 } 200 201 if ( ( targa_header.pixel_size != 32 && targa_header.pixel_size != 24 ) && targa_header.image_type != 3 ) { 202 common->Error( "LoadTGA( %s ): Only 32 or 24 bit images supported (no colormaps)\n", name ); 203 } 204 205 if ( targa_header.image_type == 2 || targa_header.image_type == 3 ) { 206 numBytes = targa_header.width * targa_header.height * ( targa_header.pixel_size >> 3 ); 207 if ( numBytes > fileSize - 18 - targa_header.id_length ) { 208 common->Error( "LoadTGA( %s ): incomplete file\n", name ); 209 } 210 } 211 212 columns = targa_header.width; 213 rows = targa_header.height; 214 numPixels = columns * rows; 215 216 if ( width ) { 217 *width = columns; 218 } 219 if ( height ) { 220 *height = rows; 221 } 222 223 targa_rgba = (byte *)R_StaticAlloc(numPixels*4, TAG_IMAGE); 224 *pic = targa_rgba; 225 226 if ( targa_header.id_length != 0 ) { 227 buf_p += targa_header.id_length; // skip TARGA image comment 228 } 229 230 if ( targa_header.image_type == 2 || targa_header.image_type == 3 ) 231 { 232 // Uncompressed RGB or gray scale image 233 for( row = rows - 1; row >= 0; row-- ) 234 { 235 pixbuf = targa_rgba + row*columns*4; 236 for( column = 0; column < columns; column++) 237 { 238 unsigned char red,green,blue,alphabyte; 239 switch( targa_header.pixel_size ) 240 { 241 242 case 8: 243 blue = *buf_p++; 244 green = blue; 245 red = blue; 246 *pixbuf++ = red; 247 *pixbuf++ = green; 248 *pixbuf++ = blue; 249 *pixbuf++ = 255; 250 break; 251 252 case 24: 253 blue = *buf_p++; 254 green = *buf_p++; 255 red = *buf_p++; 256 *pixbuf++ = red; 257 *pixbuf++ = green; 258 *pixbuf++ = blue; 259 *pixbuf++ = 255; 260 break; 261 case 32: 262 blue = *buf_p++; 263 green = *buf_p++; 264 red = *buf_p++; 265 alphabyte = *buf_p++; 266 *pixbuf++ = red; 267 *pixbuf++ = green; 268 *pixbuf++ = blue; 269 *pixbuf++ = alphabyte; 270 break; 271 default: 272 common->Error( "LoadTGA( %s ): illegal pixel_size '%d'\n", name, targa_header.pixel_size ); 273 break; 274 } 275 } 276 } 277 } 278 else if ( targa_header.image_type == 10 ) { // Runlength encoded RGB images 279 unsigned char red,green,blue,alphabyte,packetHeader,packetSize,j; 280 281 red = 0; 282 green = 0; 283 blue = 0; 284 alphabyte = 0xff; 285 286 for( row = rows - 1; row >= 0; row-- ) { 287 pixbuf = targa_rgba + row*columns*4; 288 for( column = 0; column < columns; ) { 289 packetHeader= *buf_p++; 290 packetSize = 1 + (packetHeader & 0x7f); 291 if ( packetHeader & 0x80 ) { // run-length packet 292 switch( targa_header.pixel_size ) { 293 case 24: 294 blue = *buf_p++; 295 green = *buf_p++; 296 red = *buf_p++; 297 alphabyte = 255; 298 break; 299 case 32: 300 blue = *buf_p++; 301 green = *buf_p++; 302 red = *buf_p++; 303 alphabyte = *buf_p++; 304 break; 305 default: 306 common->Error( "LoadTGA( %s ): illegal pixel_size '%d'\n", name, targa_header.pixel_size ); 307 break; 308 } 309 310 for( j = 0; j < packetSize; j++ ) { 311 *pixbuf++=red; 312 *pixbuf++=green; 313 *pixbuf++=blue; 314 *pixbuf++=alphabyte; 315 column++; 316 if ( column == columns ) { // run spans across rows 317 column = 0; 318 if ( row > 0) { 319 row--; 320 } 321 else { 322 goto breakOut; 323 } 324 pixbuf = targa_rgba + row*columns*4; 325 } 326 } 327 } 328 else { // non run-length packet 329 for( j = 0; j < packetSize; j++ ) { 330 switch( targa_header.pixel_size ) { 331 case 24: 332 blue = *buf_p++; 333 green = *buf_p++; 334 red = *buf_p++; 335 *pixbuf++ = red; 336 *pixbuf++ = green; 337 *pixbuf++ = blue; 338 *pixbuf++ = 255; 339 break; 340 case 32: 341 blue = *buf_p++; 342 green = *buf_p++; 343 red = *buf_p++; 344 alphabyte = *buf_p++; 345 *pixbuf++ = red; 346 *pixbuf++ = green; 347 *pixbuf++ = blue; 348 *pixbuf++ = alphabyte; 349 break; 350 default: 351 common->Error( "LoadTGA( %s ): illegal pixel_size '%d'\n", name, targa_header.pixel_size ); 352 break; 353 } 354 column++; 355 if ( column == columns ) { // pixel packet run spans across rows 356 column = 0; 357 if ( row > 0 ) { 358 row--; 359 } 360 else { 361 goto breakOut; 362 } 363 pixbuf = targa_rgba + row*columns*4; 364 } 365 } 366 } 367 } 368 breakOut: ; 369 } 370 } 371 372 if ( (targa_header.attributes & (1<<5)) ) { // image flp bit 373 if ( width != NULL && height != NULL ) { 374 R_VerticalFlip( *pic, *width, *height ); 375 } 376 } 377 378 fileSystem->FreeFile( buffer ); 379 } 380 381 /* 382 ========================================================= 383 384 JPG LOADING 385 386 Interfaces with the huge libjpeg 387 ========================================================= 388 */ 389 390 /* 391 ============= 392 LoadJPG 393 ============= 394 */ 395 static void LoadJPG( const char *filename, unsigned char **pic, int *width, int *height, ID_TIME_T *timestamp ) { 396 /* This struct contains the JPEG decompression parameters and pointers to 397 * working space (which is allocated as needed by the JPEG library). 398 */ 399 struct jpeg_decompress_struct cinfo; 400 /* We use our private extension JPEG error handler. 401 * Note that this struct must live as long as the main JPEG parameter 402 * struct, to avoid dangling-pointer problems. 403 */ 404 /* This struct represents a JPEG error handler. It is declared separately 405 * because applications often want to supply a specialized error handler 406 * (see the second half of this file for an example). But here we just 407 * take the easy way out and use the standard error handler, which will 408 * print a message on stderr and call exit() if compression fails. 409 * Note that this struct must live as long as the main JPEG parameter 410 * struct, to avoid dangling-pointer problems. 411 */ 412 struct jpeg_error_mgr jerr; 413 /* More stuff */ 414 JSAMPARRAY buffer; /* Output row buffer */ 415 int row_stride; /* physical row width in output buffer */ 416 unsigned char *out; 417 byte *fbuffer; 418 byte *bbuf; 419 420 /* In this example we want to open the input file before doing anything else, 421 * so that the setjmp() error recovery below can assume the file is open. 422 * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that 423 * requires it in order to read binary files. 424 */ 425 426 // JDC: because fill_input_buffer() blindly copies INPUT_BUF_SIZE bytes, 427 // we need to make sure the file buffer is padded or it may crash 428 if ( pic ) { 429 *pic = NULL; // until proven otherwise 430 } 431 { 432 int len; 433 idFile *f; 434 435 f = fileSystem->OpenFileRead( filename ); 436 if ( !f ) { 437 return; 438 } 439 len = f->Length(); 440 if ( timestamp ) { 441 *timestamp = f->Timestamp(); 442 } 443 if ( !pic ) { 444 fileSystem->CloseFile( f ); 445 return; // just getting timestamp 446 } 447 fbuffer = (byte *)Mem_ClearedAlloc( len + 4096, TAG_JPG ); 448 f->Read( fbuffer, len ); 449 fileSystem->CloseFile( f ); 450 } 451 452 453 /* Step 1: allocate and initialize JPEG decompression object */ 454 455 /* We have to set up the error handler first, in case the initialization 456 * step fails. (Unlikely, but it could happen if you are out of memory.) 457 * This routine fills in the contents of struct jerr, and returns jerr's 458 * address which we place into the link field in cinfo. 459 */ 460 cinfo.err = jpeg_std_error(&jerr); 461 462 /* Now we can initialize the JPEG decompression object. */ 463 jpeg_create_decompress(&cinfo); 464 465 /* Step 2: specify data source (eg, a file) */ 466 467 jpeg_stdio_src(&cinfo, fbuffer); 468 469 /* Step 3: read file parameters with jpeg_read_header() */ 470 471 (void) jpeg_read_header(&cinfo, true ); 472 /* We can ignore the return value from jpeg_read_header since 473 * (a) suspension is not possible with the stdio data source, and 474 * (b) we passed TRUE to reject a tables-only JPEG file as an error. 475 * See libjpeg.doc for more info. 476 */ 477 478 /* Step 4: set parameters for decompression */ 479 480 /* In this example, we don't need to change any of the defaults set by 481 * jpeg_read_header(), so we do nothing here. 482 */ 483 484 /* Step 5: Start decompressor */ 485 486 (void) jpeg_start_decompress(&cinfo); 487 /* We can ignore the return value since suspension is not possible 488 * with the stdio data source. 489 */ 490 491 /* We may need to do some setup of our own at this point before reading 492 * the data. After jpeg_start_decompress() we have the correct scaled 493 * output image dimensions available, as well as the output colormap 494 * if we asked for color quantization. 495 * In this example, we need to make an output work buffer of the right size. 496 */ 497 /* JSAMPLEs per row in output buffer */ 498 row_stride = cinfo.output_width * cinfo.output_components; 499 500 if (cinfo.output_components!=4) { 501 common->DWarning( "JPG %s is unsupported color depth (%d)", 502 filename, cinfo.output_components); 503 } 504 out = (byte *)R_StaticAlloc(cinfo.output_width*cinfo.output_height*4, TAG_IMAGE); 505 506 *pic = out; 507 *width = cinfo.output_width; 508 *height = cinfo.output_height; 509 510 /* Step 6: while (scan lines remain to be read) */ 511 /* jpeg_read_scanlines(...); */ 512 513 /* Here we use the library's state variable cinfo.output_scanline as the 514 * loop counter, so that we don't have to keep track ourselves. 515 */ 516 while (cinfo.output_scanline < cinfo.output_height) { 517 /* jpeg_read_scanlines expects an array of pointers to scanlines. 518 * Here the array is only one element long, but you could ask for 519 * more than one scanline at a time if that's more convenient. 520 */ 521 bbuf = ((out+(row_stride*cinfo.output_scanline))); 522 buffer = &bbuf; 523 (void) jpeg_read_scanlines(&cinfo, buffer, 1); 524 } 525 526 // clear all the alphas to 255 527 { 528 int i, j; 529 byte *buf; 530 531 buf = *pic; 532 533 j = cinfo.output_width * cinfo.output_height * 4; 534 for ( i = 3 ; i < j ; i+=4 ) { 535 buf[i] = 255; 536 } 537 } 538 539 /* Step 7: Finish decompression */ 540 541 (void) jpeg_finish_decompress(&cinfo); 542 /* We can ignore the return value since suspension is not possible 543 * with the stdio data source. 544 */ 545 546 /* Step 8: Release JPEG decompression object */ 547 548 /* This is an important step since it will release a good deal of memory. */ 549 jpeg_destroy_decompress(&cinfo); 550 551 /* After finish_decompress, we can close the input file. 552 * Here we postpone it until after no more JPEG errors are possible, 553 * so as to simplify the setjmp error logic above. (Actually, I don't 554 * think that jpeg_destroy can do an error exit, but why assume anything...) 555 */ 556 Mem_Free( fbuffer ); 557 558 /* At this point you may want to check to see whether any corrupt-data 559 * warnings occurred (test whether jerr.pub.num_warnings is nonzero). 560 */ 561 562 /* And we're done! */ 563 } 564 565 //=================================================================== 566 567 /* 568 ================= 569 R_LoadImage 570 571 Loads any of the supported image types into a cannonical 572 32 bit format. 573 574 Automatically attempts to load .jpg files if .tga files fail to load. 575 576 *pic will be NULL if the load failed. 577 578 Anything that is going to make this into a texture would use 579 makePowerOf2 = true, but something loading an image as a lookup 580 table of some sort would leave it in identity form. 581 582 It is important to do this at image load time instead of texture load 583 time for bump maps. 584 585 Timestamp may be NULL if the value is going to be ignored 586 587 If pic is NULL, the image won't actually be loaded, it will just find the 588 timestamp. 589 ================= 590 */ 591 void R_LoadImage( const char *cname, byte **pic, int *width, int *height, ID_TIME_T *timestamp, bool makePowerOf2 ) { 592 idStr name = cname; 593 594 if ( pic ) { 595 *pic = NULL; 596 } 597 if ( timestamp ) { 598 *timestamp = FILE_NOT_FOUND_TIMESTAMP; 599 } 600 if ( width ) { 601 *width = 0; 602 } 603 if ( height ) { 604 *height = 0; 605 } 606 607 name.DefaultFileExtension( ".tga" ); 608 609 if (name.Length()<5) { 610 return; 611 } 612 613 name.ToLower(); 614 idStr ext; 615 name.ExtractFileExtension( ext ); 616 617 if ( ext == "tga" ) { 618 LoadTGA( name.c_str(), pic, width, height, timestamp ); // try tga first 619 if ( ( pic && *pic == 0 ) || ( timestamp && *timestamp == -1 ) ) { //-V595 620 name.StripFileExtension(); 621 name.DefaultFileExtension( ".jpg" ); 622 LoadJPG( name.c_str(), pic, width, height, timestamp ); 623 } 624 } else if ( ext == "jpg" ) { 625 LoadJPG( name.c_str(), pic, width, height, timestamp ); 626 } 627 628 if ( ( width && *width < 1 ) || ( height && *height < 1 ) ) { 629 if ( pic && *pic ) { 630 R_StaticFree( *pic ); 631 *pic = 0; 632 } 633 } 634 635 // 636 // convert to exact power of 2 sizes 637 // 638 /* 639 if ( pic && *pic && makePowerOf2 ) { 640 int w, h; 641 int scaled_width, scaled_height; 642 byte *resampledBuffer; 643 644 w = *width; 645 h = *height; 646 647 for (scaled_width = 1 ; scaled_width < w ; scaled_width<<=1) 648 ; 649 for (scaled_height = 1 ; scaled_height < h ; scaled_height<<=1) 650 ; 651 652 if ( scaled_width != w || scaled_height != h ) { 653 resampledBuffer = R_ResampleTexture( *pic, w, h, scaled_width, scaled_height ); 654 R_StaticFree( *pic ); 655 *pic = resampledBuffer; 656 *width = scaled_width; 657 *height = scaled_height; 658 } 659 } 660 */ 661 } 662 663 664 /* 665 ======================= 666 R_LoadCubeImages 667 668 Loads six files with proper extensions 669 ======================= 670 */ 671 bool R_LoadCubeImages( const char *imgName, cubeFiles_t extensions, byte *pics[6], int *outSize, ID_TIME_T *timestamp ) { 672 int i, j; 673 char *cameraSides[6] = { "_forward.tga", "_back.tga", "_left.tga", "_right.tga", 674 "_up.tga", "_down.tga" }; 675 char *axisSides[6] = { "_px.tga", "_nx.tga", "_py.tga", "_ny.tga", 676 "_pz.tga", "_nz.tga" }; 677 char **sides; 678 char fullName[MAX_IMAGE_NAME]; 679 int width, height, size = 0; 680 681 if ( extensions == CF_CAMERA ) { 682 sides = cameraSides; 683 } else { 684 sides = axisSides; 685 } 686 687 // FIXME: precompressed cube map files 688 if ( pics ) { 689 memset( pics, 0, 6*sizeof(pics[0]) ); 690 } 691 if ( timestamp ) { 692 *timestamp = 0; 693 } 694 695 for ( i = 0 ; i < 6 ; i++ ) { 696 idStr::snPrintf( fullName, sizeof( fullName ), "%s%s", imgName, sides[i] ); 697 698 ID_TIME_T thisTime; 699 if ( !pics ) { 700 // just checking timestamps 701 R_LoadImageProgram( fullName, NULL, &width, &height, &thisTime ); 702 } else { 703 R_LoadImageProgram( fullName, &pics[i], &width, &height, &thisTime ); 704 } 705 if ( thisTime == FILE_NOT_FOUND_TIMESTAMP ) { 706 break; 707 } 708 if ( i == 0 ) { 709 size = width; 710 } 711 if ( width != size || height != size ) { 712 common->Warning( "Mismatched sizes on cube map '%s'", imgName ); 713 break; 714 } 715 if ( timestamp ) { 716 if ( thisTime > *timestamp ) { 717 *timestamp = thisTime; 718 } 719 } 720 if ( pics && extensions == CF_CAMERA ) { 721 // convert from "camera" images to native cube map images 722 switch( i ) { 723 case 0: // forward 724 R_RotatePic( pics[i], width); 725 break; 726 case 1: // back 727 R_RotatePic( pics[i], width); 728 R_HorizontalFlip( pics[i], width, height ); 729 R_VerticalFlip( pics[i], width, height ); 730 break; 731 case 2: // left 732 R_VerticalFlip( pics[i], width, height ); 733 break; 734 case 3: // right 735 R_HorizontalFlip( pics[i], width, height ); 736 break; 737 case 4: // up 738 R_RotatePic( pics[i], width); 739 break; 740 case 5: // down 741 R_RotatePic( pics[i], width); 742 break; 743 } 744 } 745 } 746 747 if ( i != 6 ) { 748 // we had an error, so free everything 749 if ( pics ) { 750 for ( j = 0 ; j < i ; j++ ) { 751 R_StaticFree( pics[j] ); 752 } 753 } 754 755 if ( timestamp ) { 756 *timestamp = 0; 757 } 758 return false; 759 } 760 761 if ( outSize ) { 762 *outSize = size; 763 } 764 return true; 765 }