1 /* 2 * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <setjmp.h> 29 #include <assert.h> 30 #include <string.h> 31 32 #include "jni.h" 33 34 #include "com_sun_javafx_iio_jpeg_JPEGImageLoader.h" 35 36 /* headers from libjpeg */ 37 #include <jpeglib.h> 38 #include <jerror.h> 39 40 #if defined (_LP64) || defined(_WIN64) 41 #define jlong_to_ptr(a) ((void*)(a)) 42 #define ptr_to_jlong(a) ((jlong)(a)) 43 #else 44 #define jlong_to_ptr(a) ((void*)(int)(a)) 45 #define ptr_to_jlong(a) ((jlong)(int)(a)) 46 #endif 47 48 /* On non iOS platforms we use JNI_OnLoad() shared library entrypoint. */ 49 #define USING_BUILTIN_LIBRARY_ENTRYPOINT 0 50 51 /* On iOS we use builtin libraries, thus JNI_OnLoad_javafx_iio() is the entrypoint */ 52 #ifdef __APPLE__ 53 54 #include <TargetConditionals.h> 55 56 /* RT-37125: use setjmp/longjmp versions that do not save/restore the signal mask */ 57 #define longjmp _longjmp 58 #define setjmp _setjmp 59 60 #if TARGET_OS_IPHONE /* iOS */ 61 #undef USING_BUILTIN_LIBRARY_ENTRYPOINT 62 #define USING_BUILTIN_LIBRARY_ENTRYPOINT 1 63 #endif 64 #endif 65 66 static jboolean checkAndClearException(JNIEnv *env) { 67 if (!(*env)->ExceptionCheck(env)) { 68 return JNI_FALSE; 69 } 70 (*env)->ExceptionClear(env); 71 return JNI_TRUE; 72 } 73 74 /***************** Begin verbatim copy from jni_util.c ***************/ 75 76 /** 77 * Throw a Java exception by name. Similar to SignalError. 78 */ 79 JNIEXPORT void JNICALL 80 ThrowByName(JNIEnv *env, const char *name, const char *msg) { 81 jclass cls = (*env)->FindClass(env, name); 82 if (!(*env)->ExceptionCheck(env) && cls != 0) {/* Otherwise an exception has already been thrown */ 83 (*env)->ThrowNew(env, cls, msg); 84 } 85 } 86 87 JNIEXPORT void * JNICALL 88 GetEnv(JavaVM *vm, jint version) { 89 void *env; 90 (*vm)->GetEnv(vm, &env, version); 91 return env; 92 } 93 94 /***************** Begin verbatim copy from jni_util.c ***************/ 95 96 #undef MAX 97 #define MAX(a,b) ((a) > (b) ? (a) : (b)) 98 99 /* Cached Java method IDs */ 100 static jmethodID InputStream_readID; 101 static jmethodID InputStream_skipID; 102 static jmethodID JPEGImageLoader_setInputAttributesID; 103 static jmethodID JPEGImageLoader_setOutputAttributesID; 104 static jmethodID JPEGImageLoader_updateImageProgressID; 105 static jmethodID JPEGImageLoader_emitWarningID; 106 107 /* Initialize the Java VM instance variable when the library is 108 first loaded */ 109 static JavaVM *jvm; 110 111 #if USING_BUILTIN_LIBRARY_ENTRYPOINT 112 113 JNIEXPORT jint JNICALL 114 JNI_OnLoad_javafx_iio(JavaVM *vm, void *reserved) { 115 jvm = vm; 116 #ifdef JNI_VERSION_1_8 117 //min. returned JNI_VERSION required by JDK8 for builtin libraries 118 JNIEnv *env; 119 if ((*vm)->GetEnv(vm, (void **)&env, JNI_VERSION_1_8) != JNI_OK) { 120 return JNI_VERSION_1_2; 121 } 122 return JNI_VERSION_1_8; 123 #else 124 return JNI_VERSION_1_2; 125 #endif 126 } 127 128 #else 129 130 JNIEXPORT jint JNICALL 131 JNI_OnLoad(JavaVM *vm, void *reserved) { 132 jvm = vm; 133 return JNI_VERSION_1_2; 134 } 135 136 #endif 137 138 139 /* 140 * The following sets of defines must match the warning messages in the 141 * Java code. 142 */ 143 144 /* Loader warnings */ 145 #define READ_NO_EOI 0 146 147 /* Saver warnings */ 148 149 /* Return codes for various ops */ 150 #define OK 1 151 #define NOT_OK 0 152 153 /* 154 * First we define two objects, one for the stream and buffer and one 155 * for pixels. Both contain references to Java objects and pointers to 156 * pinned arrays. These objects can be used for either input or 157 * output. Pixels can be accessed as either INT32s or bytes. 158 * Every I/O operation will have one of each these objects, one for 159 * the stream and the other to hold pixels, regardless of the I/O direction. 160 */ 161 162 /******************** StreamBuffer definition ************************/ 163 164 typedef struct streamBufferStruct { 165 jobject stream; // ImageInputStream or ImageOutputStream 166 jbyteArray hstreamBuffer; // Handle to a Java buffer for the stream 167 JOCTET *buf; // Pinned buffer pointer */ 168 int bufferOffset; // holds offset between unpin and the next pin 169 int bufferLength; // Allocated, nut just used 170 int suspendable; // Set to true to suspend input 171 long remaining_skip; // Used only on input 172 } streamBuffer, *streamBufferPtr; 173 174 /* 175 * This buffer size was set to 64K in the old classes, 4K by default in the 176 * IJG library, with the comment "an efficiently freadable size", and 1K 177 * in AWT. 178 * Unlike in the other Java designs, these objects will persist, so 64K 179 * seems too big and 1K seems too small. If 4K was good enough for the 180 * IJG folks, it's good enough for me. 181 */ 182 #define STREAMBUF_SIZE 4096 183 184 /* 185 * Used to signal that no data need be restored from an unpin to a pin. 186 * I.e. the buffer is empty. 187 */ 188 #define NO_DATA -1 189 190 // Forward reference 191 static void resetStreamBuffer(JNIEnv *env, streamBufferPtr sb); 192 193 /* 194 * Initialize a freshly allocated StreamBuffer object. The stream is left 195 * null, as it will be set from Java by setSource, but the buffer object 196 * is created and a global reference kept. Returns OK on success, NOT_OK 197 * if allocating the buffer or getting a global reference for it failed. 198 */ 199 static int initStreamBuffer(JNIEnv *env, streamBufferPtr sb) { 200 /* Initialize a new buffer */ 201 jbyteArray hInputBuffer = (*env)->NewByteArray(env, STREAMBUF_SIZE); 202 if (hInputBuffer == NULL) { 203 return NOT_OK; 204 } 205 sb->bufferLength = (*env)->GetArrayLength(env, hInputBuffer); 206 sb->hstreamBuffer = (*env)->NewGlobalRef(env, hInputBuffer); 207 if (sb->hstreamBuffer == NULL) { 208 return NOT_OK; 209 } 210 211 212 sb->stream = NULL; 213 214 sb->buf = NULL; 215 216 resetStreamBuffer(env, sb); 217 218 return OK; 219 } 220 221 /* 222 * Free all resources associated with this streamBuffer. This must 223 * be called to dispose the object to avoid leaking global references, as 224 * resetStreamBuffer does not release the buffer reference. 225 */ 226 static void destroyStreamBuffer(JNIEnv *env, streamBufferPtr sb) { 227 resetStreamBuffer(env, sb); 228 if (sb->hstreamBuffer != NULL) { 229 (*env)->DeleteGlobalRef(env, sb->hstreamBuffer); 230 } 231 } 232 233 // Forward reference 234 static void unpinStreamBuffer(JNIEnv *env, 235 streamBufferPtr sb, 236 const JOCTET *next_byte); 237 238 /* 239 * Resets the state of a streamBuffer object that has been in use. 240 * The global reference to the stream is released, but the reference 241 * to the buffer is retained. The buffer is unpinned if it was pinned. 242 * All other state is reset. 243 */ 244 static void resetStreamBuffer(JNIEnv *env, streamBufferPtr sb) { 245 if (sb->stream != NULL) { 246 (*env)->DeleteGlobalRef(env, sb->stream); 247 sb->stream = NULL; 248 } 249 unpinStreamBuffer(env, sb, NULL); 250 sb->bufferOffset = NO_DATA; 251 sb->suspendable = FALSE; 252 sb->remaining_skip = 0; 253 } 254 255 /* 256 * Pins the data buffer associated with this stream. Returns OK on 257 * success, NOT_OK on failure, as GetPrimitiveArrayCritical may fail. 258 */ 259 static int pinStreamBuffer(JNIEnv *env, 260 streamBufferPtr sb, 261 const JOCTET **next_byte) { 262 if (sb->hstreamBuffer != NULL) { 263 assert(sb->buf == NULL); 264 sb->buf = 265 (JOCTET *) (*env)->GetPrimitiveArrayCritical(env, 266 sb->hstreamBuffer, 267 NULL); 268 if (sb->buf == NULL) { 269 return NOT_OK; 270 } 271 if (sb->bufferOffset != NO_DATA) { 272 *next_byte = sb->buf + sb->bufferOffset; 273 } 274 } 275 return OK; 276 } 277 278 /* 279 * Unpins the data buffer associated with this stream. 280 */ 281 static void unpinStreamBuffer(JNIEnv *env, 282 streamBufferPtr sb, 283 const JOCTET *next_byte) { 284 if (sb->buf != NULL) { 285 assert(sb->hstreamBuffer != NULL); 286 if (next_byte == NULL) { 287 sb->bufferOffset = NO_DATA; 288 } else { 289 sb->bufferOffset = next_byte - sb->buf; 290 } 291 (*env)->ReleasePrimitiveArrayCritical(env, 292 sb->hstreamBuffer, 293 sb->buf, 294 0); 295 sb->buf = NULL; 296 } 297 } 298 299 /* 300 * Clear out the streamBuffer. This just invalidates the data in the buffer. 301 */ 302 static void clearStreamBuffer(streamBufferPtr sb) { 303 sb->bufferOffset = NO_DATA; 304 } 305 306 /*************************** end StreamBuffer definition *************/ 307 308 /*************************** Pixel Buffer definition ******************/ 309 310 typedef struct pixelBufferStruct { 311 jobject hpixelObject; // Usually a DataBuffer bank as a byte array 312 313 union pixptr { 314 INT32 *ip; // Pinned buffer pointer, as 32-bit ints 315 unsigned char *bp; // Pinned buffer pointer, as bytes 316 } buf; 317 } pixelBuffer, *pixelBufferPtr; 318 319 /* 320 * Initialize a freshly allocated PixelBuffer. All fields are simply 321 * set to NULL, as we have no idea what size buffer we will need. 322 */ 323 static void initPixelBuffer(pixelBufferPtr pb) { 324 pb->hpixelObject = NULL; 325 pb->buf.ip = NULL; 326 } 327 328 /* 329 * Set the pixelBuffer to use the given buffer, acquiring a new global 330 * reference for it. Returns OK on success, NOT_OK on failure. 331 */ 332 static int setPixelBuffer(JNIEnv *env, pixelBufferPtr pb, jobject obj) { 333 pb->hpixelObject = (*env)->NewGlobalRef(env, obj); 334 335 if (pb->hpixelObject == NULL) { 336 ThrowByName(env, 337 "java/lang/OutOfMemoryError", 338 "Setting Pixel Buffer"); 339 return NOT_OK; 340 } 341 return OK; 342 } 343 344 // Forward reference 345 static void unpinPixelBuffer(JNIEnv *env, pixelBufferPtr pb); 346 347 /* 348 * Resets a pixel buffer to its initial state. Unpins any pixel buffer, 349 * releases the global reference, and resets fields to NULL. Use this 350 * method to dispose the object as well (there is no destroyPixelBuffer). 351 */ 352 static void resetPixelBuffer(JNIEnv *env, pixelBufferPtr pb) { 353 if (pb->hpixelObject != NULL) { 354 unpinPixelBuffer(env, pb); 355 (*env)->DeleteGlobalRef(env, pb->hpixelObject); 356 pb->hpixelObject = NULL; 357 } 358 } 359 360 /* 361 * Pins the data buffer. Returns OK on success, NOT_OK on failure. 362 */ 363 static int pinPixelBuffer(JNIEnv *env, pixelBufferPtr pb) { 364 if (pb->hpixelObject != NULL) { 365 assert(pb->buf.ip == NULL); 366 pb->buf.bp = (unsigned char *) (*env)->GetPrimitiveArrayCritical 367 (env, pb->hpixelObject, NULL); 368 if (pb->buf.bp == NULL) { 369 return NOT_OK; 370 } 371 } 372 return OK; 373 } 374 375 /* 376 * Unpins the data buffer. 377 */ 378 static void unpinPixelBuffer(JNIEnv *env, pixelBufferPtr pb) { 379 380 if (pb->buf.ip != NULL) { 381 assert(pb->hpixelObject != NULL); 382 (*env)->ReleasePrimitiveArrayCritical(env, 383 pb->hpixelObject, 384 pb->buf.ip, 385 0); 386 pb->buf.ip = NULL; 387 } 388 } 389 390 /********************* end PixelBuffer definition *******************/ 391 392 /********************* ImageIOData definition ***********************/ 393 394 #define MAX_BANDS 4 395 #define JPEG_BAND_SIZE 8 396 #define NUM_BAND_VALUES (1<<JPEG_BAND_SIZE) 397 #define MAX_JPEG_BAND_VALUE (NUM_BAND_VALUES-1) 398 #define HALF_MAX_JPEG_BAND_VALUE (MAX_JPEG_BAND_VALUE>>1) 399 400 /* The number of possible incoming values to be scaled. */ 401 #define NUM_INPUT_VALUES (1 << 16) 402 403 /* 404 * The principal imageioData object, opaque to I/O direction. 405 * Each JPEGImageReader will have associated with it a 406 * jpeg_decompress_struct, and similarly each JPEGImageWriter will 407 * have associated with it a jpeg_compress_struct. In order to 408 * ensure that these associations persist from one native call to 409 * the next, and to provide a central locus of imageio-specific 410 * data, we define an imageioData struct containing references 411 * to the Java object and the IJG structs. The functions 412 * that manipulate these objects know whether input or output is being 413 * performed and therefore know how to manipulate the contents correctly. 414 * If for some reason they don't, the direction can be determined by 415 * checking the is_decompressor field of the jpegObj. 416 * In order for lower level code to determine a 417 * Java object given an IJG struct, such as for dispatching warnings, 418 * we use the client_data field of the jpeg object to store a pointer 419 * to the imageIOData object. Maintenance of this pointer is performed 420 * exclusively within the following access functions. If you 421 * change that, you run the risk of dangling pointers. 422 */ 423 typedef struct imageIODataStruct { 424 j_common_ptr jpegObj; // Either struct is fine 425 jobject imageIOobj; // A JPEGImageLoader 426 427 streamBuffer streamBuf; // Buffer for the stream 428 pixelBuffer pixelBuf; // Buffer for pixels 429 430 jboolean abortFlag; // Passed down from Java abort method 431 } imageIOData, *imageIODataPtr; 432 433 /* 434 * Allocate and initialize a new imageIOData object to associate the 435 * jpeg object and the Java object. Returns a pointer to the new object 436 * on success, NULL on failure. 437 */ 438 static imageIODataPtr initImageioData(JNIEnv *env, 439 j_common_ptr cinfo, 440 jobject obj) { 441 imageIODataPtr data = (imageIODataPtr) malloc(sizeof (imageIOData)); 442 if (data == NULL) { 443 return NULL; 444 } 445 446 data->jpegObj = cinfo; 447 cinfo->client_data = data; 448 449 #ifdef DEBUG_IIO_JPEG 450 printf("new structures: data is %p, cinfo is %p\n", data, cinfo); 451 #endif 452 453 data->imageIOobj = (*env)->NewWeakGlobalRef(env, obj); 454 if (data->imageIOobj == NULL) { 455 free(data); 456 return NULL; 457 } 458 if (initStreamBuffer(env, &data->streamBuf) == NOT_OK) { 459 (*env)->DeleteWeakGlobalRef(env, data->imageIOobj); 460 free(data); 461 return NULL; 462 } 463 initPixelBuffer(&data->pixelBuf); 464 465 data->abortFlag = JNI_FALSE; 466 467 return data; 468 } 469 470 /* 471 * Resets the imageIOData object to its initial state, as though 472 * it had just been allocated and initialized. 473 */ 474 static void resetImageIOData(JNIEnv *env, imageIODataPtr data) { 475 resetStreamBuffer(env, &data->streamBuf); 476 resetPixelBuffer(env, &data->pixelBuf); 477 data->abortFlag = JNI_FALSE; 478 } 479 480 /* 481 * Releases all resources held by this object and its subobjects, 482 * frees the object, and returns the jpeg object. This method must 483 * be called to avoid leaking global references. 484 * Note that the jpeg object is not freed or destroyed, as that is 485 * the client's responsibility, although the client_data field is 486 * cleared. 487 */ 488 static j_common_ptr destroyImageioData(JNIEnv *env, imageIODataPtr data) { 489 j_common_ptr ret = data->jpegObj; 490 (*env)->DeleteWeakGlobalRef(env, data->imageIOobj); 491 destroyStreamBuffer(env, &data->streamBuf); 492 resetPixelBuffer(env, &data->pixelBuf); 493 ret->client_data = NULL; 494 free(data); 495 return ret; 496 } 497 498 /******************** end ImageIOData definition ***********************/ 499 500 /******************** Java array pinning and unpinning *****************/ 501 502 /* We use Get/ReleasePrimitiveArrayCritical functions to avoid 503 * the need to copy array elements for the above two objects. 504 * 505 * MAKE SURE TO: 506 * 507 * - carefully insert pairs of RELEASE_ARRAYS and GET_ARRAYS around 508 * callbacks to Java. 509 * - call RELEASE_ARRAYS before returning to Java. 510 * 511 * Otherwise things will go horribly wrong. There may be memory leaks, 512 * excessive pinning, or even VM crashes! 513 * 514 * Note that GetPrimitiveArrayCritical may fail! 515 */ 516 517 /* 518 * Release (unpin) all the arrays in use during a read. 519 */ 520 static void RELEASE_ARRAYS(JNIEnv *env, imageIODataPtr data, const JOCTET *next_byte) { 521 unpinStreamBuffer(env, &data->streamBuf, next_byte); 522 523 unpinPixelBuffer(env, &data->pixelBuf); 524 525 } 526 527 /* 528 * Get (pin) all the arrays in use during a read. 529 */ 530 static int GET_ARRAYS(JNIEnv *env, imageIODataPtr data, const JOCTET **next_byte) { 531 if (pinStreamBuffer(env, &data->streamBuf, next_byte) == NOT_OK) { 532 return NOT_OK; 533 } 534 535 if (pinPixelBuffer(env, &data->pixelBuf) == NOT_OK) { 536 RELEASE_ARRAYS(env, data, *next_byte); 537 return NOT_OK; 538 } 539 return OK; 540 } 541 542 /****** end of Java array pinning and unpinning ***********/ 543 544 /****** Error Handling *******/ 545 546 /* 547 * Set up error handling to use setjmp/longjmp. This is the third such 548 * setup, as both the AWT jpeg decoder and the com.sun... JPEG classes 549 * setup thier own. Ultimately these should be integrated, as they all 550 * do pretty much the same thing. 551 */ 552 553 struct sun_jpeg_error_mgr { 554 struct jpeg_error_mgr pub; /* "public" fields */ 555 556 jmp_buf setjmp_buffer; /* for return to caller */ 557 }; 558 559 typedef struct sun_jpeg_error_mgr * sun_jpeg_error_ptr; 560 561 /* 562 * Here's the routine that will replace the standard error_exit method: 563 */ 564 565 METHODDEF(void) 566 sun_jpeg_error_exit(j_common_ptr cinfo) { 567 /* cinfo->err really points to a sun_jpeg_error_mgr struct */ 568 sun_jpeg_error_ptr myerr = (sun_jpeg_error_ptr) cinfo->err; 569 570 /* For Java, we will format the message and put it in the error we throw. */ 571 572 /* Return control to the setjmp point */ 573 longjmp(myerr->setjmp_buffer, 1); 574 } 575 576 /* 577 * Error Message handling 578 * 579 * This overrides the output_message method to send JPEG messages 580 * 581 */ 582 583 METHODDEF(void) 584 sun_jpeg_output_message(j_common_ptr cinfo) { 585 char buffer[JMSG_LENGTH_MAX]; 586 jstring string; 587 imageIODataPtr data = (imageIODataPtr) cinfo->client_data; 588 JNIEnv *env = (JNIEnv *) GetEnv(jvm, JNI_VERSION_1_2); 589 jobject theObject; 590 j_decompress_ptr dinfo; 591 592 /* Create the message */ 593 (*cinfo->err->format_message) (cinfo, buffer); 594 595 if (cinfo->is_decompressor) { 596 dinfo = (j_decompress_ptr)cinfo; 597 RELEASE_ARRAYS(env, data, dinfo->src->next_input_byte); 598 } 599 // Create a new java string from the message 600 string = (*env)->NewStringUTF(env, buffer); 601 602 theObject = data->imageIOobj; 603 604 if (cinfo->is_decompressor) { 605 (*env)->CallVoidMethod(env, theObject, 606 JPEGImageLoader_emitWarningID, 607 string); 608 checkAndClearException(env); 609 if (!GET_ARRAYS(env, data, &(dinfo->src->next_input_byte))) { 610 cinfo->err->error_exit(cinfo); 611 } 612 } 613 } 614 615 /* End of verbatim copy from jpegdecoder.c */ 616 617 /*************** end of error handling *********************/ 618 619 /*************** Shared utility code ***********************/ 620 621 static void imageio_set_stream(JNIEnv *env, 622 j_common_ptr cinfo, 623 imageIODataPtr data, 624 jobject stream) { 625 streamBufferPtr sb; 626 sun_jpeg_error_ptr jerr; 627 628 sb = &data->streamBuf; 629 630 resetStreamBuffer(env, sb); // Removes any old stream 631 632 /* Now we need a new global reference for the stream */ 633 if (stream != NULL) { // Fix for 4411955 634 sb->stream = (*env)->NewGlobalRef(env, stream); 635 if (sb->stream == NULL) { 636 ThrowByName(env, 637 "java/lang/OutOfMemoryError", 638 "Setting Stream"); 639 return; 640 } 641 } 642 643 /* And finally reset state */ 644 data->abortFlag = JNI_FALSE; 645 646 /* Establish the setjmp return context for sun_jpeg_error_exit to use. */ 647 jerr = (sun_jpeg_error_ptr) cinfo->err; 648 649 if (setjmp(jerr->setjmp_buffer)) { 650 /* If we get here, the JPEG code has signaled an error 651 while aborting. */ 652 if (!(*env)->ExceptionOccurred(env)) { 653 char buffer[JMSG_LENGTH_MAX]; 654 (*cinfo->err->format_message) (cinfo, 655 buffer); 656 ThrowByName(env, "java/io/IOException", buffer); 657 } 658 return; 659 } 660 661 jpeg_abort(cinfo); // Frees any markers, but not tables 662 663 } 664 665 static void imageio_dispose(j_common_ptr info) { 666 667 if (info != NULL) { 668 free(info->err); 669 info->err = NULL; 670 if (info->is_decompressor) { 671 j_decompress_ptr dinfo = (j_decompress_ptr) info; 672 free(dinfo->src); 673 dinfo->src = NULL; 674 } else { 675 j_compress_ptr cinfo = (j_compress_ptr) info; 676 free(cinfo->dest); 677 cinfo->dest = NULL; 678 } 679 jpeg_destroy(info); 680 free(info); 681 } 682 } 683 684 static void imageio_abort(JNIEnv *env, jobject this, 685 imageIODataPtr data) { 686 data->abortFlag = JNI_TRUE; 687 } 688 689 /*************** end of shared utility code ****************/ 690 691 /********************** Loader Support **************************/ 692 693 /********************** Source Management ***********************/ 694 695 /* 696 * INPUT HANDLING: 697 * 698 * The JPEG library's input management is defined by the jpeg_source_mgr 699 * structure which contains two fields to convey the information in the 700 * buffer and 5 methods which perform all buffer management. The library 701 * defines a standard input manager that uses stdio for obtaining compressed 702 * jpeg data, but here we need to use Java to get our data. 703 * 704 * We use the library jpeg_source_mgr but our own routines that access 705 * imageio-specific information in the imageIOData structure. 706 */ 707 708 /* 709 * Initialize source. This is called by jpeg_read_header() before any 710 * data is actually read. Unlike init_destination(), it may leave 711 * bytes_in_buffer set to 0 (in which case a fill_input_buffer() call 712 * will occur immediately). 713 */ 714 715 GLOBAL(void) 716 imageio_init_source(j_decompress_ptr cinfo) { 717 struct jpeg_source_mgr *src = cinfo->src; 718 src->next_input_byte = NULL; 719 src->bytes_in_buffer = 0; 720 } 721 722 /* 723 * This is called whenever bytes_in_buffer has reached zero and more 724 * data is wanted. In typical applications, it should read fresh data 725 * into the buffer (ignoring the current state of next_input_byte and 726 * bytes_in_buffer), reset the pointer & count to the start of the 727 * buffer, and return TRUE indicating that the buffer has been reloaded. 728 * It is not necessary to fill the buffer entirely, only to obtain at 729 * least one more byte. bytes_in_buffer MUST be set to a positive value 730 * if TRUE is returned. A FALSE return should only be used when I/O 731 * suspension is desired (this mode is discussed in the next section). 732 */ 733 734 /* 735 * Note that with I/O suspension turned on, this procedure should not 736 * do any work since the JPEG library has a very simple backtracking 737 * mechanism which relies on the fact that the buffer will be filled 738 * only when it has backed out to the top application level. When 739 * suspendable is turned on, imageio_fill_suspended_buffer will 740 * do the actual work of filling the buffer. 741 */ 742 743 GLOBAL(boolean) 744 imageio_fill_input_buffer(j_decompress_ptr cinfo) { 745 struct jpeg_source_mgr *src = cinfo->src; 746 imageIODataPtr data = (imageIODataPtr) cinfo->client_data; 747 streamBufferPtr sb = &data->streamBuf; 748 JNIEnv *env = (JNIEnv *) GetEnv(jvm, JNI_VERSION_1_2); 749 int ret; 750 751 /* This is where input suspends */ 752 if (sb->suspendable) { 753 return FALSE; 754 } 755 756 #ifdef DEBUG_IIO_JPEG 757 printf("Filling input buffer, remaining skip is %ld, ", 758 sb->remaining_skip); 759 printf("Buffer length is %d\n", sb->bufferLength); 760 #endif 761 762 /* 763 * Definitively skips. Could be left over if we tried to skip 764 * more than a buffer's worth but suspended when getting the next 765 * buffer. Now we aren't suspended, so we can catch up. 766 */ 767 if (sb->remaining_skip) { 768 src->skip_input_data(cinfo, 0); 769 } 770 771 /* 772 * Now fill a complete buffer, or as much of one as the stream 773 * will give us if we are near the end. 774 */ 775 RELEASE_ARRAYS(env, data, src->next_input_byte); 776 ret = (*env)->CallIntMethod(env, 777 sb->stream, 778 InputStream_readID, 779 sb->hstreamBuffer, 0, 780 sb->bufferLength); 781 if (ret > sb->bufferLength) ret = sb->bufferLength; 782 if ((*env)->ExceptionOccurred(env) 783 || !GET_ARRAYS(env, data, &(src->next_input_byte))) { 784 cinfo->err->error_exit((j_common_ptr) cinfo); 785 } 786 787 #ifdef DEBUG_IIO_JPEG 788 printf("Buffer filled. ret = %d\n", ret); 789 #endif 790 /* 791 * If we have reached the end of the stream, then the EOI marker 792 * is missing. We accept such streams but generate a warning. 793 * The image is likely to be corrupted, though everything through 794 * the end of the last complete MCU should be usable. 795 */ 796 if (ret <= 0) { 797 jobject reader = data->imageIOobj; 798 #ifdef DEBUG_IIO_JPEG 799 printf("YO! Early EOI! ret = %d\n", ret); 800 #endif 801 RELEASE_ARRAYS(env, data, src->next_input_byte); 802 (*env)->CallVoidMethod(env, reader, 803 JPEGImageLoader_emitWarningID, 804 READ_NO_EOI); 805 if ((*env)->ExceptionOccurred(env) 806 || !GET_ARRAYS(env, data, &(src->next_input_byte))) { 807 cinfo->err->error_exit((j_common_ptr) cinfo); 808 } 809 810 sb->buf[0] = (JOCTET) 0xFF; 811 sb->buf[1] = (JOCTET) JPEG_EOI; 812 ret = 2; 813 } 814 815 src->next_input_byte = sb->buf; 816 src->bytes_in_buffer = ret; 817 818 return TRUE; 819 } 820 821 /* 822 * With I/O suspension turned on, the JPEG library requires that all 823 * buffer filling be done at the top application level, using this 824 * function. Due to the way that backtracking works, this procedure 825 * saves all of the data that was left in the buffer when suspension 826 * occured and read new data only at the end. 827 */ 828 829 GLOBAL(void) 830 imageio_fill_suspended_buffer(j_decompress_ptr cinfo) { 831 struct jpeg_source_mgr *src = cinfo->src; 832 imageIODataPtr data = (imageIODataPtr) cinfo->client_data; 833 streamBufferPtr sb = &data->streamBuf; 834 JNIEnv *env = (JNIEnv *) GetEnv(jvm, JNI_VERSION_1_2); 835 jint ret; 836 int offset, buflen; 837 838 /* 839 * The original (jpegdecoder.c) had code here that called 840 * InputStream.available and just returned if the number of bytes 841 * available was less than any remaining skip. Presumably this was 842 * to avoid blocking, although the benefit was unclear, as no more 843 * decompression can take place until more data is available, so 844 * the code would block on input a little further along anyway. 845 * ImageInputStreams don't have an available method, so we'll just 846 * block in the skip if we have to. 847 */ 848 849 if (sb->remaining_skip) { 850 src->skip_input_data(cinfo, 0); 851 } 852 853 /* Save the data currently in the buffer */ 854 offset = src->bytes_in_buffer; 855 if (src->next_input_byte > sb->buf) { 856 memcpy(sb->buf, src->next_input_byte, offset); 857 } 858 RELEASE_ARRAYS(env, data, src->next_input_byte); 859 buflen = sb->bufferLength - offset; 860 if (buflen <= 0) { 861 if (!GET_ARRAYS(env, data, &(src->next_input_byte))) { 862 cinfo->err->error_exit((j_common_ptr) cinfo); 863 } 864 return; 865 } 866 867 ret = (*env)->CallIntMethod(env, sb->stream, 868 InputStream_readID, 869 sb->hstreamBuffer, 870 offset, buflen); 871 if (ret > buflen) ret = buflen; 872 if ((*env)->ExceptionOccurred(env) 873 || !GET_ARRAYS(env, data, &(src->next_input_byte))) { 874 cinfo->err->error_exit((j_common_ptr) cinfo); 875 } 876 /* 877 * If we have reached the end of the stream, then the EOI marker 878 * is missing. We accept such streams but generate a warning. 879 * The image is likely to be corrupted, though everything through 880 * the end of the last complete MCU should be usable. 881 */ 882 if (ret <= 0) { 883 jobject reader = data->imageIOobj; 884 RELEASE_ARRAYS(env, data, src->next_input_byte); 885 (*env)->CallVoidMethod(env, reader, 886 JPEGImageLoader_emitWarningID, 887 READ_NO_EOI); 888 if ((*env)->ExceptionOccurred(env) 889 || !GET_ARRAYS(env, data, &(src->next_input_byte))) { 890 cinfo->err->error_exit((j_common_ptr) cinfo); 891 } 892 893 sb->buf[offset] = (JOCTET) 0xFF; 894 sb->buf[offset + 1] = (JOCTET) JPEG_EOI; 895 ret = 2; 896 } 897 898 src->next_input_byte = sb->buf; 899 src->bytes_in_buffer = ret + offset; 900 901 return; 902 } 903 904 /* 905 * Skip num_bytes worth of data. The buffer pointer and count are 906 * advanced over num_bytes input bytes, using the input stream 907 * skipBytes method if the skip is greater than the number of bytes 908 * in the buffer. This is used to skip over a potentially large amount of 909 * uninteresting data (such as an APPn marker). bytes_in_buffer will be 910 * zero on return if the skip is larger than the current contents of the 911 * buffer. 912 * 913 * A negative skip count is treated as a no-op. A zero skip count 914 * skips any remaining skip from a previous skip while suspended. 915 * 916 * Note that with I/O suspension turned on, this procedure does not 917 * call skipBytes since the JPEG library has a very simple backtracking 918 * mechanism which relies on the fact that the application level has 919 * exclusive control over actual I/O. 920 */ 921 922 GLOBAL(void) 923 imageio_skip_input_data(j_decompress_ptr cinfo, long num_bytes) { 924 struct jpeg_source_mgr *src = cinfo->src; 925 imageIODataPtr data = (imageIODataPtr) cinfo->client_data; 926 streamBufferPtr sb = &data->streamBuf; 927 JNIEnv *env = (JNIEnv *) GetEnv(jvm, JNI_VERSION_1_2); 928 jlong ret; 929 jobject reader; 930 931 if (num_bytes < 0) { 932 return; 933 } 934 num_bytes += sb->remaining_skip; 935 sb->remaining_skip = 0; 936 937 /* First the easy case where we are skipping <= the current contents. */ 938 ret = src->bytes_in_buffer; 939 if (ret >= num_bytes) { 940 src->next_input_byte += num_bytes; 941 src->bytes_in_buffer -= num_bytes; 942 return; 943 } 944 945 /* 946 * We are skipping more than is in the buffer. We empty the buffer and, 947 * if we aren't suspended, call the Java skipBytes method. We always 948 * leave the buffer empty, to be filled by either fill method above. 949 */ 950 src->bytes_in_buffer = 0; 951 src->next_input_byte = sb->buf; 952 953 num_bytes -= (long) ret; 954 if (sb->suspendable) { 955 sb->remaining_skip = num_bytes; 956 return; 957 } 958 959 RELEASE_ARRAYS(env, data, src->next_input_byte); 960 ret = (*env)->CallLongMethod(env, 961 sb->stream, 962 InputStream_skipID, 963 (jlong) num_bytes); 964 if ((*env)->ExceptionOccurred(env) 965 || !GET_ARRAYS(env, data, &(src->next_input_byte))) { 966 cinfo->err->error_exit((j_common_ptr) cinfo); 967 } 968 969 /* 970 * If we have reached the end of the stream, then the EOI marker 971 * is missing. We accept such streams but generate a warning. 972 * The image is likely to be corrupted, though everything through 973 * the end of the last complete MCU should be usable. 974 */ 975 if (ret <= 0) { 976 reader = data->imageIOobj; 977 RELEASE_ARRAYS(env, data, src->next_input_byte); 978 (*env)->CallVoidMethod(env, 979 reader, 980 JPEGImageLoader_emitWarningID, 981 READ_NO_EOI); 982 983 if ((*env)->ExceptionOccurred(env) 984 || !GET_ARRAYS(env, data, &(src->next_input_byte))) { 985 cinfo->err->error_exit((j_common_ptr) cinfo); 986 } 987 sb->buf[0] = (JOCTET) 0xFF; 988 sb->buf[1] = (JOCTET) JPEG_EOI; 989 src->bytes_in_buffer = 2; 990 src->next_input_byte = sb->buf; 991 } 992 } 993 994 /* 995 * Terminate source --- called by jpeg_finish_decompress() after all 996 * data for an image has been read. In our case pushes back any 997 * remaining data, as it will be for another image and must be available 998 * for java to find out that there is another image. Also called if 999 * reseting state after reading a tables-only image. 1000 */ 1001 1002 GLOBAL(void) 1003 imageio_term_source(j_decompress_ptr cinfo) { 1004 // To pushback, just seek back by src->bytes_in_buffer 1005 struct jpeg_source_mgr *src = cinfo->src; 1006 imageIODataPtr data = (imageIODataPtr) cinfo->client_data; 1007 JNIEnv *env = (JNIEnv *) GetEnv(jvm, JNI_VERSION_1_2); 1008 jobject reader = data->imageIOobj; 1009 if (src->bytes_in_buffer > 0) { 1010 RELEASE_ARRAYS(env, data, src->next_input_byte); 1011 1012 if ((*env)->ExceptionOccurred(env) 1013 || !GET_ARRAYS(env, data, &(src->next_input_byte))) { 1014 cinfo->err->error_exit((j_common_ptr) cinfo); 1015 } 1016 src->bytes_in_buffer = 0; 1017 //src->next_input_byte = sb->buf; 1018 } 1019 } 1020 1021 /********************* end of source manager ******************/ 1022 1023 /********************* ICC profile support ********************/ 1024 /* 1025 * The following routines are modified versions of the ICC 1026 * profile support routines available from the IJG website. 1027 * The originals were written by Todd Newman 1028 * <tdn@eccentric.esd.sgi.com> and modified by Tom Lane for 1029 * the IJG. They are further modified to fit in the context 1030 * of the imageio JPEG plug-in. 1031 */ 1032 1033 /* 1034 * Since an ICC profile can be larger than the maximum size of a JPEG marker 1035 * (64K), we need provisions to split it into multiple markers. The format 1036 * defined by the ICC specifies one or more APP2 markers containing the 1037 * following data: 1038 * Identifying string ASCII "ICC_PROFILE\0" (12 bytes) 1039 * Marker sequence number 1 for first APP2, 2 for next, etc (1 byte) 1040 * Number of markers Total number of APP2's used (1 byte) 1041 * Profile data (remainder of APP2 data) 1042 * Decoders should use the marker sequence numbers to reassemble the profile, 1043 * rather than assuming that the APP2 markers appear in the correct sequence. 1044 */ 1045 1046 #define ICC_MARKER (JPEG_APP0 + 2) /* JPEG marker code for ICC */ 1047 #define ICC_OVERHEAD_LEN 14 /* size of non-profile data in APP2 */ 1048 #define MAX_BYTES_IN_MARKER 65533 /* maximum data len of a JPEG marker */ 1049 #define MAX_DATA_BYTES_IN_ICC_MARKER (MAX_BYTES_IN_MARKER - ICC_OVERHEAD_LEN) 1050 1051 /* 1052 * Handy subroutine to test whether a saved marker is an ICC profile marker. 1053 */ 1054 1055 static boolean 1056 marker_is_icc(jpeg_saved_marker_ptr marker) { 1057 return 1058 marker->marker == ICC_MARKER && 1059 marker->data_length >= ICC_OVERHEAD_LEN && 1060 /* verify the identifying string */ 1061 GETJOCTET(marker->data[0]) == 0x49 && 1062 GETJOCTET(marker->data[1]) == 0x43 && 1063 GETJOCTET(marker->data[2]) == 0x43 && 1064 GETJOCTET(marker->data[3]) == 0x5F && 1065 GETJOCTET(marker->data[4]) == 0x50 && 1066 GETJOCTET(marker->data[5]) == 0x52 && 1067 GETJOCTET(marker->data[6]) == 0x4F && 1068 GETJOCTET(marker->data[7]) == 0x46 && 1069 GETJOCTET(marker->data[8]) == 0x49 && 1070 GETJOCTET(marker->data[9]) == 0x4C && 1071 GETJOCTET(marker->data[10]) == 0x45 && 1072 GETJOCTET(marker->data[11]) == 0x0; 1073 } 1074 1075 /* 1076 * See if there was an ICC profile in the JPEG file being read; 1077 * if so, reassemble and return the profile data as a new Java byte array. 1078 * If there was no ICC profile, return NULL. 1079 * 1080 * If the file contains invalid ICC APP2 markers, we throw an IIOException 1081 * with an appropriate message. 1082 */ 1083 1084 jbyteArray 1085 read_icc_profile(JNIEnv *env, j_decompress_ptr cinfo) { 1086 jpeg_saved_marker_ptr marker; 1087 int num_markers = 0; 1088 int num_found_markers = 0; 1089 int seq_no; 1090 JOCTET *icc_data; 1091 JOCTET *dst_ptr; 1092 unsigned int total_length; 1093 #define MAX_SEQ_NO 255 // sufficient since marker numbers are bytes 1094 jpeg_saved_marker_ptr icc_markers[MAX_SEQ_NO + 1]; 1095 int first; // index of the first marker in the icc_markers array 1096 int last; // index of the last marker in the icc_markers array 1097 jbyteArray data = NULL; 1098 1099 /* This first pass over the saved markers discovers whether there are 1100 * any ICC markers and verifies the consistency of the marker numbering. 1101 */ 1102 1103 for (seq_no = 0; seq_no <= MAX_SEQ_NO; seq_no++) 1104 icc_markers[seq_no] = NULL; 1105 1106 1107 for (marker = cinfo->marker_list; marker != NULL; marker = marker->next) { 1108 if (marker_is_icc(marker)) { 1109 if (num_markers == 0) 1110 num_markers = GETJOCTET(marker->data[13]); 1111 else if (num_markers != GETJOCTET(marker->data[13])) { 1112 ThrowByName(env, "java/io/IOException", 1113 "Invalid icc profile: inconsistent num_markers fields"); 1114 return NULL; 1115 } 1116 seq_no = GETJOCTET(marker->data[12]); 1117 1118 /* Some third-party tools produce images with profile chunk 1119 * numeration started from zero. It is inconsistent with ICC 1120 * spec, but seems to be recognized by majority of image 1121 * processing tools, so we should be more tolerant to this 1122 * departure from the spec. 1123 */ 1124 if (seq_no < 0 || seq_no > num_markers) { 1125 ThrowByName(env, "java/io/IOException", 1126 "Invalid icc profile: bad sequence number"); 1127 return NULL; 1128 } 1129 if (icc_markers[seq_no] != NULL) { 1130 ThrowByName(env, "java/io/IOException", 1131 "Invalid icc profile: duplicate sequence numbers"); 1132 return NULL; 1133 } 1134 icc_markers[seq_no] = marker; 1135 num_found_markers++; 1136 } 1137 } 1138 1139 if (num_markers == 0) 1140 return NULL; // There is no profile 1141 1142 if (num_markers != num_found_markers) { 1143 ThrowByName(env, "java/io/IOException", 1144 "Invalid icc profile: invalid number of icc markers"); 1145 return NULL; 1146 } 1147 1148 first = icc_markers[0] ? 0 : 1; 1149 last = num_found_markers + first; 1150 1151 /* Check for missing markers, count total space needed. 1152 */ 1153 total_length = 0; 1154 for (seq_no = first; seq_no < last; seq_no++) { 1155 unsigned int length; 1156 if (icc_markers[seq_no] == NULL) { 1157 ThrowByName(env, "java/io/IOException", 1158 "Invalid icc profile: missing sequence number"); 1159 return NULL; 1160 } 1161 /* check the data length correctness */ 1162 length = icc_markers[seq_no]->data_length; 1163 if (ICC_OVERHEAD_LEN > length || length > MAX_BYTES_IN_MARKER) { 1164 ThrowByName(env, "java/io/IOException", 1165 "Invalid icc profile: invalid data length"); 1166 return NULL; 1167 } 1168 total_length += (length - ICC_OVERHEAD_LEN); 1169 } 1170 1171 if (total_length <= 0) { 1172 ThrowByName(env, "java/io/IOException", 1173 "Invalid icc profile: found only empty markers"); 1174 return NULL; 1175 } 1176 1177 /* Allocate a Java byte array for assembled data */ 1178 1179 data = (*env)->NewByteArray(env, total_length); 1180 if (data == NULL) { 1181 ThrowByName(env, 1182 "java/lang/OutOfMemoryError", 1183 "Reading ICC profile"); 1184 return NULL; 1185 } 1186 1187 icc_data = (JOCTET *) (*env)->GetPrimitiveArrayCritical(env, 1188 data, 1189 NULL); 1190 if (icc_data == NULL) { 1191 ThrowByName(env, "java/io/IOException", 1192 "Unable to pin icc profile data array"); 1193 return NULL; 1194 } 1195 1196 /* and fill it in */ 1197 dst_ptr = icc_data; 1198 for (seq_no = first; seq_no < last; seq_no++) { 1199 JOCTET FAR *src_ptr = icc_markers[seq_no]->data + ICC_OVERHEAD_LEN; 1200 unsigned int length = 1201 icc_markers[seq_no]->data_length - ICC_OVERHEAD_LEN; 1202 1203 memcpy(dst_ptr, src_ptr, length); 1204 dst_ptr += length; 1205 } 1206 1207 /* finally, unpin the array */ 1208 (*env)->ReleasePrimitiveArrayCritical(env, 1209 data, 1210 icc_data, 1211 0); 1212 1213 1214 return data; 1215 } 1216 1217 /********************* end of ICC profile support *************/ 1218 1219 /********************* Loader JNI calls ***********************/ 1220 1221 JNIEXPORT void JNICALL Java_com_sun_javafx_iio_jpeg_JPEGImageLoader_initJPEGMethodIDs 1222 (JNIEnv *env, jclass cls, jclass InputStreamClass) { 1223 // InputStream methods. 1224 InputStream_readID = (*env)->GetMethodID(env, 1225 InputStreamClass, 1226 "read", 1227 "([BII)I"); 1228 if ((*env)->ExceptionCheck(env)) { 1229 return; 1230 } 1231 1232 InputStream_skipID = (*env)->GetMethodID(env, 1233 InputStreamClass, 1234 "skip", 1235 "(J)J"); 1236 if ((*env)->ExceptionCheck(env)) { 1237 return; 1238 } 1239 1240 // JPEGImageLoader IDs. 1241 JPEGImageLoader_setInputAttributesID = (*env)->GetMethodID(env, 1242 cls, 1243 "setInputAttributes", 1244 "(IIIII[B)V"); 1245 if ((*env)->ExceptionCheck(env)) { 1246 return; 1247 } 1248 1249 JPEGImageLoader_setOutputAttributesID = (*env)->GetMethodID(env, 1250 cls, 1251 "setOutputAttributes", 1252 "(II)V"); 1253 if ((*env)->ExceptionCheck(env)) { 1254 return; 1255 } 1256 1257 JPEGImageLoader_updateImageProgressID = (*env)->GetMethodID(env, 1258 cls, 1259 "updateImageProgress", 1260 "(I)V"); 1261 if ((*env)->ExceptionCheck(env)) { 1262 return; 1263 } 1264 1265 JPEGImageLoader_emitWarningID = (*env)->GetMethodID(env, 1266 cls, 1267 "emitWarning", 1268 "(Ljava/lang/String;)V"); 1269 if ((*env)->ExceptionCheck(env)) { 1270 return; 1271 } 1272 1273 } 1274 1275 JNIEXPORT void JNICALL Java_com_sun_javafx_iio_jpeg_JPEGImageLoader_disposeNative 1276 (JNIEnv *env, jclass cls, jlong ptr) { 1277 imageIODataPtr data = (imageIODataPtr) jlong_to_ptr(ptr); 1278 j_common_ptr info = destroyImageioData(env, data); 1279 1280 imageio_dispose(info); 1281 } 1282 1283 #define JPEG_APP1 (JPEG_APP0 + 1) /* EXIF APP1 marker code */ 1284 1285 /* 1286 * For EXIF images, the APP1 will appear immediately after the SOI, 1287 * so it's safe to only look at the first marker in the list. 1288 * (see http://www.exif.org/Exif2-2.PDF, section 4.7, page 58) 1289 */ 1290 #define IS_EXIF(c) \ 1291 (((c)->marker_list != NULL) && ((c)->marker_list->marker == JPEG_APP1)) 1292 1293 JNIEXPORT jlong JNICALL Java_com_sun_javafx_iio_jpeg_JPEGImageLoader_initDecompressor 1294 (JNIEnv *env, jobject this, jobject stream) { 1295 imageIODataPtr data; 1296 struct sun_jpeg_error_mgr *jerr_mgr; 1297 1298 /* This struct contains the JPEG decompression parameters and pointers to 1299 * working space (which is allocated as needed by the JPEG library). 1300 */ 1301 struct jpeg_decompress_struct *cinfo; 1302 int jret; 1303 int h_samp0, h_samp1, h_samp2; 1304 int v_samp0, v_samp1, v_samp2; 1305 struct jpeg_source_mgr *src; 1306 sun_jpeg_error_ptr jerr; 1307 jbyteArray profileData = NULL; 1308 1309 cinfo = malloc(sizeof (struct jpeg_decompress_struct)); 1310 if (cinfo == NULL) { 1311 ThrowByName(env, 1312 "java/lang/OutOfMemoryError", 1313 "Initializing Reader"); 1314 return 0; 1315 } 1316 1317 /* We use our private extension JPEG error handler. 1318 */ 1319 jerr_mgr = malloc(sizeof (struct sun_jpeg_error_mgr)); 1320 if (jerr_mgr == NULL) { 1321 free(cinfo); 1322 ThrowByName(env, 1323 "java/lang/OutOfMemoryError", 1324 "Initializing Reader"); 1325 return 0; 1326 } 1327 1328 /* We set up the normal JPEG error routines, then override error_exit. */ 1329 cinfo->err = jpeg_std_error(&(jerr_mgr->pub)); 1330 jerr_mgr->pub.error_exit = sun_jpeg_error_exit; 1331 /* We need to setup our own print routines */ 1332 jerr_mgr->pub.output_message = sun_jpeg_output_message; 1333 /* Now we can setjmp before every call to the library */ 1334 1335 /* Establish the setjmp return context for sun_jpeg_error_exit to use. */ 1336 if (setjmp(jerr_mgr->setjmp_buffer)) { 1337 /* If we get here, the JPEG code has signaled an error. */ 1338 char buffer[JMSG_LENGTH_MAX]; 1339 (*cinfo->err->format_message) ((struct jpeg_common_struct *) cinfo, 1340 buffer); 1341 free(cinfo); 1342 free(jerr_mgr); 1343 ThrowByName(env, "java/io/IOException", buffer); 1344 return 0; 1345 } 1346 1347 /* Perform library initialization */ 1348 jpeg_create_decompress(cinfo); 1349 1350 // Set up to keep any APP2 markers, as these might contain ICC profile 1351 // data 1352 jpeg_save_markers(cinfo, ICC_MARKER, 0xFFFF); 1353 1354 /* 1355 * Now set up our source. 1356 */ 1357 cinfo->src = 1358 (struct jpeg_source_mgr *) malloc(sizeof (struct jpeg_source_mgr)); 1359 if (cinfo->src == NULL) { 1360 free(cinfo); 1361 free(jerr_mgr); 1362 ThrowByName(env, 1363 "java/lang/OutOfMemoryError", 1364 "Initializing Reader"); 1365 return 0; 1366 } 1367 cinfo->src->bytes_in_buffer = 0; 1368 cinfo->src->next_input_byte = NULL; 1369 cinfo->src->init_source = imageio_init_source; 1370 cinfo->src->fill_input_buffer = imageio_fill_input_buffer; 1371 cinfo->src->skip_input_data = imageio_skip_input_data; 1372 cinfo->src->resync_to_restart = jpeg_resync_to_restart; // use default 1373 cinfo->src->term_source = imageio_term_source; 1374 1375 /* set up the association to persist for future calls */ 1376 data = initImageioData(env, (j_common_ptr) cinfo, this); 1377 if (data == NULL) { 1378 free(cinfo->src); 1379 free(cinfo); 1380 free(jerr_mgr); 1381 ThrowByName(env, 1382 "java/lang/OutOfMemoryError", 1383 "Initializing Reader"); 1384 return 0; 1385 } 1386 1387 imageio_set_stream(env, (j_common_ptr) cinfo, data, stream); 1388 1389 if ((*env)->ExceptionCheck(env)) { 1390 free(cinfo->src); 1391 free(cinfo); 1392 free(jerr_mgr); 1393 return 0; 1394 } 1395 1396 imageio_init_source((j_decompress_ptr) cinfo); 1397 1398 src = cinfo->src; 1399 jerr = (sun_jpeg_error_ptr) cinfo->err; 1400 1401 /* Establish the setjmp return context for sun_jpeg_error_exit to use. */ 1402 if (setjmp(jerr->setjmp_buffer)) { 1403 /* If we get here, the JPEG code has signaled an error 1404 while reading the header. */ 1405 RELEASE_ARRAYS(env, data, src->next_input_byte); 1406 if (!(*env)->ExceptionOccurred(env)) { 1407 char buffer[JMSG_LENGTH_MAX]; 1408 (*cinfo->err->format_message) ((struct jpeg_common_struct *) cinfo, 1409 buffer); 1410 ThrowByName(env, "java/io/IOException", buffer); 1411 } 1412 free(cinfo->src); 1413 free(cinfo); 1414 free(jerr_mgr); 1415 return 0; 1416 } 1417 1418 if (GET_ARRAYS(env, data, &src->next_input_byte) == NOT_OK) { 1419 RELEASE_ARRAYS(env, data, src->next_input_byte); 1420 free(cinfo->src); 1421 free(cinfo); 1422 free(jerr_mgr); 1423 ThrowByName(env, 1424 "java/io/IOException", 1425 "Array pin failed"); 1426 return 0; 1427 } 1428 1429 jret = jpeg_read_header(cinfo, FALSE); 1430 1431 if (jret == JPEG_HEADER_TABLES_ONLY) { 1432 imageio_term_source(cinfo); // Pushback remaining buffer contents 1433 #ifdef DEBUG_IIO_JPEG 1434 printf("just read tables-only image; q table 0 at %p\n", 1435 cinfo->quant_tbl_ptrs[0]); 1436 #endif 1437 RELEASE_ARRAYS(env, data, src->next_input_byte); 1438 } else { 1439 /* 1440 * Now adjust the jpeg_color_space variable, which was set in 1441 * default_decompress_parms, to reflect our differences from IJG 1442 */ 1443 1444 switch (cinfo->jpeg_color_space) { 1445 default: 1446 break; 1447 case JCS_YCbCr: 1448 1449 /* 1450 * There are several possibilities: 1451 * - we got image with embeded colorspace 1452 * Use it. User knows what he is doing. 1453 * - we got JFIF image 1454 * Must be YCbCr (see http://www.w3.org/Graphics/JPEG/jfif3.pdf, page 2) 1455 * - we got EXIF image 1456 * Must be YCbCr (see http://www.exif.org/Exif2-2.PDF, section 4.7, page 63) 1457 * - something else 1458 * Apply heuristical rules to identify actual colorspace. 1459 */ 1460 1461 if (cinfo->saw_Adobe_marker) { 1462 if (cinfo->Adobe_transform != 1) { 1463 /* 1464 * IJG guesses this is YCbCr and emits a warning 1465 * We would rather not guess. Then the user knows 1466 * To read this as a Raster if at all 1467 */ 1468 cinfo->jpeg_color_space = JCS_UNKNOWN; 1469 cinfo->out_color_space = JCS_UNKNOWN; 1470 } 1471 } 1472 break; 1473 #ifdef YCCALPHA 1474 case JCS_YCC: 1475 cinfo->out_color_space = JCS_YCC; 1476 break; 1477 #endif 1478 case JCS_YCCK: 1479 if ((cinfo->saw_Adobe_marker) && (cinfo->Adobe_transform != 2)) { 1480 /* 1481 * IJG guesses this is YCCK and emits a warning 1482 * We would rather not guess. Then the user knows 1483 * To read this as a Raster if at all 1484 */ 1485 cinfo->jpeg_color_space = JCS_UNKNOWN; 1486 cinfo->out_color_space = JCS_UNKNOWN; 1487 } else { 1488 /* There is no support for YCCK on jfx side, so request RGB output */ 1489 cinfo->out_color_space = JCS_RGB; 1490 } 1491 break; 1492 case JCS_CMYK: 1493 /* 1494 * IJG assumes all unidentified 4-channels are CMYK. 1495 * We assume that only if the second two channels are 1496 * not subsampled (either horizontally or vertically). 1497 * If they are, we assume YCCK. 1498 */ 1499 h_samp0 = cinfo->comp_info[0].h_samp_factor; 1500 h_samp1 = cinfo->comp_info[1].h_samp_factor; 1501 h_samp2 = cinfo->comp_info[2].h_samp_factor; 1502 1503 v_samp0 = cinfo->comp_info[0].v_samp_factor; 1504 v_samp1 = cinfo->comp_info[1].v_samp_factor; 1505 v_samp2 = cinfo->comp_info[2].v_samp_factor; 1506 1507 if ((h_samp1 > h_samp0) && (h_samp2 > h_samp0) || 1508 (v_samp1 > v_samp0) && (v_samp2 > v_samp0)) { 1509 cinfo->jpeg_color_space = JCS_YCCK; 1510 /* Leave the output space as CMYK */ 1511 } 1512 1513 /* There is no support for CMYK on jfx side, so request RGB output */ 1514 cinfo->out_color_space = JCS_RGB; 1515 } 1516 RELEASE_ARRAYS(env, data, src->next_input_byte); 1517 1518 /* read icc profile data */ 1519 profileData = read_icc_profile(env, cinfo); 1520 1521 if ((*env)->ExceptionCheck(env)) { 1522 free(cinfo->src); 1523 free(cinfo); 1524 free(jerr_mgr); 1525 return 0; 1526 } 1527 1528 (*env)->CallVoidMethod(env, this, 1529 JPEGImageLoader_setInputAttributesID, 1530 cinfo->image_width, 1531 cinfo->image_height, 1532 cinfo->jpeg_color_space, 1533 cinfo->out_color_space, 1534 cinfo->num_components, 1535 profileData); 1536 if ((*env)->ExceptionCheck(env)) { 1537 free(cinfo->src); 1538 free(cinfo); 1539 free(jerr_mgr); 1540 return 0; 1541 } 1542 } 1543 1544 return ptr_to_jlong(data); 1545 } 1546 1547 JNIEXPORT jint JNICALL Java_com_sun_javafx_iio_jpeg_JPEGImageLoader_startDecompression 1548 (JNIEnv *env, jobject this, jlong ptr, jint outCS, jint dest_width, jint dest_height) { 1549 imageIODataPtr data = (imageIODataPtr) jlong_to_ptr(ptr); 1550 j_decompress_ptr cinfo = (j_decompress_ptr) data->jpegObj; 1551 struct jpeg_source_mgr *src = cinfo->src; 1552 sun_jpeg_error_ptr jerr; 1553 1554 jfloat x_scale; 1555 jfloat y_scale; 1556 jfloat max_scale; 1557 1558 if (GET_ARRAYS(env, data, &cinfo->src->next_input_byte) == NOT_OK) { 1559 ThrowByName(env, 1560 "java/io/IOException", 1561 "Array pin failed"); 1562 return JCS_UNKNOWN; 1563 } 1564 1565 cinfo = (j_decompress_ptr) data->jpegObj; 1566 1567 /* Establish the setjmp return context for sun_jpeg_error_exit to use. */ 1568 jerr = (sun_jpeg_error_ptr) cinfo->err; 1569 1570 if (setjmp(jerr->setjmp_buffer)) { 1571 /* If we get here, the JPEG code has signaled an error 1572 while initializing compression. */ 1573 RELEASE_ARRAYS(env, data, cinfo->src->next_input_byte); 1574 if (!(*env)->ExceptionOccurred(env)) { 1575 char buffer[JMSG_LENGTH_MAX]; 1576 (*cinfo->err->format_message) ((struct jpeg_common_struct *) cinfo, 1577 buffer); 1578 ThrowByName(env, "java/io/IOException", buffer); 1579 } 1580 return JCS_UNKNOWN; 1581 } 1582 1583 cinfo->out_color_space = outCS; 1584 1585 /* decide how much we want to sub-sample the incoming jpeg image. 1586 * The libjpeg docs say: 1587 * 1588 * unsigned int scale_num, scale_denom 1589 * 1590 * Scale the image by the fraction scale_num/scale_denom. Default is 1591 * 1/1, or no scaling. Currently, the only supported scaling ratios 1592 * are 1/1, 1/2, 1/4, and 1/8. (The library design allows for arbitrary 1593 * scaling ratios but this is not likely to be implemented any time soon.) 1594 * Smaller scaling ratios permit significantly faster decoding since 1595 * fewer pixels need be processed and a simpler IDCT method can be used. 1596 */ 1597 1598 cinfo->scale_num = 1; 1599 1600 x_scale = (jfloat) dest_width / (jfloat) cinfo->image_width; 1601 y_scale = (jfloat) dest_height / (jfloat) cinfo->image_height; 1602 max_scale = x_scale > y_scale ? x_scale : y_scale; 1603 1604 if (max_scale > 0.5) { 1605 cinfo->scale_denom = 1; 1606 } else if (max_scale > 0.25) { 1607 cinfo->scale_denom = 2; 1608 } else if (max_scale > 0.125) { 1609 cinfo->scale_denom = 4; 1610 } else { 1611 cinfo->scale_denom = 8; 1612 } 1613 1614 jpeg_start_decompress(cinfo); 1615 1616 RELEASE_ARRAYS(env, data, cinfo->src->next_input_byte); 1617 (*env)->CallVoidMethod(env, this, 1618 JPEGImageLoader_setOutputAttributesID, 1619 cinfo->output_width, 1620 cinfo->output_height); 1621 1622 return cinfo->output_components; 1623 } 1624 1625 #define SAFE_TO_MULT(a, b) (((a) > 0) && ((b) >= 0) && ((0x7fffffff / (a)) > (b))) 1626 1627 JNIEXPORT jboolean JNICALL Java_com_sun_javafx_iio_jpeg_JPEGImageLoader_decompressIndirect 1628 (JNIEnv *env, jobject this, jlong ptr, jboolean report_progress, jbyteArray barray) { 1629 imageIODataPtr data = (imageIODataPtr) jlong_to_ptr(ptr); 1630 j_decompress_ptr cinfo = (j_decompress_ptr) data->jpegObj; 1631 struct jpeg_source_mgr *src = cinfo->src; 1632 sun_jpeg_error_ptr jerr; 1633 int bytes_per_row = cinfo->output_width * cinfo->output_components; 1634 int offset = 0; 1635 JSAMPROW scanline_ptr = (JSAMPROW) malloc(bytes_per_row * sizeof (JSAMPLE)); 1636 1637 if (scanline_ptr == NULL) { 1638 ThrowByName(env, 1639 "java/lang/OutOfMemoryError", 1640 "Reading JPEG Stream"); 1641 return JNI_FALSE; 1642 } 1643 1644 if (!SAFE_TO_MULT(cinfo->output_width, cinfo->output_components) || 1645 !SAFE_TO_MULT(bytes_per_row, cinfo->output_height) || 1646 ((*env)->GetArrayLength(env, barray) < 1647 (bytes_per_row * cinfo->output_height))) 1648 { 1649 free(scanline_ptr); 1650 ThrowByName(env, 1651 "java/lang/OutOfMemoryError", 1652 "Reading JPEG Stream"); 1653 return JNI_FALSE; 1654 } 1655 1656 if (GET_ARRAYS(env, data, &cinfo->src->next_input_byte) == NOT_OK) { 1657 free(scanline_ptr); 1658 ThrowByName(env, 1659 "java/io/IOException", 1660 "Array pin failed"); 1661 return JNI_FALSE; 1662 } 1663 1664 /* Establish the setjmp return context for sun_jpeg_error_exit to use. */ 1665 jerr = (sun_jpeg_error_ptr) cinfo->err; 1666 1667 if (setjmp(jerr->setjmp_buffer)) { 1668 /* If we get here, the JPEG code has signaled an error 1669 while reading. */ 1670 if (!(*env)->ExceptionOccurred(env)) { 1671 char buffer[JMSG_LENGTH_MAX]; 1672 (*cinfo->err->format_message) ((struct jpeg_common_struct *) cinfo, 1673 buffer); 1674 ThrowByName(env, "java/io/IOException", buffer); 1675 } 1676 free(scanline_ptr); 1677 RELEASE_ARRAYS(env, data, cinfo->src->next_input_byte); 1678 return JNI_FALSE; 1679 } 1680 1681 while (cinfo->output_scanline < cinfo->output_height) { 1682 int num_scanlines; 1683 if (report_progress == JNI_TRUE) { 1684 RELEASE_ARRAYS(env, data, cinfo->src->next_input_byte); 1685 (*env)->CallVoidMethod(env, this, 1686 JPEGImageLoader_updateImageProgressID, 1687 cinfo->output_scanline); 1688 if ((*env)->ExceptionCheck(env)) { 1689 free(scanline_ptr); 1690 return JNI_FALSE; 1691 } 1692 if (GET_ARRAYS(env, data, &cinfo->src->next_input_byte) == NOT_OK) { 1693 ThrowByName(env, 1694 "java/io/IOException", 1695 "Array pin failed"); 1696 free(scanline_ptr); 1697 return JNI_FALSE; 1698 } 1699 } 1700 1701 num_scanlines = jpeg_read_scanlines(cinfo, &scanline_ptr, 1); 1702 if (num_scanlines == 1) { 1703 jboolean iscopy = FALSE; 1704 jbyte *body = (*env)->GetPrimitiveArrayCritical(env, barray, &iscopy); 1705 if (body == NULL) { 1706 fprintf(stderr, "decompressIndirect: GetPrimitiveArrayCritical returns NULL: out of memory\n"); 1707 free(scanline_ptr); 1708 RELEASE_ARRAYS(env, data, cinfo->src->next_input_byte); 1709 return JNI_FALSE; 1710 } 1711 memcpy(body+offset,scanline_ptr, bytes_per_row); 1712 (*env)->ReleasePrimitiveArrayCritical(env, barray, body, JNI_ABORT); 1713 offset += bytes_per_row; 1714 } 1715 } 1716 1717 if (report_progress == JNI_TRUE) { 1718 RELEASE_ARRAYS(env, data, cinfo->src->next_input_byte); 1719 (*env)->CallVoidMethod(env, this, 1720 JPEGImageLoader_updateImageProgressID, 1721 cinfo->output_height); 1722 if ((*env)->ExceptionCheck(env)) { 1723 free(scanline_ptr); 1724 return JNI_FALSE; 1725 } 1726 if (GET_ARRAYS(env, data, &cinfo->src->next_input_byte) == NOT_OK) { 1727 ThrowByName(env, 1728 "java/io/IOException", 1729 "Array pin failed"); 1730 free(scanline_ptr); 1731 return JNI_FALSE; 1732 } 1733 } 1734 1735 jpeg_finish_decompress(cinfo); 1736 free(scanline_ptr); 1737 1738 RELEASE_ARRAYS(env, data, cinfo->src->next_input_byte); 1739 return JNI_TRUE; 1740 }