1 /*
2  * Copyright (C)2011-2020 D. R. Commander.  All Rights Reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * - Redistributions of source code must retain the above copyright notice,
8  *   this list of conditions and the following disclaimer.
9  * - Redistributions in binary form must reproduce the above copyright notice,
10  *   this list of conditions and the following disclaimer in the documentation
11  *   and/or other materials provided with the distribution.
12  * - Neither the name of the libjpeg-turbo Project nor the names of its
13  *   contributors may be used to endorse or promote products derived from this
14  *   software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS",
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <stdlib.h>
30 #include <string.h>
31 #include "turbojpeg.h"
32 #ifdef WIN32
33 #include "tjutil.h"
34 #endif
35 #include <jni.h>
36 #include "java/org_libjpegturbo_turbojpeg_TJCompressor.h"
37 #include "java/org_libjpegturbo_turbojpeg_TJDecompressor.h"
38 #include "java/org_libjpegturbo_turbojpeg_TJTransformer.h"
39 #include "java/org_libjpegturbo_turbojpeg_TJ.h"
40 
41 #define BAILIF0(f) { \
42   if (!(f) || (*env)->ExceptionCheck(env)) { \
43     goto bailout; \
44   } \
45 }
46 
47 #define THROW(msg, exceptionClass) { \
48   jclass _exccls = (*env)->FindClass(env, exceptionClass); \
49   \
50   BAILIF0(_exccls); \
51   (*env)->ThrowNew(env, _exccls, msg); \
52   goto bailout; \
53 }
54 
55 #define THROW_TJ() { \
56   jclass _exccls; \
57   jmethodID _excid; \
58   jobject _excobj; \
59   jstring _errstr; \
60   \
61   BAILIF0(_errstr = (*env)->NewStringUTF(env, tjGetErrorStr2(handle))); \
62   BAILIF0(_exccls = (*env)->FindClass(env, \
63     "org/libjpegturbo/turbojpeg/TJException")); \
64   BAILIF0(_excid = (*env)->GetMethodID(env, _exccls, "<init>", \
65                                        "(Ljava/lang/String;I)V")); \
66   BAILIF0(_excobj = (*env)->NewObject(env, _exccls, _excid, _errstr, \
67                                       tjGetErrorCode(handle))); \
68   (*env)->Throw(env, _excobj); \
69   goto bailout; \
70 }
71 
72 #define THROW_ARG(msg)  THROW(msg, "java/lang/IllegalArgumentException")
73 
74 #define THROW_MEM() \
75   THROW("Memory allocation failure", "java/lang/OutOfMemoryError");
76 
77 #define GET_HANDLE() \
78   jclass _cls = (*env)->GetObjectClass(env, obj); \
79   jfieldID _fid; \
80   \
81   BAILIF0(_cls); \
82   BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "handle", "J")); \
83   handle = (tjhandle)(size_t)(*env)->GetLongField(env, obj, _fid);
84 
85 #ifdef _WIN32
86 #define setenv(envvar, value, dummy)  _putenv_s(envvar, value)
87 #endif
88 
89 #define PROP2ENV(property, envvar) { \
90   if ((jName = (*env)->NewStringUTF(env, property)) != NULL && \
91       (jValue = (*env)->CallStaticObjectMethod(env, cls, mid, \
92                                                jName)) != NULL) { \
93     if ((value = (*env)->GetStringUTFChars(env, jValue, 0)) != NULL) { \
94       setenv(envvar, value, 1); \
95       (*env)->ReleaseStringUTFChars(env, jValue, value); \
96     } \
97   } \
98 }
99 
100 #define SAFE_RELEASE(javaArray, cArray) { \
101   if (javaArray && cArray) \
102     (*env)->ReleasePrimitiveArrayCritical(env, javaArray, (void *)cArray, 0); \
103   cArray = NULL; \
104 }
105 
ProcessSystemProperties(JNIEnv * env)106 static int ProcessSystemProperties(JNIEnv *env)
107 {
108   jclass cls;
109   jmethodID mid;
110   jstring jName, jValue;
111   const char *value;
112 
113   BAILIF0(cls = (*env)->FindClass(env, "java/lang/System"));
114   BAILIF0(mid = (*env)->GetStaticMethodID(env, cls, "getProperty",
115     "(Ljava/lang/String;)Ljava/lang/String;"));
116 
117   PROP2ENV("turbojpeg.optimize", "TJ_OPTIMIZE");
118   PROP2ENV("turbojpeg.arithmetic", "TJ_ARITHMETIC");
119   PROP2ENV("turbojpeg.restart", "TJ_RESTART");
120   PROP2ENV("turbojpeg.progressive", "TJ_PROGRESSIVE");
121   return 0;
122 
123 bailout:
124   return -1;
125 }
126 
127 /* TurboJPEG 1.2.x: TJ::bufSize() */
Java_org_libjpegturbo_turbojpeg_TJ_bufSize(JNIEnv * env,jclass cls,jint width,jint height,jint jpegSubsamp)128 JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJ_bufSize
129   (JNIEnv *env, jclass cls, jint width, jint height, jint jpegSubsamp)
130 {
131   jint retval = (jint)tjBufSize(width, height, jpegSubsamp);
132 
133   if (retval == -1) THROW_ARG(tjGetErrorStr());
134 
135 bailout:
136   return retval;
137 }
138 
139 /* TurboJPEG 1.4.x: TJ::bufSizeYUV() */
Java_org_libjpegturbo_turbojpeg_TJ_bufSizeYUV__IIII(JNIEnv * env,jclass cls,jint width,jint pad,jint height,jint subsamp)140 JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJ_bufSizeYUV__IIII
141   (JNIEnv *env, jclass cls, jint width, jint pad, jint height, jint subsamp)
142 {
143   jint retval = (jint)tjBufSizeYUV2(width, pad, height, subsamp);
144 
145   if (retval == -1) THROW_ARG(tjGetErrorStr());
146 
147 bailout:
148   return retval;
149 }
150 
151 /* TurboJPEG 1.2.x: TJ::bufSizeYUV() */
Java_org_libjpegturbo_turbojpeg_TJ_bufSizeYUV__III(JNIEnv * env,jclass cls,jint width,jint height,jint subsamp)152 JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJ_bufSizeYUV__III
153   (JNIEnv *env, jclass cls, jint width, jint height, jint subsamp)
154 {
155   return Java_org_libjpegturbo_turbojpeg_TJ_bufSizeYUV__IIII(env, cls, width,
156                                                              4, height,
157                                                              subsamp);
158 }
159 
160 /* TurboJPEG 1.4.x: TJ::planeSizeYUV() */
Java_org_libjpegturbo_turbojpeg_TJ_planeSizeYUV__IIIII(JNIEnv * env,jclass cls,jint componentID,jint width,jint stride,jint height,jint subsamp)161 JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJ_planeSizeYUV__IIIII
162   (JNIEnv *env, jclass cls, jint componentID, jint width, jint stride,
163    jint height, jint subsamp)
164 {
165   jint retval = (jint)tjPlaneSizeYUV(componentID, width, stride, height,
166                                      subsamp);
167 
168   if (retval == -1) THROW_ARG(tjGetErrorStr());
169 
170 bailout:
171   return retval;
172 }
173 
174 /* TurboJPEG 1.4.x: TJ::planeWidth() */
Java_org_libjpegturbo_turbojpeg_TJ_planeWidth__III(JNIEnv * env,jclass cls,jint componentID,jint width,jint subsamp)175 JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJ_planeWidth__III
176   (JNIEnv *env, jclass cls, jint componentID, jint width, jint subsamp)
177 {
178   jint retval = (jint)tjPlaneWidth(componentID, width, subsamp);
179 
180   if (retval == -1) THROW_ARG(tjGetErrorStr());
181 
182 bailout:
183   return retval;
184 }
185 
186 /* TurboJPEG 1.4.x: TJ::planeHeight() */
Java_org_libjpegturbo_turbojpeg_TJ_planeHeight__III(JNIEnv * env,jclass cls,jint componentID,jint height,jint subsamp)187 JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJ_planeHeight__III
188   (JNIEnv *env, jclass cls, jint componentID, jint height, jint subsamp)
189 {
190   jint retval = (jint)tjPlaneHeight(componentID, height, subsamp);
191 
192   if (retval == -1) THROW_ARG(tjGetErrorStr());
193 
194 bailout:
195   return retval;
196 }
197 
198 /* TurboJPEG 1.2.x: TJCompressor::init() */
Java_org_libjpegturbo_turbojpeg_TJCompressor_init(JNIEnv * env,jobject obj)199 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_init
200   (JNIEnv *env, jobject obj)
201 {
202   jclass cls;
203   jfieldID fid;
204   tjhandle handle;
205 
206   if ((handle = tjInitCompress()) == NULL)
207     THROW(tjGetErrorStr(), "org/libjpegturbo/turbojpeg/TJException");
208 
209   BAILIF0(cls = (*env)->GetObjectClass(env, obj));
210   BAILIF0(fid = (*env)->GetFieldID(env, cls, "handle", "J"));
211   (*env)->SetLongField(env, obj, fid, (size_t)handle);
212 
213 bailout:
214   return;
215 }
216 
TJCompressor_compress(JNIEnv * env,jobject obj,jarray src,jint srcElementSize,jint x,jint y,jint width,jint pitch,jint height,jint pf,jbyteArray dst,jint jpegSubsamp,jint jpegQual,jint flags)217 static jint TJCompressor_compress
218   (JNIEnv *env, jobject obj, jarray src, jint srcElementSize, jint x, jint y,
219    jint width, jint pitch, jint height, jint pf, jbyteArray dst,
220    jint jpegSubsamp, jint jpegQual, jint flags)
221 {
222   tjhandle handle = 0;
223   unsigned long jpegSize = 0;
224   jsize arraySize = 0, actualPitch;
225   unsigned char *srcBuf = NULL, *jpegBuf = NULL;
226 
227   GET_HANDLE();
228 
229   if (pf < 0 || pf >= org_libjpegturbo_turbojpeg_TJ_NUMPF || width < 1 ||
230       height < 1 || pitch < 0)
231     THROW_ARG("Invalid argument in compress()");
232   if (org_libjpegturbo_turbojpeg_TJ_NUMPF != TJ_NUMPF)
233     THROW_ARG("Mismatch between Java and C API");
234 
235   actualPitch = (pitch == 0) ? width * tjPixelSize[pf] : pitch;
236   arraySize = (y + height - 1) * actualPitch + (x + width) * tjPixelSize[pf];
237   if ((*env)->GetArrayLength(env, src) * srcElementSize < arraySize)
238     THROW_ARG("Source buffer is not large enough");
239   jpegSize = tjBufSize(width, height, jpegSubsamp);
240   if ((*env)->GetArrayLength(env, dst) < (jsize)jpegSize)
241     THROW_ARG("Destination buffer is not large enough");
242 
243   if (ProcessSystemProperties(env) < 0) goto bailout;
244 
245   BAILIF0(srcBuf = (*env)->GetPrimitiveArrayCritical(env, src, 0));
246   BAILIF0(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, dst, 0));
247 
248   if (tjCompress2(handle, &srcBuf[y * actualPitch + x * tjPixelSize[pf]],
249                   width, pitch, height, pf, &jpegBuf, &jpegSize, jpegSubsamp,
250                   jpegQual, flags | TJFLAG_NOREALLOC) == -1) {
251     SAFE_RELEASE(dst, jpegBuf);
252     SAFE_RELEASE(src, srcBuf);
253     THROW_TJ();
254   }
255 
256 bailout:
257   SAFE_RELEASE(dst, jpegBuf);
258   SAFE_RELEASE(src, srcBuf);
259   return (jint)jpegSize;
260 }
261 
262 /* TurboJPEG 1.3.x: TJCompressor::compress() byte source */
Java_org_libjpegturbo_turbojpeg_TJCompressor_compress___3BIIIIII_3BIII(JNIEnv * env,jobject obj,jbyteArray src,jint x,jint y,jint width,jint pitch,jint height,jint pf,jbyteArray dst,jint jpegSubsamp,jint jpegQual,jint flags)263 JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compress___3BIIIIII_3BIII
264   (JNIEnv *env, jobject obj, jbyteArray src, jint x, jint y, jint width,
265    jint pitch, jint height, jint pf, jbyteArray dst, jint jpegSubsamp,
266    jint jpegQual, jint flags)
267 {
268   return TJCompressor_compress(env, obj, src, 1, x, y, width, pitch, height,
269                                pf, dst, jpegSubsamp, jpegQual, flags);
270 }
271 
272 /* TurboJPEG 1.2.x: TJCompressor::compress() byte source */
Java_org_libjpegturbo_turbojpeg_TJCompressor_compress___3BIIII_3BIII(JNIEnv * env,jobject obj,jbyteArray src,jint width,jint pitch,jint height,jint pf,jbyteArray dst,jint jpegSubsamp,jint jpegQual,jint flags)273 JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compress___3BIIII_3BIII
274   (JNIEnv *env, jobject obj, jbyteArray src, jint width, jint pitch,
275    jint height, jint pf, jbyteArray dst, jint jpegSubsamp, jint jpegQual,
276    jint flags)
277 {
278   return TJCompressor_compress(env, obj, src, 1, 0, 0, width, pitch, height,
279                                pf, dst, jpegSubsamp, jpegQual, flags);
280 }
281 
282 /* TurboJPEG 1.3.x: TJCompressor::compress() int source */
Java_org_libjpegturbo_turbojpeg_TJCompressor_compress___3IIIIIII_3BIII(JNIEnv * env,jobject obj,jintArray src,jint x,jint y,jint width,jint stride,jint height,jint pf,jbyteArray dst,jint jpegSubsamp,jint jpegQual,jint flags)283 JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compress___3IIIIIII_3BIII
284   (JNIEnv *env, jobject obj, jintArray src, jint x, jint y, jint width,
285    jint stride, jint height, jint pf, jbyteArray dst, jint jpegSubsamp,
286    jint jpegQual, jint flags)
287 {
288   if (pf < 0 || pf >= org_libjpegturbo_turbojpeg_TJ_NUMPF)
289     THROW_ARG("Invalid argument in compress()");
290   if (tjPixelSize[pf] != sizeof(jint))
291     THROW_ARG("Pixel format must be 32-bit when compressing from an integer buffer.");
292 
293   return TJCompressor_compress(env, obj, src, sizeof(jint), x, y, width,
294                                stride * sizeof(jint), height, pf, dst,
295                                jpegSubsamp, jpegQual, flags);
296 
297 bailout:
298   return 0;
299 }
300 
301 /* TurboJPEG 1.2.x: TJCompressor::compress() int source */
Java_org_libjpegturbo_turbojpeg_TJCompressor_compress___3IIIII_3BIII(JNIEnv * env,jobject obj,jintArray src,jint width,jint stride,jint height,jint pf,jbyteArray dst,jint jpegSubsamp,jint jpegQual,jint flags)302 JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compress___3IIIII_3BIII
303   (JNIEnv *env, jobject obj, jintArray src, jint width, jint stride,
304    jint height, jint pf, jbyteArray dst, jint jpegSubsamp, jint jpegQual,
305    jint flags)
306 {
307   if (pf < 0 || pf >= org_libjpegturbo_turbojpeg_TJ_NUMPF)
308     THROW_ARG("Invalid argument in compress()");
309   if (tjPixelSize[pf] != sizeof(jint))
310     THROW_ARG("Pixel format must be 32-bit when compressing from an integer buffer.");
311 
312   return TJCompressor_compress(env, obj, src, sizeof(jint), 0, 0, width,
313                                stride * sizeof(jint), height, pf, dst,
314                                jpegSubsamp, jpegQual, flags);
315 
316 bailout:
317   return 0;
318 }
319 
320 /* TurboJPEG 1.4.x: TJCompressor::compressFromYUV() */
Java_org_libjpegturbo_turbojpeg_TJCompressor_compressFromYUV___3_3B_3II_3III_3BII(JNIEnv * env,jobject obj,jobjectArray srcobjs,jintArray jSrcOffsets,jint width,jintArray jSrcStrides,jint height,jint subsamp,jbyteArray dst,jint jpegQual,jint flags)321 JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_compressFromYUV___3_3B_3II_3III_3BII
322   (JNIEnv *env, jobject obj, jobjectArray srcobjs, jintArray jSrcOffsets,
323    jint width, jintArray jSrcStrides, jint height, jint subsamp,
324    jbyteArray dst, jint jpegQual, jint flags)
325 {
326   tjhandle handle = 0;
327   unsigned long jpegSize = 0;
328   jbyteArray jSrcPlanes[3] = { NULL, NULL, NULL };
329   const unsigned char *srcPlanesTmp[3] = { NULL, NULL, NULL };
330   const unsigned char *srcPlanes[3] = { NULL, NULL, NULL };
331   int *srcOffsetsTmp = NULL, srcOffsets[3] = { 0, 0, 0 };
332   int *srcStridesTmp = NULL, srcStrides[3] = { 0, 0, 0 };
333   unsigned char *jpegBuf = NULL;
334   int nc = (subsamp == org_libjpegturbo_turbojpeg_TJ_SAMP_GRAY ? 1 : 3), i;
335 
336   GET_HANDLE();
337 
338   if (subsamp < 0 || subsamp >= org_libjpegturbo_turbojpeg_TJ_NUMSAMP)
339     THROW_ARG("Invalid argument in compressFromYUV()");
340   if (org_libjpegturbo_turbojpeg_TJ_NUMSAMP != TJ_NUMSAMP)
341     THROW_ARG("Mismatch between Java and C API");
342 
343   if ((*env)->GetArrayLength(env, srcobjs) < nc)
344     THROW_ARG("Planes array is too small for the subsampling type");
345   if ((*env)->GetArrayLength(env, jSrcOffsets) < nc)
346     THROW_ARG("Offsets array is too small for the subsampling type");
347   if ((*env)->GetArrayLength(env, jSrcStrides) < nc)
348     THROW_ARG("Strides array is too small for the subsampling type");
349 
350   jpegSize = tjBufSize(width, height, subsamp);
351   if ((*env)->GetArrayLength(env, dst) < (jsize)jpegSize)
352     THROW_ARG("Destination buffer is not large enough");
353 
354   if (ProcessSystemProperties(env) < 0) goto bailout;
355 
356   BAILIF0(srcOffsetsTmp =
357           (*env)->GetPrimitiveArrayCritical(env, jSrcOffsets, 0));
358   for (i = 0; i < nc; i++) srcOffsets[i] = srcOffsetsTmp[i];
359   SAFE_RELEASE(jSrcOffsets, srcOffsetsTmp);
360 
361   BAILIF0(srcStridesTmp =
362           (*env)->GetPrimitiveArrayCritical(env, jSrcStrides, 0));
363   for (i = 0; i < nc; i++) srcStrides[i] = srcStridesTmp[i];
364   SAFE_RELEASE(jSrcStrides, srcStridesTmp);
365 
366   for (i = 0; i < nc; i++) {
367     int planeSize = tjPlaneSizeYUV(i, width, srcStrides[i], height, subsamp);
368     int pw = tjPlaneWidth(i, width, subsamp);
369 
370     if (planeSize < 0 || pw < 0)
371       THROW_ARG(tjGetErrorStr());
372 
373     if (srcOffsets[i] < 0)
374       THROW_ARG("Invalid argument in compressFromYUV()");
375     if (srcStrides[i] < 0 && srcOffsets[i] - planeSize + pw < 0)
376       THROW_ARG("Negative plane stride would cause memory to be accessed below plane boundary");
377 
378     BAILIF0(jSrcPlanes[i] = (*env)->GetObjectArrayElement(env, srcobjs, i));
379     if ((*env)->GetArrayLength(env, jSrcPlanes[i]) <
380         srcOffsets[i] + planeSize)
381       THROW_ARG("Source plane is not large enough");
382 
383     BAILIF0(srcPlanesTmp[i] =
384             (*env)->GetPrimitiveArrayCritical(env, jSrcPlanes[i], 0));
385     srcPlanes[i] = &srcPlanesTmp[i][srcOffsets[i]];
386     SAFE_RELEASE(jSrcPlanes[i], srcPlanesTmp[i]);
387   }
388   BAILIF0(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, dst, 0));
389 
390   if (tjCompressFromYUVPlanes(handle, srcPlanes, width, srcStrides, height,
391                               subsamp, &jpegBuf, &jpegSize, jpegQual,
392                               flags | TJFLAG_NOREALLOC) == -1) {
393     SAFE_RELEASE(dst, jpegBuf);
394     THROW_TJ();
395   }
396 
397 bailout:
398   SAFE_RELEASE(dst, jpegBuf);
399   return (jint)jpegSize;
400 }
401 
TJCompressor_encodeYUV(JNIEnv * env,jobject obj,jarray src,jint srcElementSize,jint x,jint y,jint width,jint pitch,jint height,jint pf,jobjectArray dstobjs,jintArray jDstOffsets,jintArray jDstStrides,jint subsamp,jint flags)402 static void TJCompressor_encodeYUV
403   (JNIEnv *env, jobject obj, jarray src, jint srcElementSize, jint x, jint y,
404    jint width, jint pitch, jint height, jint pf, jobjectArray dstobjs,
405    jintArray jDstOffsets, jintArray jDstStrides, jint subsamp, jint flags)
406 {
407   tjhandle handle = 0;
408   jsize arraySize = 0, actualPitch;
409   unsigned char *srcBuf = NULL;
410   jbyteArray jDstPlanes[3] = { NULL, NULL, NULL };
411   unsigned char *dstPlanesTmp[3] = { NULL, NULL, NULL };
412   unsigned char *dstPlanes[3] = { NULL, NULL, NULL };
413   int *dstOffsetsTmp = NULL, dstOffsets[3] = { 0, 0, 0 };
414   int *dstStridesTmp = NULL, dstStrides[3] = { 0, 0, 0 };
415   int nc = (subsamp == org_libjpegturbo_turbojpeg_TJ_SAMP_GRAY ? 1 : 3), i;
416 
417   GET_HANDLE();
418 
419   if (pf < 0 || pf >= org_libjpegturbo_turbojpeg_TJ_NUMPF || width < 1 ||
420       height < 1 || pitch < 0 || subsamp < 0 ||
421       subsamp >= org_libjpegturbo_turbojpeg_TJ_NUMSAMP)
422     THROW_ARG("Invalid argument in encodeYUV()");
423   if (org_libjpegturbo_turbojpeg_TJ_NUMPF != TJ_NUMPF ||
424       org_libjpegturbo_turbojpeg_TJ_NUMSAMP != TJ_NUMSAMP)
425     THROW_ARG("Mismatch between Java and C API");
426 
427   if ((*env)->GetArrayLength(env, dstobjs) < nc)
428     THROW_ARG("Planes array is too small for the subsampling type");
429   if ((*env)->GetArrayLength(env, jDstOffsets) < nc)
430     THROW_ARG("Offsets array is too small for the subsampling type");
431   if ((*env)->GetArrayLength(env, jDstStrides) < nc)
432     THROW_ARG("Strides array is too small for the subsampling type");
433 
434   actualPitch = (pitch == 0) ? width * tjPixelSize[pf] : pitch;
435   arraySize = (y + height - 1) * actualPitch + (x + width) * tjPixelSize[pf];
436   if ((*env)->GetArrayLength(env, src) * srcElementSize < arraySize)
437     THROW_ARG("Source buffer is not large enough");
438 
439   BAILIF0(dstOffsetsTmp =
440           (*env)->GetPrimitiveArrayCritical(env, jDstOffsets, 0));
441   for (i = 0; i < nc; i++) dstOffsets[i] = dstOffsetsTmp[i];
442   SAFE_RELEASE(jDstOffsets, dstOffsetsTmp);
443 
444   BAILIF0(dstStridesTmp =
445           (*env)->GetPrimitiveArrayCritical(env, jDstStrides, 0));
446   for (i = 0; i < nc; i++) dstStrides[i] = dstStridesTmp[i];
447   SAFE_RELEASE(jDstStrides, dstStridesTmp);
448 
449   for (i = 0; i < nc; i++) {
450     int planeSize = tjPlaneSizeYUV(i, width, dstStrides[i], height, subsamp);
451     int pw = tjPlaneWidth(i, width, subsamp);
452 
453     if (planeSize < 0 || pw < 0)
454       THROW_ARG(tjGetErrorStr());
455 
456     if (dstOffsets[i] < 0)
457       THROW_ARG("Invalid argument in encodeYUV()");
458     if (dstStrides[i] < 0 && dstOffsets[i] - planeSize + pw < 0)
459       THROW_ARG("Negative plane stride would cause memory to be accessed below plane boundary");
460 
461     BAILIF0(jDstPlanes[i] = (*env)->GetObjectArrayElement(env, dstobjs, i));
462     if ((*env)->GetArrayLength(env, jDstPlanes[i]) <
463         dstOffsets[i] + planeSize)
464       THROW_ARG("Destination plane is not large enough");
465 
466     BAILIF0(dstPlanesTmp[i] =
467             (*env)->GetPrimitiveArrayCritical(env, jDstPlanes[i], 0));
468     dstPlanes[i] = &dstPlanesTmp[i][dstOffsets[i]];
469     SAFE_RELEASE(jDstPlanes[i], dstPlanesTmp[i]);
470   }
471   BAILIF0(srcBuf = (*env)->GetPrimitiveArrayCritical(env, src, 0));
472 
473   if (tjEncodeYUVPlanes(handle, &srcBuf[y * actualPitch + x * tjPixelSize[pf]],
474                         width, pitch, height, pf, dstPlanes, dstStrides,
475                         subsamp, flags) == -1) {
476     SAFE_RELEASE(src, srcBuf);
477     THROW_TJ();
478   }
479 
480 bailout:
481   SAFE_RELEASE(src, srcBuf);
482 }
483 
484 /* TurboJPEG 1.4.x: TJCompressor::encodeYUV() byte source */
Java_org_libjpegturbo_turbojpeg_TJCompressor_encodeYUV___3BIIIIII_3_3B_3I_3III(JNIEnv * env,jobject obj,jbyteArray src,jint x,jint y,jint width,jint pitch,jint height,jint pf,jobjectArray dstobjs,jintArray jDstOffsets,jintArray jDstStrides,jint subsamp,jint flags)485 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_encodeYUV___3BIIIIII_3_3B_3I_3III
486   (JNIEnv *env, jobject obj, jbyteArray src, jint x, jint y, jint width,
487    jint pitch, jint height, jint pf, jobjectArray dstobjs,
488    jintArray jDstOffsets, jintArray jDstStrides, jint subsamp, jint flags)
489 {
490   TJCompressor_encodeYUV(env, obj, src, 1, x, y, width, pitch, height, pf,
491                          dstobjs, jDstOffsets, jDstStrides, subsamp, flags);
492 }
493 
494 /* TurboJPEG 1.4.x: TJCompressor::encodeYUV() int source */
Java_org_libjpegturbo_turbojpeg_TJCompressor_encodeYUV___3IIIIIII_3_3B_3I_3III(JNIEnv * env,jobject obj,jintArray src,jint x,jint y,jint width,jint stride,jint height,jint pf,jobjectArray dstobjs,jintArray jDstOffsets,jintArray jDstStrides,jint subsamp,jint flags)495 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_encodeYUV___3IIIIIII_3_3B_3I_3III
496   (JNIEnv *env, jobject obj, jintArray src, jint x, jint y, jint width,
497    jint stride, jint height, jint pf, jobjectArray dstobjs,
498    jintArray jDstOffsets, jintArray jDstStrides, jint subsamp, jint flags)
499 {
500   if (pf < 0 || pf >= org_libjpegturbo_turbojpeg_TJ_NUMPF)
501     THROW_ARG("Invalid argument in encodeYUV()");
502   if (tjPixelSize[pf] != sizeof(jint))
503     THROW_ARG("Pixel format must be 32-bit when encoding from an integer buffer.");
504 
505   TJCompressor_encodeYUV(env, obj, src, sizeof(jint), x, y, width,
506                          stride * sizeof(jint), height, pf, dstobjs,
507                          jDstOffsets, jDstStrides, subsamp, flags);
508 
509 bailout:
510   return;
511 }
512 
TJCompressor_encodeYUV_12(JNIEnv * env,jobject obj,jarray src,jint srcElementSize,jint width,jint pitch,jint height,jint pf,jbyteArray dst,jint subsamp,jint flags)513 static void JNICALL TJCompressor_encodeYUV_12
514   (JNIEnv *env, jobject obj, jarray src, jint srcElementSize, jint width,
515    jint pitch, jint height, jint pf, jbyteArray dst, jint subsamp, jint flags)
516 {
517   tjhandle handle = 0;
518   jsize arraySize = 0;
519   unsigned char *srcBuf = NULL, *dstBuf = NULL;
520 
521   GET_HANDLE();
522 
523   if (pf < 0 || pf >= org_libjpegturbo_turbojpeg_TJ_NUMPF || width < 1 ||
524       height < 1 || pitch < 0)
525     THROW_ARG("Invalid argument in encodeYUV()");
526   if (org_libjpegturbo_turbojpeg_TJ_NUMPF != TJ_NUMPF)
527     THROW_ARG("Mismatch between Java and C API");
528 
529   arraySize = (pitch == 0) ? width * tjPixelSize[pf] * height : pitch * height;
530   if ((*env)->GetArrayLength(env, src) * srcElementSize < arraySize)
531     THROW_ARG("Source buffer is not large enough");
532   if ((*env)->GetArrayLength(env, dst) <
533       (jsize)tjBufSizeYUV(width, height, subsamp))
534     THROW_ARG("Destination buffer is not large enough");
535 
536   BAILIF0(srcBuf = (*env)->GetPrimitiveArrayCritical(env, src, 0));
537   BAILIF0(dstBuf = (*env)->GetPrimitiveArrayCritical(env, dst, 0));
538 
539   if (tjEncodeYUV2(handle, srcBuf, width, pitch, height, pf, dstBuf, subsamp,
540                    flags) == -1) {
541     SAFE_RELEASE(dst, dstBuf);
542     SAFE_RELEASE(src, srcBuf);
543     THROW_TJ();
544   }
545 
546 bailout:
547   SAFE_RELEASE(dst, dstBuf);
548   SAFE_RELEASE(src, srcBuf);
549 }
550 
551 /* TurboJPEG 1.2.x: TJCompressor::encodeYUV() byte source */
Java_org_libjpegturbo_turbojpeg_TJCompressor_encodeYUV___3BIIII_3BII(JNIEnv * env,jobject obj,jbyteArray src,jint width,jint pitch,jint height,jint pf,jbyteArray dst,jint subsamp,jint flags)552 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_encodeYUV___3BIIII_3BII
553   (JNIEnv *env, jobject obj, jbyteArray src, jint width, jint pitch,
554    jint height, jint pf, jbyteArray dst, jint subsamp, jint flags)
555 {
556   TJCompressor_encodeYUV_12(env, obj, src, 1, width, pitch, height, pf, dst,
557                             subsamp, flags);
558 }
559 
560 /* TurboJPEG 1.2.x: TJCompressor::encodeYUV() int source */
Java_org_libjpegturbo_turbojpeg_TJCompressor_encodeYUV___3IIIII_3BII(JNIEnv * env,jobject obj,jintArray src,jint width,jint stride,jint height,jint pf,jbyteArray dst,jint subsamp,jint flags)561 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_encodeYUV___3IIIII_3BII
562   (JNIEnv *env, jobject obj, jintArray src, jint width, jint stride,
563    jint height, jint pf, jbyteArray dst, jint subsamp, jint flags)
564 {
565   if (pf < 0 || pf >= org_libjpegturbo_turbojpeg_TJ_NUMPF)
566     THROW_ARG("Invalid argument in encodeYUV()");
567   if (tjPixelSize[pf] != sizeof(jint))
568     THROW_ARG("Pixel format must be 32-bit when encoding from an integer buffer.");
569 
570   TJCompressor_encodeYUV_12(env, obj, src, sizeof(jint), width,
571                             stride * sizeof(jint), height, pf, dst, subsamp,
572                             flags);
573 
574 bailout:
575   return;
576 }
577 
578 /* TurboJPEG 1.2.x: TJCompressor::destroy() */
Java_org_libjpegturbo_turbojpeg_TJCompressor_destroy(JNIEnv * env,jobject obj)579 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJCompressor_destroy
580   (JNIEnv *env, jobject obj)
581 {
582   tjhandle handle = 0;
583 
584   GET_HANDLE();
585 
586   if (tjDestroy(handle) == -1) THROW_TJ();
587   (*env)->SetLongField(env, obj, _fid, 0);
588 
589 bailout:
590   return;
591 }
592 
593 /* TurboJPEG 1.2.x: TJDecompressor::init() */
Java_org_libjpegturbo_turbojpeg_TJDecompressor_init(JNIEnv * env,jobject obj)594 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_init
595   (JNIEnv *env, jobject obj)
596 {
597   jclass cls;
598   jfieldID fid;
599   tjhandle handle;
600 
601   if ((handle = tjInitDecompress()) == NULL)
602     THROW(tjGetErrorStr(), "org/libjpegturbo/turbojpeg/TJException");
603 
604   BAILIF0(cls = (*env)->GetObjectClass(env, obj));
605   BAILIF0(fid = (*env)->GetFieldID(env, cls, "handle", "J"));
606   (*env)->SetLongField(env, obj, fid, (size_t)handle);
607 
608 bailout:
609   return;
610 }
611 
612 /* TurboJPEG 1.2.x: TJDecompressor::getScalingFactors() */
Java_org_libjpegturbo_turbojpeg_TJ_getScalingFactors(JNIEnv * env,jclass cls)613 JNIEXPORT jobjectArray JNICALL Java_org_libjpegturbo_turbojpeg_TJ_getScalingFactors
614   (JNIEnv *env, jclass cls)
615 {
616   jclass sfcls = NULL;
617   jfieldID fid = 0;
618   tjscalingfactor *sf = NULL;
619   int n = 0, i;
620   jobject sfobj = NULL;
621   jobjectArray sfjava = NULL;
622 
623   if ((sf = tjGetScalingFactors(&n)) == NULL || n == 0)
624     THROW_ARG(tjGetErrorStr());
625 
626   BAILIF0(sfcls = (*env)->FindClass(env,
627     "org/libjpegturbo/turbojpeg/TJScalingFactor"));
628   BAILIF0(sfjava = (jobjectArray)(*env)->NewObjectArray(env, n, sfcls, 0));
629 
630   for (i = 0; i < n; i++) {
631     BAILIF0(sfobj = (*env)->AllocObject(env, sfcls));
632     BAILIF0(fid = (*env)->GetFieldID(env, sfcls, "num", "I"));
633     (*env)->SetIntField(env, sfobj, fid, sf[i].num);
634     BAILIF0(fid = (*env)->GetFieldID(env, sfcls, "denom", "I"));
635     (*env)->SetIntField(env, sfobj, fid, sf[i].denom);
636     (*env)->SetObjectArrayElement(env, sfjava, i, sfobj);
637   }
638 
639 bailout:
640   return sfjava;
641 }
642 
643 /* TurboJPEG 1.2.x: TJDecompressor::decompressHeader() */
Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompressHeader(JNIEnv * env,jobject obj,jbyteArray src,jint jpegSize)644 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompressHeader
645   (JNIEnv *env, jobject obj, jbyteArray src, jint jpegSize)
646 {
647   tjhandle handle = 0;
648   unsigned char *jpegBuf = NULL;
649   int width = 0, height = 0, jpegSubsamp = -1, jpegColorspace = -1;
650 
651   GET_HANDLE();
652 
653   if ((*env)->GetArrayLength(env, src) < jpegSize)
654     THROW_ARG("Source buffer is not large enough");
655 
656   BAILIF0(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, src, 0));
657 
658   if (tjDecompressHeader3(handle, jpegBuf, (unsigned long)jpegSize, &width,
659                           &height, &jpegSubsamp, &jpegColorspace) == -1) {
660     SAFE_RELEASE(src, jpegBuf);
661     THROW_TJ();
662   }
663 
664   SAFE_RELEASE(src, jpegBuf);
665 
666   BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "jpegSubsamp", "I"));
667   (*env)->SetIntField(env, obj, _fid, jpegSubsamp);
668   if ((_fid = (*env)->GetFieldID(env, _cls, "jpegColorspace", "I")) == 0)
669     (*env)->ExceptionClear(env);
670   else
671     (*env)->SetIntField(env, obj, _fid, jpegColorspace);
672   BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "jpegWidth", "I"));
673   (*env)->SetIntField(env, obj, _fid, width);
674   BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "jpegHeight", "I"));
675   (*env)->SetIntField(env, obj, _fid, height);
676 
677 bailout:
678   SAFE_RELEASE(src, jpegBuf);
679 }
680 
TJDecompressor_decompress(JNIEnv * env,jobject obj,jbyteArray src,jint jpegSize,jarray dst,jint dstElementSize,jint x,jint y,jint width,jint pitch,jint height,jint pf,jint flags)681 static void TJDecompressor_decompress
682   (JNIEnv *env, jobject obj, jbyteArray src, jint jpegSize, jarray dst,
683    jint dstElementSize, jint x, jint y, jint width, jint pitch, jint height,
684    jint pf, jint flags)
685 {
686   tjhandle handle = 0;
687   jsize arraySize = 0, actualPitch;
688   unsigned char *jpegBuf = NULL, *dstBuf = NULL;
689 
690   GET_HANDLE();
691 
692   if (pf < 0 || pf >= org_libjpegturbo_turbojpeg_TJ_NUMPF)
693     THROW_ARG("Invalid argument in decompress()");
694   if (org_libjpegturbo_turbojpeg_TJ_NUMPF != TJ_NUMPF)
695     THROW_ARG("Mismatch between Java and C API");
696 
697   if ((*env)->GetArrayLength(env, src) < jpegSize)
698     THROW_ARG("Source buffer is not large enough");
699   actualPitch = (pitch == 0) ? width * tjPixelSize[pf] : pitch;
700   arraySize = (y + height - 1) * actualPitch + (x + width) * tjPixelSize[pf];
701   if ((*env)->GetArrayLength(env, dst) * dstElementSize < arraySize)
702     THROW_ARG("Destination buffer is not large enough");
703 
704   BAILIF0(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, src, 0));
705   BAILIF0(dstBuf = (*env)->GetPrimitiveArrayCritical(env, dst, 0));
706 
707   if (tjDecompress2(handle, jpegBuf, (unsigned long)jpegSize,
708                     &dstBuf[y * actualPitch + x * tjPixelSize[pf]], width,
709                     pitch, height, pf, flags) == -1) {
710     SAFE_RELEASE(dst, dstBuf);
711     SAFE_RELEASE(src, jpegBuf);
712     THROW_TJ();
713   }
714 
715 bailout:
716   SAFE_RELEASE(dst, dstBuf);
717   SAFE_RELEASE(src, jpegBuf);
718 }
719 
720 /* TurboJPEG 1.3.x: TJDecompressor::decompress() byte destination */
Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress___3BI_3BIIIIIII(JNIEnv * env,jobject obj,jbyteArray src,jint jpegSize,jbyteArray dst,jint x,jint y,jint width,jint pitch,jint height,jint pf,jint flags)721 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress___3BI_3BIIIIIII
722   (JNIEnv *env, jobject obj, jbyteArray src, jint jpegSize, jbyteArray dst,
723    jint x, jint y, jint width, jint pitch, jint height, jint pf, jint flags)
724 {
725   TJDecompressor_decompress(env, obj, src, jpegSize, dst, 1, x, y, width,
726                             pitch, height, pf, flags);
727 }
728 
729 /* TurboJPEG 1.2.x: TJDecompressor::decompress() byte destination */
Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress___3BI_3BIIIII(JNIEnv * env,jobject obj,jbyteArray src,jint jpegSize,jbyteArray dst,jint width,jint pitch,jint height,jint pf,jint flags)730 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress___3BI_3BIIIII
731   (JNIEnv *env, jobject obj, jbyteArray src, jint jpegSize, jbyteArray dst,
732    jint width, jint pitch, jint height, jint pf, jint flags)
733 {
734   TJDecompressor_decompress(env, obj, src, jpegSize, dst, 1, 0, 0, width,
735                             pitch, height, pf, flags);
736 }
737 
738 /* TurboJPEG 1.3.x: TJDecompressor::decompress() int destination */
Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress___3BI_3IIIIIIII(JNIEnv * env,jobject obj,jbyteArray src,jint jpegSize,jintArray dst,jint x,jint y,jint width,jint stride,jint height,jint pf,jint flags)739 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress___3BI_3IIIIIIII
740   (JNIEnv *env, jobject obj, jbyteArray src, jint jpegSize, jintArray dst,
741    jint x, jint y, jint width, jint stride, jint height, jint pf, jint flags)
742 {
743   if (pf < 0 || pf >= org_libjpegturbo_turbojpeg_TJ_NUMPF)
744     THROW_ARG("Invalid argument in decompress()");
745   if (tjPixelSize[pf] != sizeof(jint))
746     THROW_ARG("Pixel format must be 32-bit when decompressing to an integer buffer.");
747 
748   TJDecompressor_decompress(env, obj, src, jpegSize, dst, sizeof(jint), x, y,
749                             width, stride * sizeof(jint), height, pf, flags);
750 
751 bailout:
752   return;
753 }
754 
755 /* TurboJPEG 1.2.x: TJDecompressor::decompress() int destination */
Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress___3BI_3IIIIII(JNIEnv * env,jobject obj,jbyteArray src,jint jpegSize,jintArray dst,jint width,jint stride,jint height,jint pf,jint flags)756 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompress___3BI_3IIIIII
757   (JNIEnv *env, jobject obj, jbyteArray src, jint jpegSize, jintArray dst,
758    jint width, jint stride, jint height, jint pf, jint flags)
759 {
760   if (pf < 0 || pf >= org_libjpegturbo_turbojpeg_TJ_NUMPF)
761     THROW_ARG("Invalid argument in decompress()");
762   if (tjPixelSize[pf] != sizeof(jint))
763     THROW_ARG("Pixel format must be 32-bit when decompressing to an integer buffer.");
764 
765   TJDecompressor_decompress(env, obj, src, jpegSize, dst, sizeof(jint), 0, 0,
766                             width, stride * sizeof(jint), height, pf, flags);
767 
768 bailout:
769   return;
770 }
771 
772 /* TurboJPEG 1.4.x: TJDecompressor::decompressToYUV() */
Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompressToYUV___3BI_3_3B_3II_3III(JNIEnv * env,jobject obj,jbyteArray src,jint jpegSize,jobjectArray dstobjs,jintArray jDstOffsets,jint desiredWidth,jintArray jDstStrides,jint desiredHeight,jint flags)773 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompressToYUV___3BI_3_3B_3II_3III
774   (JNIEnv *env, jobject obj, jbyteArray src, jint jpegSize,
775    jobjectArray dstobjs, jintArray jDstOffsets, jint desiredWidth,
776    jintArray jDstStrides, jint desiredHeight, jint flags)
777 {
778   tjhandle handle = 0;
779   unsigned char *jpegBuf = NULL;
780   jbyteArray jDstPlanes[3] = { NULL, NULL, NULL };
781   unsigned char *dstPlanesTmp[3] = { NULL, NULL, NULL };
782   unsigned char *dstPlanes[3] = { NULL, NULL, NULL };
783   int *dstOffsetsTmp = NULL, dstOffsets[3] = { 0, 0, 0 };
784   int *dstStridesTmp = NULL, dstStrides[3] = { 0, 0, 0 };
785   int jpegSubsamp = -1, jpegWidth = 0, jpegHeight = 0;
786   int nc = 0, i, width, height, scaledWidth, scaledHeight, nsf = 0;
787   tjscalingfactor *sf;
788 
789   GET_HANDLE();
790 
791   if ((*env)->GetArrayLength(env, src) < jpegSize)
792     THROW_ARG("Source buffer is not large enough");
793   BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "jpegSubsamp", "I"));
794   jpegSubsamp = (int)(*env)->GetIntField(env, obj, _fid);
795   BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "jpegWidth", "I"));
796   jpegWidth = (int)(*env)->GetIntField(env, obj, _fid);
797   BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "jpegHeight", "I"));
798   jpegHeight = (int)(*env)->GetIntField(env, obj, _fid);
799 
800   nc = (jpegSubsamp == org_libjpegturbo_turbojpeg_TJ_SAMP_GRAY ? 1 : 3);
801 
802   width = desiredWidth;
803   height = desiredHeight;
804   if (width == 0) width = jpegWidth;
805   if (height == 0) height = jpegHeight;
806   sf = tjGetScalingFactors(&nsf);
807   if (!sf || nsf < 1)
808     THROW_ARG(tjGetErrorStr());
809   for (i = 0; i < nsf; i++) {
810     scaledWidth = TJSCALED(jpegWidth, sf[i]);
811     scaledHeight = TJSCALED(jpegHeight, sf[i]);
812     if (scaledWidth <= width && scaledHeight <= height)
813       break;
814   }
815   if (i >= nsf)
816     THROW_ARG("Could not scale down to desired image dimensions");
817 
818   BAILIF0(dstOffsetsTmp =
819           (*env)->GetPrimitiveArrayCritical(env, jDstOffsets, 0));
820   for (i = 0; i < nc; i++) dstOffsets[i] = dstOffsetsTmp[i];
821   SAFE_RELEASE(jDstOffsets, dstOffsetsTmp);
822 
823   BAILIF0(dstStridesTmp =
824           (*env)->GetPrimitiveArrayCritical(env, jDstStrides, 0));
825   for (i = 0; i < nc; i++) dstStrides[i] = dstStridesTmp[i];
826   SAFE_RELEASE(jDstStrides, dstStridesTmp);
827 
828   for (i = 0; i < nc; i++) {
829     int planeSize = tjPlaneSizeYUV(i, scaledWidth, dstStrides[i], scaledHeight,
830                                    jpegSubsamp);
831     int pw = tjPlaneWidth(i, scaledWidth, jpegSubsamp);
832 
833     if (planeSize < 0 || pw < 0)
834       THROW_ARG(tjGetErrorStr());
835 
836     if (dstOffsets[i] < 0)
837       THROW_ARG("Invalid argument in decompressToYUV()");
838     if (dstStrides[i] < 0 && dstOffsets[i] - planeSize + pw < 0)
839       THROW_ARG("Negative plane stride would cause memory to be accessed below plane boundary");
840 
841     BAILIF0(jDstPlanes[i] = (*env)->GetObjectArrayElement(env, dstobjs, i));
842     if ((*env)->GetArrayLength(env, jDstPlanes[i]) <
843         dstOffsets[i] + planeSize)
844       THROW_ARG("Destination plane is not large enough");
845 
846     BAILIF0(dstPlanesTmp[i] =
847             (*env)->GetPrimitiveArrayCritical(env, jDstPlanes[i], 0));
848     dstPlanes[i] = &dstPlanesTmp[i][dstOffsets[i]];
849     SAFE_RELEASE(jDstPlanes[i], dstPlanesTmp[i]);
850   }
851   BAILIF0(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, src, 0));
852 
853   if (tjDecompressToYUVPlanes(handle, jpegBuf, (unsigned long)jpegSize,
854                               dstPlanes, desiredWidth, dstStrides,
855                               desiredHeight, flags) == -1) {
856     SAFE_RELEASE(src, jpegBuf);
857     THROW_TJ();
858   }
859 
860 bailout:
861   SAFE_RELEASE(src, jpegBuf);
862 }
863 
864 /* TurboJPEG 1.2.x: TJDecompressor::decompressToYUV() */
Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompressToYUV___3BI_3BI(JNIEnv * env,jobject obj,jbyteArray src,jint jpegSize,jbyteArray dst,jint flags)865 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decompressToYUV___3BI_3BI
866   (JNIEnv *env, jobject obj, jbyteArray src, jint jpegSize, jbyteArray dst,
867    jint flags)
868 {
869   tjhandle handle = 0;
870   unsigned char *jpegBuf = NULL, *dstBuf = NULL;
871   int jpegSubsamp = -1, jpegWidth = 0, jpegHeight = 0;
872 
873   GET_HANDLE();
874 
875   if ((*env)->GetArrayLength(env, src) < jpegSize)
876     THROW_ARG("Source buffer is not large enough");
877   BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "jpegSubsamp", "I"));
878   jpegSubsamp = (int)(*env)->GetIntField(env, obj, _fid);
879   BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "jpegWidth", "I"));
880   jpegWidth = (int)(*env)->GetIntField(env, obj, _fid);
881   BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "jpegHeight", "I"));
882   jpegHeight = (int)(*env)->GetIntField(env, obj, _fid);
883   if ((*env)->GetArrayLength(env, dst) <
884       (jsize)tjBufSizeYUV(jpegWidth, jpegHeight, jpegSubsamp))
885     THROW_ARG("Destination buffer is not large enough");
886 
887   BAILIF0(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, src, 0));
888   BAILIF0(dstBuf = (*env)->GetPrimitiveArrayCritical(env, dst, 0));
889 
890   if (tjDecompressToYUV(handle, jpegBuf, (unsigned long)jpegSize, dstBuf,
891                         flags) == -1) {
892     SAFE_RELEASE(dst, dstBuf);
893     SAFE_RELEASE(src, jpegBuf);
894     THROW_TJ();
895   }
896 
897 bailout:
898   SAFE_RELEASE(dst, dstBuf);
899   SAFE_RELEASE(src, jpegBuf);
900 }
901 
TJDecompressor_decodeYUV(JNIEnv * env,jobject obj,jobjectArray srcobjs,jintArray jSrcOffsets,jintArray jSrcStrides,jint subsamp,jarray dst,jint dstElementSize,jint x,jint y,jint width,jint pitch,jint height,jint pf,jint flags)902 static void TJDecompressor_decodeYUV
903   (JNIEnv *env, jobject obj, jobjectArray srcobjs, jintArray jSrcOffsets,
904    jintArray jSrcStrides, jint subsamp, jarray dst, jint dstElementSize,
905    jint x, jint y, jint width, jint pitch, jint height, jint pf, jint flags)
906 {
907   tjhandle handle = 0;
908   jsize arraySize = 0, actualPitch;
909   jbyteArray jSrcPlanes[3] = { NULL, NULL, NULL };
910   const unsigned char *srcPlanesTmp[3] = { NULL, NULL, NULL };
911   const unsigned char *srcPlanes[3] = { NULL, NULL, NULL };
912   int *srcOffsetsTmp = NULL, srcOffsets[3] = { 0, 0, 0 };
913   int *srcStridesTmp = NULL, srcStrides[3] = { 0, 0, 0 };
914   unsigned char *dstBuf = NULL;
915   int nc = (subsamp == org_libjpegturbo_turbojpeg_TJ_SAMP_GRAY ? 1 : 3), i;
916 
917   GET_HANDLE();
918 
919   if (pf < 0 || pf >= org_libjpegturbo_turbojpeg_TJ_NUMPF || subsamp < 0 ||
920       subsamp >= org_libjpegturbo_turbojpeg_TJ_NUMSAMP)
921     THROW_ARG("Invalid argument in decodeYUV()");
922   if (org_libjpegturbo_turbojpeg_TJ_NUMPF != TJ_NUMPF ||
923       org_libjpegturbo_turbojpeg_TJ_NUMSAMP != TJ_NUMSAMP)
924     THROW_ARG("Mismatch between Java and C API");
925 
926   if ((*env)->GetArrayLength(env, srcobjs) < nc)
927     THROW_ARG("Planes array is too small for the subsampling type");
928   if ((*env)->GetArrayLength(env, jSrcOffsets) < nc)
929     THROW_ARG("Offsets array is too small for the subsampling type");
930   if ((*env)->GetArrayLength(env, jSrcStrides) < nc)
931     THROW_ARG("Strides array is too small for the subsampling type");
932 
933   actualPitch = (pitch == 0) ? width * tjPixelSize[pf] : pitch;
934   arraySize = (y + height - 1) * actualPitch + (x + width) * tjPixelSize[pf];
935   if ((*env)->GetArrayLength(env, dst) * dstElementSize < arraySize)
936     THROW_ARG("Destination buffer is not large enough");
937 
938   BAILIF0(srcOffsetsTmp =
939           (*env)->GetPrimitiveArrayCritical(env, jSrcOffsets, 0));
940   for (i = 0; i < nc; i++) srcOffsets[i] = srcOffsetsTmp[i];
941   SAFE_RELEASE(jSrcOffsets, srcOffsetsTmp);
942 
943   BAILIF0(srcStridesTmp =
944           (*env)->GetPrimitiveArrayCritical(env, jSrcStrides, 0));
945   for (i = 0; i < nc; i++) srcStrides[i] = srcStridesTmp[i];
946   SAFE_RELEASE(jSrcStrides, srcStridesTmp);
947 
948   for (i = 0; i < nc; i++) {
949     int planeSize = tjPlaneSizeYUV(i, width, srcStrides[i], height, subsamp);
950     int pw = tjPlaneWidth(i, width, subsamp);
951 
952     if (planeSize < 0 || pw < 0)
953       THROW_ARG(tjGetErrorStr());
954 
955     if (srcOffsets[i] < 0)
956       THROW_ARG("Invalid argument in decodeYUV()");
957     if (srcStrides[i] < 0 && srcOffsets[i] - planeSize + pw < 0)
958       THROW_ARG("Negative plane stride would cause memory to be accessed below plane boundary");
959 
960     BAILIF0(jSrcPlanes[i] = (*env)->GetObjectArrayElement(env, srcobjs, i));
961     if ((*env)->GetArrayLength(env, jSrcPlanes[i]) <
962         srcOffsets[i] + planeSize)
963       THROW_ARG("Source plane is not large enough");
964 
965     BAILIF0(srcPlanesTmp[i] =
966             (*env)->GetPrimitiveArrayCritical(env, jSrcPlanes[i], 0));
967     srcPlanes[i] = &srcPlanesTmp[i][srcOffsets[i]];
968     SAFE_RELEASE(jSrcPlanes[i], srcPlanesTmp[i]);
969   }
970   BAILIF0(dstBuf = (*env)->GetPrimitiveArrayCritical(env, dst, 0));
971 
972   if (tjDecodeYUVPlanes(handle, srcPlanes, srcStrides, subsamp,
973                         &dstBuf[y * actualPitch + x * tjPixelSize[pf]], width,
974                         pitch, height, pf, flags) == -1) {
975     SAFE_RELEASE(dst, dstBuf);
976     THROW_TJ();
977   }
978 
979 bailout:
980   SAFE_RELEASE(dst, dstBuf);
981 }
982 
983 /* TurboJPEG 1.4.x: TJDecompressor::decodeYUV() byte destination */
Java_org_libjpegturbo_turbojpeg_TJDecompressor_decodeYUV___3_3B_3I_3II_3BIIIIIII(JNIEnv * env,jobject obj,jobjectArray srcobjs,jintArray jSrcOffsets,jintArray jSrcStrides,jint subsamp,jbyteArray dst,jint x,jint y,jint width,jint pitch,jint height,jint pf,jint flags)984 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decodeYUV___3_3B_3I_3II_3BIIIIIII
985   (JNIEnv *env, jobject obj, jobjectArray srcobjs, jintArray jSrcOffsets,
986    jintArray jSrcStrides, jint subsamp, jbyteArray dst, jint x, jint y,
987    jint width, jint pitch, jint height, jint pf, jint flags)
988 {
989   TJDecompressor_decodeYUV(env, obj, srcobjs, jSrcOffsets, jSrcStrides,
990                            subsamp, dst, 1, x, y, width, pitch, height, pf,
991                            flags);
992 }
993 
994 /* TurboJPEG 1.4.x: TJDecompressor::decodeYUV() int destination */
Java_org_libjpegturbo_turbojpeg_TJDecompressor_decodeYUV___3_3B_3I_3II_3IIIIIIII(JNIEnv * env,jobject obj,jobjectArray srcobjs,jintArray jSrcOffsets,jintArray jSrcStrides,jint subsamp,jintArray dst,jint x,jint y,jint width,jint stride,jint height,jint pf,jint flags)995 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_decodeYUV___3_3B_3I_3II_3IIIIIIII
996   (JNIEnv *env, jobject obj, jobjectArray srcobjs, jintArray jSrcOffsets,
997    jintArray jSrcStrides, jint subsamp, jintArray dst, jint x, jint y,
998    jint width, jint stride, jint height, jint pf, jint flags)
999 {
1000   if (pf < 0 || pf >= org_libjpegturbo_turbojpeg_TJ_NUMPF)
1001     THROW_ARG("Invalid argument in decodeYUV()");
1002   if (tjPixelSize[pf] != sizeof(jint))
1003     THROW_ARG("Pixel format must be 32-bit when decoding to an integer buffer.");
1004 
1005   TJDecompressor_decodeYUV(env, obj, srcobjs, jSrcOffsets, jSrcStrides,
1006                            subsamp, dst, sizeof(jint), x, y, width,
1007                            stride * sizeof(jint), height, pf, flags);
1008 
1009 bailout:
1010   return;
1011 }
1012 
1013 /* TurboJPEG 1.2.x: TJTransformer::init() */
Java_org_libjpegturbo_turbojpeg_TJTransformer_init(JNIEnv * env,jobject obj)1014 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJTransformer_init
1015   (JNIEnv *env, jobject obj)
1016 {
1017   jclass cls;
1018   jfieldID fid;
1019   tjhandle handle;
1020 
1021   if ((handle = tjInitTransform()) == NULL)
1022     THROW(tjGetErrorStr(), "org/libjpegturbo/turbojpeg/TJException");
1023 
1024   BAILIF0(cls = (*env)->GetObjectClass(env, obj));
1025   BAILIF0(fid = (*env)->GetFieldID(env, cls, "handle", "J"));
1026   (*env)->SetLongField(env, obj, fid, (size_t)handle);
1027 
1028 bailout:
1029   return;
1030 }
1031 
1032 typedef struct _JNICustomFilterParams {
1033   JNIEnv *env;
1034   jobject tobj;
1035   jobject cfobj;
1036 } JNICustomFilterParams;
1037 
JNICustomFilter(short * coeffs,tjregion arrayRegion,tjregion planeRegion,int componentIndex,int transformIndex,tjtransform * transform)1038 static int JNICustomFilter(short *coeffs, tjregion arrayRegion,
1039                            tjregion planeRegion, int componentIndex,
1040                            int transformIndex, tjtransform *transform)
1041 {
1042   JNICustomFilterParams *params = (JNICustomFilterParams *)transform->data;
1043   JNIEnv *env = params->env;
1044   jobject tobj = params->tobj, cfobj = params->cfobj;
1045   jobject arrayRegionObj, planeRegionObj, bufobj, borobj;
1046   jclass cls;
1047   jmethodID mid;
1048   jfieldID fid;
1049 
1050   BAILIF0(bufobj = (*env)->NewDirectByteBuffer(env, coeffs,
1051     sizeof(short) * arrayRegion.w * arrayRegion.h));
1052   BAILIF0(cls = (*env)->FindClass(env, "java/nio/ByteOrder"));
1053   BAILIF0(mid = (*env)->GetStaticMethodID(env, cls, "nativeOrder",
1054                                           "()Ljava/nio/ByteOrder;"));
1055   BAILIF0(borobj = (*env)->CallStaticObjectMethod(env, cls, mid));
1056   BAILIF0(cls = (*env)->GetObjectClass(env, bufobj));
1057   BAILIF0(mid = (*env)->GetMethodID(env, cls, "order",
1058     "(Ljava/nio/ByteOrder;)Ljava/nio/ByteBuffer;"));
1059   (*env)->CallObjectMethod(env, bufobj, mid, borobj);
1060   BAILIF0(mid = (*env)->GetMethodID(env, cls, "asShortBuffer",
1061                                     "()Ljava/nio/ShortBuffer;"));
1062   BAILIF0(bufobj = (*env)->CallObjectMethod(env, bufobj, mid));
1063 
1064   BAILIF0(cls = (*env)->FindClass(env, "java/awt/Rectangle"));
1065   BAILIF0(arrayRegionObj = (*env)->AllocObject(env, cls));
1066   BAILIF0(fid = (*env)->GetFieldID(env, cls, "x", "I"));
1067   (*env)->SetIntField(env, arrayRegionObj, fid, arrayRegion.x);
1068   BAILIF0(fid = (*env)->GetFieldID(env, cls, "y", "I"));
1069   (*env)->SetIntField(env, arrayRegionObj, fid, arrayRegion.y);
1070   BAILIF0(fid = (*env)->GetFieldID(env, cls, "width", "I"));
1071   (*env)->SetIntField(env, arrayRegionObj, fid, arrayRegion.w);
1072   BAILIF0(fid = (*env)->GetFieldID(env, cls, "height", "I"));
1073   (*env)->SetIntField(env, arrayRegionObj, fid, arrayRegion.h);
1074 
1075   BAILIF0(planeRegionObj = (*env)->AllocObject(env, cls));
1076   BAILIF0(fid = (*env)->GetFieldID(env, cls, "x", "I"));
1077   (*env)->SetIntField(env, planeRegionObj, fid, planeRegion.x);
1078   BAILIF0(fid = (*env)->GetFieldID(env, cls, "y", "I"));
1079   (*env)->SetIntField(env, planeRegionObj, fid, planeRegion.y);
1080   BAILIF0(fid = (*env)->GetFieldID(env, cls, "width", "I"));
1081   (*env)->SetIntField(env, planeRegionObj, fid, planeRegion.w);
1082   BAILIF0(fid = (*env)->GetFieldID(env, cls, "height", "I"));
1083   (*env)->SetIntField(env, planeRegionObj, fid, planeRegion.h);
1084 
1085   BAILIF0(cls = (*env)->GetObjectClass(env, cfobj));
1086   BAILIF0(mid = (*env)->GetMethodID(env, cls, "customFilter",
1087     "(Ljava/nio/ShortBuffer;Ljava/awt/Rectangle;Ljava/awt/Rectangle;IILorg/libjpegturbo/turbojpeg/TJTransform;)V"));
1088   (*env)->CallVoidMethod(env, cfobj, mid, bufobj, arrayRegionObj,
1089                          planeRegionObj, componentIndex, transformIndex, tobj);
1090 
1091   return 0;
1092 
1093 bailout:
1094   return -1;
1095 }
1096 
1097 /* TurboJPEG 1.2.x: TJTransformer::transform() */
Java_org_libjpegturbo_turbojpeg_TJTransformer_transform(JNIEnv * env,jobject obj,jbyteArray jsrcBuf,jint jpegSize,jobjectArray dstobjs,jobjectArray tobjs,jint flags)1098 JNIEXPORT jintArray JNICALL Java_org_libjpegturbo_turbojpeg_TJTransformer_transform
1099   (JNIEnv *env, jobject obj, jbyteArray jsrcBuf, jint jpegSize,
1100    jobjectArray dstobjs, jobjectArray tobjs, jint flags)
1101 {
1102   tjhandle handle = 0;
1103   unsigned char *jpegBuf = NULL, **dstBufs = NULL;
1104   jsize n = 0;
1105   unsigned long *dstSizes = NULL;
1106   tjtransform *t = NULL;
1107   jbyteArray *jdstBufs = NULL;
1108   int i, jpegWidth = 0, jpegHeight = 0, jpegSubsamp;
1109   jintArray jdstSizes = 0;
1110   jint *dstSizesi = NULL;
1111   JNICustomFilterParams *params = NULL;
1112 
1113   GET_HANDLE();
1114 
1115   if ((*env)->GetArrayLength(env, jsrcBuf) < jpegSize)
1116     THROW_ARG("Source buffer is not large enough");
1117   BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "jpegWidth", "I"));
1118   jpegWidth = (int)(*env)->GetIntField(env, obj, _fid);
1119   BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "jpegHeight", "I"));
1120   jpegHeight = (int)(*env)->GetIntField(env, obj, _fid);
1121   BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "jpegSubsamp", "I"));
1122   jpegSubsamp = (int)(*env)->GetIntField(env, obj, _fid);
1123 
1124   n = (*env)->GetArrayLength(env, dstobjs);
1125   if (n != (*env)->GetArrayLength(env, tobjs))
1126     THROW_ARG("Mismatch between size of transforms array and destination buffers array");
1127 
1128   if ((dstBufs =
1129        (unsigned char **)malloc(sizeof(unsigned char *) * n)) == NULL)
1130     THROW_MEM();
1131   if ((jdstBufs = (jbyteArray *)malloc(sizeof(jbyteArray) * n)) == NULL)
1132     THROW_MEM();
1133   if ((dstSizes = (unsigned long *)malloc(sizeof(unsigned long) * n)) == NULL)
1134     THROW_MEM();
1135   if ((t = (tjtransform *)malloc(sizeof(tjtransform) * n)) == NULL)
1136     THROW_MEM();
1137   if ((params = (JNICustomFilterParams *)malloc(sizeof(JNICustomFilterParams) *
1138                                                 n)) == NULL)
1139     THROW_MEM();
1140   for (i = 0; i < n; i++) {
1141     dstBufs[i] = NULL;  jdstBufs[i] = NULL;  dstSizes[i] = 0;
1142     memset(&t[i], 0, sizeof(tjtransform));
1143     memset(&params[i], 0, sizeof(JNICustomFilterParams));
1144   }
1145 
1146   for (i = 0; i < n; i++) {
1147     jobject tobj, cfobj;
1148 
1149     BAILIF0(tobj = (*env)->GetObjectArrayElement(env, tobjs, i));
1150     BAILIF0(_cls = (*env)->GetObjectClass(env, tobj));
1151     BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "op", "I"));
1152     t[i].op = (*env)->GetIntField(env, tobj, _fid);
1153     BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "options", "I"));
1154     t[i].options = (*env)->GetIntField(env, tobj, _fid);
1155     BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "x", "I"));
1156     t[i].r.x = (*env)->GetIntField(env, tobj, _fid);
1157     BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "y", "I"));
1158     t[i].r.y = (*env)->GetIntField(env, tobj, _fid);
1159     BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "width", "I"));
1160     t[i].r.w = (*env)->GetIntField(env, tobj, _fid);
1161     BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "height", "I"));
1162     t[i].r.h = (*env)->GetIntField(env, tobj, _fid);
1163 
1164     BAILIF0(_fid = (*env)->GetFieldID(env, _cls, "cf",
1165       "Lorg/libjpegturbo/turbojpeg/TJCustomFilter;"));
1166     cfobj = (*env)->GetObjectField(env, tobj, _fid);
1167     if (cfobj) {
1168       params[i].env = env;
1169       params[i].tobj = tobj;
1170       params[i].cfobj = cfobj;
1171       t[i].customFilter = JNICustomFilter;
1172       t[i].data = (void *)&params[i];
1173     }
1174   }
1175 
1176   for (i = 0; i < n; i++) {
1177     int w = jpegWidth, h = jpegHeight;
1178 
1179     if (t[i].r.w != 0) w = t[i].r.w;
1180     if (t[i].r.h != 0) h = t[i].r.h;
1181     BAILIF0(jdstBufs[i] = (*env)->GetObjectArrayElement(env, dstobjs, i));
1182     if ((unsigned long)(*env)->GetArrayLength(env, jdstBufs[i]) <
1183         tjBufSize(w, h, jpegSubsamp))
1184       THROW_ARG("Destination buffer is not large enough");
1185   }
1186   BAILIF0(jpegBuf = (*env)->GetPrimitiveArrayCritical(env, jsrcBuf, 0));
1187   for (i = 0; i < n; i++)
1188     BAILIF0(dstBufs[i] =
1189             (*env)->GetPrimitiveArrayCritical(env, jdstBufs[i], 0));
1190 
1191   if (tjTransform(handle, jpegBuf, jpegSize, n, dstBufs, dstSizes, t,
1192                   flags | TJFLAG_NOREALLOC) == -1) {
1193     for (i = 0; i < n; i++)
1194       SAFE_RELEASE(jdstBufs[i], dstBufs[i]);
1195     SAFE_RELEASE(jsrcBuf, jpegBuf);
1196     THROW_TJ();
1197   }
1198 
1199   for (i = 0; i < n; i++)
1200     SAFE_RELEASE(jdstBufs[i], dstBufs[i]);
1201   SAFE_RELEASE(jsrcBuf, jpegBuf);
1202 
1203   jdstSizes = (*env)->NewIntArray(env, n);
1204   BAILIF0(dstSizesi = (*env)->GetIntArrayElements(env, jdstSizes, 0));
1205   for (i = 0; i < n; i++) dstSizesi[i] = (int)dstSizes[i];
1206 
1207 bailout:
1208   if (dstSizesi) (*env)->ReleaseIntArrayElements(env, jdstSizes, dstSizesi, 0);
1209   if (dstBufs) {
1210     for (i = 0; i < n; i++) {
1211       if (dstBufs[i] && jdstBufs && jdstBufs[i])
1212         (*env)->ReleasePrimitiveArrayCritical(env, jdstBufs[i], dstBufs[i], 0);
1213     }
1214     free(dstBufs);
1215   }
1216   SAFE_RELEASE(jsrcBuf, jpegBuf);
1217   free(jdstBufs);
1218   free(dstSizes);
1219   free(t);
1220   return jdstSizes;
1221 }
1222 
1223 /* TurboJPEG 1.2.x: TJDecompressor::destroy() */
Java_org_libjpegturbo_turbojpeg_TJDecompressor_destroy(JNIEnv * env,jobject obj)1224 JNIEXPORT void JNICALL Java_org_libjpegturbo_turbojpeg_TJDecompressor_destroy
1225   (JNIEnv *env, jobject obj)
1226 {
1227   Java_org_libjpegturbo_turbojpeg_TJCompressor_destroy(env, obj);
1228 }
1229