diff --git a/src/main/c/VipsImage.c b/src/main/c/VipsImage.c index 0dcdbfba..fa175f26 100644 --- a/src/main/c/VipsImage.c +++ b/src/main/c/VipsImage.c @@ -43,6 +43,21 @@ new_from_buffer(JNIEnv *env, void *buffer, int length) return im; } +static VipsImage * +new_from_buffer_with_options(JNIEnv *env, void *buffer, int length, jstring options) +{ + const char *options_str = (*env)->GetStringUTFChars(env, options, NULL); + VipsImage *im = NULL; + if ((im = vips_image_new_from_buffer(buffer, length, options_str, NULL)) == NULL) + { + (*env)->ReleaseStringUTFChars(env, options, options_str); + throwVipsException(env, "Unable to decode image buffer"); + return NULL; + } + (*env)->ReleaseStringUTFChars(env, options, options_str); + return im; +} + JNIEXPORT void JNICALL Java_com_criteo_vips_VipsImage_blackNative(JNIEnv *env, jobject obj, jint width, jint height) { @@ -86,7 +101,7 @@ Java_com_criteo_vips_VipsImage_initFieldIDs(JNIEnv *env, jobject cls) } JNIEXPORT void JNICALL -Java_com_criteo_vips_VipsImage_newFromByteBuffer(JNIEnv *env, jobject obj, jobject buffer, jint length) +Java_com_criteo_vips_VipsImage_newFromByteBuffer__Ljava_nio_ByteBuffer_2I(JNIEnv *env, jobject obj, jobject buffer, jint length) { void *buf = (*env)->GetDirectBufferAddress(env, buffer); @@ -95,7 +110,16 @@ Java_com_criteo_vips_VipsImage_newFromByteBuffer(JNIEnv *env, jobject obj, jobje } JNIEXPORT void JNICALL -Java_com_criteo_vips_VipsImage_newFromBuffer(JNIEnv *env, jobject obj, jbyteArray buffer, jint length) +Java_com_criteo_vips_VipsImage_newFromByteBuffer__Ljava_nio_ByteBuffer_2ILjava_lang_String_2(JNIEnv *env, jobject obj, jobject buffer, jint length, jstring options) +{ + void *buf = (*env)->GetDirectBufferAddress(env, buffer); + + (*env)->SetLongField(env, obj, handle_fid, (jlong) new_from_buffer_with_options(env, buf, length, options)); + (*env)->SetLongField(env, obj, buffer_fid, (jlong) NULL); +} + +JNIEXPORT void JNICALL +Java_com_criteo_vips_VipsImage_newFromBuffer___3BI(JNIEnv *env, jobject obj, jbyteArray buffer, jint length) { void *internal_buffer = NULL; VipsImage* im = NULL; @@ -114,6 +138,26 @@ Java_com_criteo_vips_VipsImage_newFromBuffer(JNIEnv *env, jobject obj, jbyteArra (*env)->SetLongField(env, obj, buffer_fid, (jlong) internal_buffer); } +JNIEXPORT void JNICALL +Java_com_criteo_vips_VipsImage_newFromBuffer___3BILjava_lang_String_2(JNIEnv *env, jobject obj, jbyteArray buffer, jint length, jstring options) +{ + void *internal_buffer = NULL; + VipsImage* im = NULL; + size_t len = length * sizeof(jbyte); + + if ((internal_buffer = vips_tracked_malloc(len)) == NULL) + { + (*env)->SetLongField(env, obj, handle_fid, (jlong) NULL); + (*env)->SetLongField(env, obj, buffer_fid, (jlong) NULL); + throwVipsException(env, "Unable to allocate memory"); + return; + } + (*env)->GetByteArrayRegion(env, buffer, 0, len, internal_buffer); + im = new_from_buffer_with_options(env, internal_buffer, length, options); + (*env)->SetLongField(env, obj, handle_fid, (jlong) im); + (*env)->SetLongField(env, obj, buffer_fid, (jlong) internal_buffer); +} + JNIEXPORT void JNICALL Java_com_criteo_vips_VipsImage_newFromFile(JNIEnv *env, jobject obj, jstring filename) { diff --git a/src/main/c/VipsImage.h b/src/main/c/VipsImage.h index d9cce72b..a4afd620 100644 --- a/src/main/c/VipsImage.h +++ b/src/main/c/VipsImage.h @@ -20,17 +20,33 @@ JNIEXPORT void JNICALL Java_com_criteo_vips_VipsImage_initFieldIDs * Method: newFromByteBuffer * Signature: (Ljava/nio/ByteBuffer;I)V */ -JNIEXPORT void JNICALL Java_com_criteo_vips_VipsImage_newFromByteBuffer +JNIEXPORT void JNICALL Java_com_criteo_vips_VipsImage_newFromByteBuffer__Ljava_nio_ByteBuffer_2I (JNIEnv *, jobject, jobject, jint); +/* + * Class: com_criteo_vips_VipsImage + * Method: newFromByteBuffer + * Signature: (Ljava/nio/ByteBuffer;ILjava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_com_criteo_vips_VipsImage_newFromByteBuffer__Ljava_nio_ByteBuffer_2ILjava_lang_String_2 + (JNIEnv *, jobject, jobject, jint, jstring); + /* * Class: com_criteo_vips_VipsImage * Method: newFromBuffer * Signature: ([BI)V */ -JNIEXPORT void JNICALL Java_com_criteo_vips_VipsImage_newFromBuffer +JNIEXPORT void JNICALL Java_com_criteo_vips_VipsImage_newFromBuffer___3BI (JNIEnv *, jobject, jbyteArray, jint); +/* + * Class: com_criteo_vips_VipsImage + * Method: newFromBuffer + * Signature: ([BILjava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_com_criteo_vips_VipsImage_newFromBuffer___3BILjava_lang_String_2 + (JNIEnv *, jobject, jbyteArray, jint, jstring); + /* * Class: com_criteo_vips_VipsImage * Method: newFromFile diff --git a/src/main/java/com/criteo/vips/VipsImage.java b/src/main/java/com/criteo/vips/VipsImage.java index 8397672d..9a550f18 100644 --- a/src/main/java/com/criteo/vips/VipsImage.java +++ b/src/main/java/com/criteo/vips/VipsImage.java @@ -43,18 +43,30 @@ public class VipsImage extends Vips implements Image { private native void newFromByteBuffer(ByteBuffer buffer, int length) throws VipsException; + private native void newFromByteBuffer(ByteBuffer buffer, int length, String options) throws VipsException; + private native void newFromBuffer(byte[] buffer, int length) throws VipsException; + private native void newFromBuffer(byte[] buffer, int length, String options) throws VipsException; + private native void newFromFile(String filename) throws VipsException; public VipsImage(ByteBuffer buffer, int length) throws VipsException { newFromByteBuffer(buffer, length); } + public VipsImage(ByteBuffer buffer, int length, String options) throws VipsException { + newFromByteBuffer(buffer, length, options); + } + public VipsImage(byte[] buffer, int length) throws VipsException { newFromBuffer(buffer, length); } + public VipsImage(byte[] buffer, int length, String options) throws VipsException { + newFromBuffer(buffer, length, options); + } + public VipsImage(VipsImage image, PixelPacket color) throws VipsException { newFromImage(image, color); } diff --git a/src/test/java/com/criteo/vips/VipsImageTest.java b/src/test/java/com/criteo/vips/VipsImageTest.java index fba1b472..b3a81925 100644 --- a/src/test/java/com/criteo/vips/VipsImageTest.java +++ b/src/test/java/com/criteo/vips/VipsImageTest.java @@ -924,4 +924,22 @@ public void TestWriteJPEGFromByteArrayShouldNotThrows(@FromDataPoints("filenames assertNotNull(out); } } + + @Test + public void TestShouldThrowErrorOnOperationIfTruncatedImage() throws IOException, VipsException { + byte[] bufferArray = VipsTestUtils.getByteArray("truncated_image_missing_20_bytes.jpg"); + + // Should succeed + VipsImage image = new VipsImage(bufferArray, bufferArray.length); + image.writeToArray(VipsImageFormat.JPG, false); + + try { + // Should fail + VipsImage truncatedImage = new VipsImage(bufferArray, bufferArray.length, "fail-on=truncated"); + truncatedImage.writeToArray(VipsImageFormat.JPG, false); + fail("should throw exception for truncated image if fail-on is set"); + } catch (VipsException e) { + // expected + } + } } diff --git a/src/test/resources/truncated_image_missing_20_bytes.jpg b/src/test/resources/truncated_image_missing_20_bytes.jpg new file mode 100644 index 00000000..ab85b83b Binary files /dev/null and b/src/test/resources/truncated_image_missing_20_bytes.jpg differ