1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  * Copyright (C) 2014-2016 Mopria Alliance, Inc.
4  * Copyright (C) 2013 Hewlett-Packard Development Company, L.P.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 
19 #include <jni.h>
20 #include "lib_wprint.h"
21 #include "wprint_debug.h"
22 #include <errno.h>
23 #include "../plugins/wprint_mupdf.h"
24 
25 #define TAG "wprintJNI"
26 
27 #define MAX_NUM_PAGES 2000
28 
29 static jclass _LocalJobParamsClass;
30 static jfieldID _LocalJobParamsField__borderless;
31 static jfieldID _LocalJobParamsField__duplex;
32 static jfieldID _LocalJobParamsField__media_size;
33 static jfieldID _LocalJobParamsField__media_type;
34 static jfieldID _LocalJobParamsField__media_tray;
35 static jfieldID _LocalJobParamsField__color_space;
36 static jfieldID _LocalJobParamsField__render_flags;
37 static jfieldID _LocalJobParamsField__num_copies;
38 static jfieldID _LocalJobParamsField__page_range;
39 static jfieldID _LocalJobParamsField__print_resolution;
40 static jfieldID _LocalJobParamsField__printable_width;
41 static jfieldID _LocalJobParamsField__printable_height;
42 static jfieldID _LocalJobParamsField__page_width;
43 static jfieldID _LocalJobParamsField__page_height;
44 static jfieldID _LocalJobParamsField__page_margin_top;
45 static jfieldID _LocalJobParamsField__page_margin_left;
46 static jfieldID _LocalJobParamsField__page_margin_right;
47 static jfieldID _LocalJobParamsField__page_margin_bottom;
48 static jfieldID _LocalJobParamsField__job_margin_top;
49 static jfieldID _LocalJobParamsField__job_margin_left;
50 static jfieldID _LocalJobParamsField__job_margin_right;
51 static jfieldID _LocalJobParamsField__job_margin_bottom;
52 static jfieldID _LocalJobParamsField__fit_to_page;
53 static jfieldID _LocalJobParamsField__fill_page;
54 static jfieldID _LocalJobParamsField__auto_rotate;
55 static jfieldID _LocalJobParamsField__portrait_mode;
56 static jfieldID _LocalJobParamsField__landscape_mode;
57 static jfieldID _LocalJobParamsField__nativeData;
58 static jfieldID _LocalJobParamsField__document_category;
59 static jfieldID _LocalJobParamsField__alignment;
60 static jfieldID _LocalJobParamsField__document_scaling;
61 static jfieldID _LocalJobParamsField__job_name;
62 static jfieldID _LocalJobParamsField__job_originating_user_name;
63 static jfieldID _LocalJobParamsField__pdf_render_resolution;
64 
65 static jclass _LocalPrinterCapabilitiesClass;
66 static jfieldID _LocalPrinterCapabilitiesField__name;
67 static jfieldID _LocalPrinterCapabilitiesField__path;
68 static jfieldID _LocalPrinterCapabilitiesField__uuid;
69 static jfieldID _LocalPrinterCapabilitiesField__location;
70 static jfieldID _LocalPrinterCapabilitiesField__duplex;
71 static jfieldID _LocalPrinterCapabilitiesField__borderless;
72 static jfieldID _LocalPrinterCapabilitiesField__color;
73 static jfieldID _LocalPrinterCapabilitiesField__isSupported;
74 static jfieldID _LocalPrinterCapabilitiesField__mediaDefault;
75 static jfieldID _LocalPrinterCapabilitiesField__supportedMediaTypes;
76 static jfieldID _LocalPrinterCapabilitiesField__supportedMediaSizes;
77 static jfieldID _LocalPrinterCapabilitiesField__nativeData;
78 static jfieldID _LocalPrinterCapabilitiesField__certificate;
79 
80 static jclass _JobCallbackClass;
81 static jobject _callbackReceiver;
82 static jmethodID _JobCallbackMethod__jobCallback;
83 
84 static jclass _JobCallbackParamsClass;
85 static jmethodID _JobCallbackParamsMethod__init;
86 static jfieldID _JobCallbackParamsField__jobId;
87 static jfieldID _JobCallbackParamsField__jobState;
88 static jfieldID _JobCallbackParamsField__jobDoneResult;
89 static jfieldID _JobCallbackParamsField__blockedReasons;
90 static jfieldID _JobCallbackParamsField__certificate;
91 
92 static jclass _PrintServiceStringsClass;
93 static jfieldID _PrintServiceStringsField__JOB_STATE_QUEUED;
94 static jfieldID _PrintServiceStringsField__JOB_STATE_RUNNING;
95 static jfieldID _PrintServiceStringsField__JOB_STATE_BLOCKED;
96 static jfieldID _PrintServiceStringsField__JOB_STATE_DONE;
97 static jfieldID _PrintServiceStringsField__JOB_STATE_OTHER;
98 static jfieldID _PrintServiceStringsField__JOB_DONE_OK;
99 static jfieldID _PrintServiceStringsField__JOB_DONE_ERROR;
100 static jfieldID _PrintServiceStringsField__JOB_DONE_CANCELLED;
101 static jfieldID _PrintServiceStringsField__JOB_DONE_CORRUPT;
102 static jfieldID _PrintServiceStringsField__JOB_DONE_OTHER;
103 static jfieldID _PrintServiceStringsField__BLOCKED_REASON__OFFLINE;
104 static jfieldID _PrintServiceStringsField__BLOCKED_REASON__BUSY;
105 static jfieldID _PrintServiceStringsField__BLOCKED_REASON__CANCELLED;
106 static jfieldID _PrintServiceStringsField__BLOCKED_REASON__OUT_OF_PAPER;
107 static jfieldID _PrintServiceStringsField__BLOCKED_REASON__OUT_OF_INK;
108 static jfieldID _PrintServiceStringsField__BLOCKED_REASON__OUT_OF_TONER;
109 static jfieldID _PrintServiceStringsField__BLOCKED_REASON__JAMMED;
110 static jfieldID _PrintServiceStringsField__BLOCKED_REASON__DOOR_OPEN;
111 static jfieldID _PrintServiceStringsField__BLOCKED_REASON__SERVICE_REQUEST;
112 static jfieldID _PrintServiceStringsField__BLOCKED_REASON__LOW_ON_INK;
113 static jfieldID _PrintServiceStringsField__BLOCKED_REASON__LOW_ON_TONER;
114 static jfieldID _PrintServiceStringsField__BLOCKED_REASON__REALLY_LOW_ON_INK;
115 static jfieldID _PrintServiceStringsField__BLOCKED_REASON__BAD_CERTIFICATE;
116 static jfieldID _PrintServiceStringsField__BLOCKED_REASON__UNKNOWN;
117 static jfieldID _PrintServiceStringsField__ALIGNMENT__CENTER;
118 static jfieldID _PrintServiceStringsField__ALIGNMENT__CENTER_HORIZONTAL;
119 static jfieldID _PrintServiceStringsField__ALIGNMENT__CENTER_VERTICAL;
120 static jfieldID _PrintServiceStringsField__ALIGNMENT__CENTER_HORIZONTAL_ON_ORIENTATION;
121 
122 // Global so it can be used in PDF render code
123 JavaVM *_JVM = NULL;
124 
125 static jstring _fakeDir;
126 
127 int g_API_version = 0;
128 
129 /*
130  * Convert char * to a java object
131  */
132 static void stringToJava(JNIEnv *env, jobject obj, jfieldID id, const char *str);
133 
134 /*
135  * Retuns if the mime type is MIME_TYPE_PDF
136  */
_is_pdf_doc(const char * mime_type,const char * pathname)137 static bool _is_pdf_doc(const char *mime_type, const char *pathname) {
138     if (mime_type == NULL || pathname == NULL) {
139         return false;
140     }
141 
142     if (strcmp(mime_type, MIME_TYPE_PDF) == 0) {
143         return true;
144     }
145 
146     return false;
147 }
148 
149 /*
150  * Returns if the string is numeric
151  */
_isNumeric(const char * s)152 static int _isNumeric(const char *s) {
153     if (s == NULL || *s == '\0' || isspace(*s)) {
154         return 0;
155     }
156     char *p;
157     strtod(s, &p);
158     return *p == '\0';
159 }
160 
161 /*
162  * Outputs the number of pages in a pdf to page_count. Returns False if an error ocurred
163  */
_get_pdf_page_count(const char * mime_type,int * page_count,const char * pathname)164 static bool _get_pdf_page_count(const char *mime_type, int *page_count, const char *pathname) {
165     *page_count = 0;
166 
167     if (!_is_pdf_doc(mime_type, pathname)) {
168         return false;
169     }
170 
171     pdf_render_ifc_t *pdf_render_ifc = create_pdf_render_ifc();
172     *page_count = pdf_render_ifc->openDocument(pdf_render_ifc, pathname);
173     pdf_render_ifc->destroy(pdf_render_ifc);
174 
175     LOGI("pdf page count for %s: %d", pathname, *page_count);
176     if (*page_count < 0) {
177         LOGE("page count error");
178         *page_count = 0;
179     }
180     return true;
181 }
182 
183 /*
184  * Reorders pdf pages before sending to the printer. In general the last page is printed first.
185  * Removes pages from pages_ary if they are not in the specified range.
186  */
_order_pdf_pages(int num_pages,int * pages_ary,int * num_index,char * page_range_split)187 static bool _order_pdf_pages(int num_pages, int *pages_ary, int *num_index,
188         char *page_range_split) {
189     bool succeeded = false;
190     char num_begin_ary[5] = "";
191     char num_end_ary[5] = "";
192     int num_counter = 0;
193     bool dash_encountered = false;
194     int range_count = 0;
195 
196     // initialize to 0
197     memset(num_begin_ary, 0, 5);
198     memset(num_end_ary, 0, 5);
199 
200     for (range_count = 0; range_count < (int) strlen(page_range_split); range_count++) {
201         // skip spaces
202         if (!isspace(page_range_split[range_count])) {
203             // store first number found in range in num_begin_ary
204             // and second number (after the dash '-') in num_end_ary
205             // skip the dash ('-') character
206             if (page_range_split[range_count] == '-') {
207                 dash_encountered = true;
208                 num_counter = 0;
209                 continue;
210             }
211 
212             if (!dash_encountered) {
213                 num_begin_ary[num_counter++] = page_range_split[range_count];
214             } else {
215                 num_end_ary[num_counter++] = page_range_split[range_count];
216             }
217         }
218     }
219 
220     // fill in first cell of end num with 0 so array has a valid number
221     if (!dash_encountered) {
222         num_end_ary[0] = '0';
223     }
224 
225     // make sure numeric values are stored in num_begin_ary and num_end_ary
226     if (_isNumeric(num_begin_ary) && _isNumeric(num_end_ary)) {
227         // convert to integers
228         int num_begin = atoi(num_begin_ary);
229         int num_end = atoi(num_end_ary);
230 
231         // if ending number was 0, there was no range, only a single page number
232         // so, set it to the value of the beginning number
233         if (num_end == 0) {
234             num_end = num_begin;
235         }
236 
237         // make sure beginning and ending numbers are at least 1
238         if (num_begin > 0 && num_end > 0) {
239             // make sure the beginning and ending numbers are not greater than the page count
240             if (num_begin <= num_pages && num_end <= num_pages) {
241                 if (num_end >= num_begin) {
242                     // make sure the upper bound does not exceed the number of pages
243                     if (num_end > num_pages) {
244                         num_end = num_pages;
245                     }
246                     // store range in pages_ary in ascending order
247                     int count = 0;
248                     for (count = *num_index; count <= (*num_index + num_end - num_begin); count++) {
249                         *(pages_ary + count) = num_begin++;
250                         *num_index += 1;
251                     }
252                 } else {
253                     // reverse order
254                     // make sure the upper bound does not exceed the number of pages
255                     if (num_begin > num_pages) {
256                         num_begin = num_pages;
257                     }
258                     // store range in pages_ary in descending order
259                     int count = 0;
260                     for (count = *num_index; count <= *num_index + num_begin - num_end; count++) {
261                         *(pages_ary + count) = num_begin--;
262                         *num_index += 1;
263                     }
264                 }
265                 succeeded = true;
266             } else {
267                 LOGE("_order_pdf_pages(), ERROR: first and/or last numbers are not greater than "
268                         "%d: first num=%d, second num=%d", num_pages, num_begin, num_end);
269             }
270         } else {
271             LOGE("_order_pdf_pages(), ERROR: first and/or last numbers are not greater than 0: "
272                     "first num=%d, second num=%d", num_begin, num_end);
273         }
274     } else {
275         LOGE("_order_pdf_pages(), ERROR: first and/or last numbers are not numeric: first num=%s, "
276                 "second num=%s", num_begin_ary, num_end_ary);
277     }
278     return succeeded;
279 }
280 
281 /*
282  * Outputs page range of a pdf to page_range_str
283  */
_get_pdf_page_range(JNIEnv * env,jobject javaJobParams,int * pages_ary,int num_pages,int * num_index,char * page_range_str)284 static void _get_pdf_page_range(JNIEnv *env, jobject javaJobParams, int *pages_ary, int num_pages,
285         int *num_index, char *page_range_str) {
286     char *page_range = NULL;
287     jstring pageRangeObject = (jstring) (*env)->GetObjectField(env, javaJobParams,
288             _LocalJobParamsField__page_range);
289     if (pageRangeObject) {
290         int page_range_size = (*env)->GetStringLength(env, pageRangeObject);
291         const jbyte *pageRange = (jbyte *) (*env)->GetStringUTFChars(env, pageRangeObject, 0);
292         if (strcmp((char *) pageRange, "") != 0) {
293             page_range = (char *) malloc(page_range_size + 1);
294             memset(page_range, 0, page_range_size + 1);
295             strncpy(page_range, (char *) pageRange, page_range_size);
296 
297             // no empty strings
298             if (strcmp(page_range, "") == 0) {
299                 free(page_range);
300                 page_range = NULL;
301             }
302 
303             (*env)->ReleaseStringUTFChars(env, pageRangeObject, (const char *) pageRange);
304             LOGD("_get_pdf_page_range(), page_range from JNI environment=%s", page_range);
305         }
306     }
307 
308     if (!page_range) {
309         page_range = (char *) malloc(MAX_NUM_PAGES + 1);
310         memset(page_range, 0, MAX_NUM_PAGES + 1);
311 
312         snprintf(page_range_str, MAX_NUM_PAGES, "1-%d", num_pages);
313         snprintf(page_range, MAX_NUM_PAGES, "1-%d", num_pages);
314     } else {
315         strncpy(page_range_str, page_range, MAX_NUM_PAGES);
316     }
317 
318     LOGD("_get_pdf_page_range(), range: %s, pages in document: %d", page_range_str, num_pages);
319 
320     // get the first token in page_range_str
321     memset(pages_ary, 0, MAX_NUM_PAGES);
322     char *page_range_split = strtok(page_range, ",");
323     while (page_range_split != NULL) {
324         if (!_order_pdf_pages(num_pages, pages_ary, num_index, page_range_split)) {
325             snprintf(page_range_str, MAX_NUM_PAGES, "1-%d", num_pages);
326             LOGD("_get_pdf_page_range(), setting page_range to: %s", page_range_str);
327             _order_pdf_pages(num_pages, pages_ary, num_index, page_range_str);
328             break;
329         }
330 
331         // get next range token
332         page_range_split = strtok(NULL, ",");
333     }
334 
335     if (page_range) {
336         free(page_range);
337     }
338 }
339 
340 /*
341  * Sends a pdf to a printer
342  */
_print_pdf_pages(wJob_t job_handle,printer_capabilities_t * printer_cap,duplex_t duplex,char * pathname,int num_index,int * pages_ary)343 static jint _print_pdf_pages(wJob_t job_handle, printer_capabilities_t *printer_cap,
344         duplex_t duplex, char *pathname, int num_index, int *pages_ary) {
345     int num_pages = num_index;
346 
347     // now, print the pages
348     int page_index;
349     jint result = ERROR;
350 
351     // print forward direction if printer prints pages face down; otherwise print backward
352     // NOTE: last page is sent from calling function
353     if (printer_cap->faceDownTray || duplex) {
354         LOGD("_print_pdf_pages(), pages print face down or duplex, printing in normal order");
355         page_index = 0;
356         while (page_index < num_pages) {
357             LOGD("_print_pdf_pages(), PRINTING PDF: %d", *(pages_ary + page_index));
358             result = wprintPage(job_handle, *(pages_ary + page_index++), pathname, false, true,
359                     0, 0, 0, 0);
360 
361             if (result != OK) {
362                 break;
363             }
364         }
365     } else {
366         LOGI("   _print_pdf_pages(), pages print face up, printing in reverse");
367         page_index = num_pages - 1;
368         while (page_index >= 0) {
369             LOGD("_print_pdf_pages(), PRINTING PDF: %s, page: %d", pathname,
370                     *(pages_ary + page_index));
371             result = wprintPage(job_handle, *(pages_ary + page_index--), pathname, false, true,
372                     0, 0, 0, 0);
373             if (result != OK) {
374                 break;
375             }
376         }
377     }
378 
379     LOGI("   _print_pdf_pages(), printing result: %s", result == OK ? "OK" : "ERROR");
380     return result;
381 }
382 
383 /*
384  * Initialize JNI. Maps java values to jni values.
385  */
_initJNI(JNIEnv * env,jobject callbackReceiver,jstring fakeDir)386 static void _initJNI(JNIEnv *env, jobject callbackReceiver, jstring fakeDir) {
387     _fakeDir = (jstring) (*env)->NewGlobalRef(env, fakeDir);
388 
389     // fill out static accessors for wPrintJobParameters
390     _LocalJobParamsClass = (jclass) (*env)->NewGlobalRef(
391             env, (*env)->FindClass(env, "com/android/bips/jni/LocalJobParams"));
392     _LocalJobParamsField__borderless = (*env)->GetFieldID(env, _LocalJobParamsClass, "borderless",
393             "I");
394     _LocalJobParamsField__duplex = (*env)->GetFieldID(env, _LocalJobParamsClass, "duplex", "I");
395     _LocalJobParamsField__media_size = (*env)->GetFieldID(env, _LocalJobParamsClass, "media_size",
396             "I");
397     _LocalJobParamsField__media_type = (*env)->GetFieldID(env, _LocalJobParamsClass, "media_type",
398             "I");
399     _LocalJobParamsField__media_tray = (*env)->GetFieldID(env, _LocalJobParamsClass, "media_tray",
400             "I");
401     _LocalJobParamsField__color_space = (*env)->GetFieldID(env, _LocalJobParamsClass, "color_space",
402             "I");
403     _LocalJobParamsField__render_flags = (*env)->GetFieldID(env, _LocalJobParamsClass,
404             "render_flags", "I");
405     _LocalJobParamsField__num_copies = (*env)->GetFieldID(env, _LocalJobParamsClass, "num_copies",
406             "I");
407     _LocalJobParamsField__page_range = (*env)->GetFieldID(env, _LocalJobParamsClass, "page_range",
408             "Ljava/lang/String;");
409     _LocalJobParamsField__print_resolution = (*env)->GetFieldID(env, _LocalJobParamsClass,
410             "print_resolution", "I");
411     _LocalJobParamsField__printable_width = (*env)->GetFieldID(env, _LocalJobParamsClass,
412             "printable_width", "I");
413     _LocalJobParamsField__printable_height = (*env)->GetFieldID(env, _LocalJobParamsClass,
414             "printable_height", "I");
415     _LocalJobParamsField__page_width = (*env)->GetFieldID(env, _LocalJobParamsClass, "page_width",
416             "F");
417     _LocalJobParamsField__page_height = (*env)->GetFieldID(env, _LocalJobParamsClass, "page_height",
418             "F");
419     _LocalJobParamsField__page_margin_top = (*env)->GetFieldID(env, _LocalJobParamsClass,
420             "page_margin_top", "F");
421     _LocalJobParamsField__page_margin_left = (*env)->GetFieldID(env, _LocalJobParamsClass,
422             "page_margin_left", "F");
423     _LocalJobParamsField__page_margin_right = (*env)->GetFieldID(env, _LocalJobParamsClass,
424             "page_margin_right", "F");
425     _LocalJobParamsField__page_margin_bottom = (*env)->GetFieldID(env, _LocalJobParamsClass,
426             "page_margin_bottom", "F");
427     _LocalJobParamsField__nativeData = (*env)->GetFieldID(env, _LocalJobParamsClass, "nativeData",
428             "[B");
429     _LocalJobParamsField__fit_to_page = (*env)->GetFieldID(env, _LocalJobParamsClass, "fit_to_page",
430             "Z");
431     _LocalJobParamsField__fill_page = (*env)->GetFieldID(env, _LocalJobParamsClass, "fill_page",
432             "Z");
433     _LocalJobParamsField__auto_rotate = (*env)->GetFieldID(env, _LocalJobParamsClass, "auto_rotate",
434             "Z");
435     _LocalJobParamsField__portrait_mode = (*env)->GetFieldID(env, _LocalJobParamsClass,
436             "portrait_mode", "Z");
437     _LocalJobParamsField__landscape_mode = (*env)->GetFieldID(env, _LocalJobParamsClass,
438             "landscape_mode", "Z");
439     _LocalJobParamsField__document_category = (*env)->GetFieldID(env, _LocalJobParamsClass,
440             "document_category",
441             "Ljava/lang/String;");
442     _LocalJobParamsField__alignment = (*env)->GetFieldID(env, _LocalJobParamsClass, "alignment",
443             "I");
444     _LocalJobParamsField__job_margin_top = (*env)->GetFieldID(env, _LocalJobParamsClass,
445             "job_margin_top", "F");
446     _LocalJobParamsField__job_margin_left = (*env)->GetFieldID(env, _LocalJobParamsClass,
447             "job_margin_left", "F");
448     _LocalJobParamsField__job_margin_right = (*env)->GetFieldID(env, _LocalJobParamsClass,
449             "job_margin_right", "F");
450     _LocalJobParamsField__job_margin_bottom = (*env)->GetFieldID(env, _LocalJobParamsClass,
451             "job_margin_bottom", "F");
452     _LocalJobParamsField__document_scaling = (*env)->GetFieldID(env, _LocalJobParamsClass,
453             "document_scaling", "Z");
454     _LocalJobParamsField__job_name = (*env)->GetFieldID(env, _LocalJobParamsClass, "job_name",
455             "Ljava/lang/String;");
456     _LocalJobParamsField__job_originating_user_name = (*env)->GetFieldID(
457             env, _LocalJobParamsClass, "job_originating_user_name", "Ljava/lang/String;");
458     _LocalJobParamsField__pdf_render_resolution = (*env)->GetFieldID(env, _LocalJobParamsClass,
459             "pdf_render_resolution", "I");
460 
461     // fill out static accessors for LocalPrinterCapabilities
462     _LocalPrinterCapabilitiesClass = (jclass) (*env)->NewGlobalRef(env, (*env)->FindClass(
463             env, "com/android/bips/jni/LocalPrinterCapabilities"));
464     _LocalPrinterCapabilitiesField__path = (*env)->GetFieldID(
465             env, _LocalPrinterCapabilitiesClass, "path", "Ljava/lang/String;");
466     _LocalPrinterCapabilitiesField__name = (*env)->GetFieldID(
467             env, _LocalPrinterCapabilitiesClass, "name", "Ljava/lang/String;");
468     _LocalPrinterCapabilitiesField__uuid = (*env)->GetFieldID(
469             env, _LocalPrinterCapabilitiesClass, "uuid", "Ljava/lang/String;");
470     _LocalPrinterCapabilitiesField__location = (*env)->GetFieldID(
471             env, _LocalPrinterCapabilitiesClass, "location", "Ljava/lang/String;");
472     _LocalPrinterCapabilitiesField__duplex = (*env)->GetFieldID(
473             env, _LocalPrinterCapabilitiesClass, "duplex", "Z");
474     _LocalPrinterCapabilitiesField__borderless = (*env)->GetFieldID(
475             env, _LocalPrinterCapabilitiesClass, "borderless", "Z");
476     _LocalPrinterCapabilitiesField__color = (*env)->GetFieldID(
477             env, _LocalPrinterCapabilitiesClass, "color", "Z");
478     _LocalPrinterCapabilitiesField__isSupported = (*env)->GetFieldID(
479             env, _LocalPrinterCapabilitiesClass, "isSupported", "Z");
480     _LocalPrinterCapabilitiesField__mediaDefault = (*env)->GetFieldID(
481             env, _LocalPrinterCapabilitiesClass, "mediaDefault", "Ljava/lang/String;");
482     _LocalPrinterCapabilitiesField__supportedMediaTypes = (*env)->GetFieldID(
483             env, _LocalPrinterCapabilitiesClass, "supportedMediaTypes", "[I");
484     _LocalPrinterCapabilitiesField__supportedMediaSizes = (*env)->GetFieldID(
485             env, _LocalPrinterCapabilitiesClass, "supportedMediaSizes", "[I");
486     _LocalPrinterCapabilitiesField__nativeData = (*env)->GetFieldID(
487             env, _LocalPrinterCapabilitiesClass, "nativeData", "[B");
488     _LocalPrinterCapabilitiesField__certificate = (*env)->GetFieldID(
489             env, _LocalPrinterCapabilitiesClass, "certificate", "[B");
490 
491     _JobCallbackParamsClass = (jclass) (*env)->NewGlobalRef(env, (*env)->FindClass(
492             env, "com/android/bips/jni/JobCallbackParams"));
493     _JobCallbackParamsMethod__init = (*env)->GetMethodID(env, _JobCallbackParamsClass,
494             "<init>", "()V");
495     _JobCallbackParamsField__jobId = (*env)->GetFieldID(env, _JobCallbackParamsClass, "jobId",
496             "I");
497     _JobCallbackParamsField__jobState = (*env)->GetFieldID(
498             env, _JobCallbackParamsClass, "jobState", "Ljava/lang/String;");
499     _JobCallbackParamsField__jobDoneResult = (*env)->GetFieldID(
500             env, _JobCallbackParamsClass, "jobDoneResult", "Ljava/lang/String;");
501     _JobCallbackParamsField__blockedReasons = (*env)->GetFieldID(
502             env, _JobCallbackParamsClass, "blockedReasons", "[Ljava/lang/String;");
503     _JobCallbackParamsField__certificate = (*env)->GetFieldID(
504             env, _JobCallbackParamsClass, "certificate", "[B");
505 
506     if (callbackReceiver) {
507         _callbackReceiver = (jobject) (*env)->NewGlobalRef(env, callbackReceiver);
508     }
509     if (_callbackReceiver) {
510         _JobCallbackClass = (jclass) (*env)->NewGlobalRef(env, (*env)->GetObjectClass(
511                 env, _callbackReceiver));
512         _JobCallbackMethod__jobCallback = (*env)->GetMethodID(
513                 env, _JobCallbackClass, "jobCallback",
514                 "(ILcom/android/bips/jni/JobCallbackParams;)V");
515     } else {
516         _callbackReceiver = 0;
517     }
518 
519     _PrintServiceStringsClass = (jclass) (*env)->NewGlobalRef(env, (*env)->FindClass(
520             env, "com/android/bips/jni/BackendConstants"));
521     _PrintServiceStringsField__JOB_STATE_QUEUED = (*env)->GetStaticFieldID(
522             env, _PrintServiceStringsClass, "JOB_STATE_QUEUED", "Ljava/lang/String;");
523     _PrintServiceStringsField__JOB_STATE_RUNNING = (*env)->GetStaticFieldID(
524             env, _PrintServiceStringsClass, "JOB_STATE_RUNNING", "Ljava/lang/String;");
525     _PrintServiceStringsField__JOB_STATE_BLOCKED = (*env)->GetStaticFieldID(
526             env, _PrintServiceStringsClass, "JOB_STATE_BLOCKED", "Ljava/lang/String;");
527     _PrintServiceStringsField__JOB_STATE_DONE = (*env)->GetStaticFieldID(
528             env, _PrintServiceStringsClass, "JOB_STATE_DONE", "Ljava/lang/String;");
529     _PrintServiceStringsField__JOB_STATE_OTHER = (*env)->GetStaticFieldID(
530             env, _PrintServiceStringsClass, "JOB_STATE_OTHER", "Ljava/lang/String;");
531     _PrintServiceStringsField__JOB_DONE_OK = (*env)->GetStaticFieldID(
532             env, _PrintServiceStringsClass, "JOB_DONE_OK", "Ljava/lang/String;");
533     _PrintServiceStringsField__JOB_DONE_ERROR = (*env)->GetStaticFieldID(
534             env, _PrintServiceStringsClass, "JOB_DONE_ERROR", "Ljava/lang/String;");
535     _PrintServiceStringsField__JOB_DONE_CANCELLED = (*env)->GetStaticFieldID(
536             env, _PrintServiceStringsClass, "JOB_DONE_CANCELLED", "Ljava/lang/String;");
537     _PrintServiceStringsField__JOB_DONE_CORRUPT = (*env)->GetStaticFieldID(
538             env, _PrintServiceStringsClass, "JOB_DONE_CORRUPT", "Ljava/lang/String;");
539     _PrintServiceStringsField__JOB_DONE_OTHER = (*env)->GetStaticFieldID(
540             env, _PrintServiceStringsClass, "JOB_DONE_OTHER", "Ljava/lang/String;");
541     _PrintServiceStringsField__BLOCKED_REASON__OFFLINE = (*env)->GetStaticFieldID(
542             env, _PrintServiceStringsClass, "BLOCKED_REASON__OFFLINE", "Ljava/lang/String;");
543     _PrintServiceStringsField__BLOCKED_REASON__BUSY = (*env)->GetStaticFieldID(
544             env, _PrintServiceStringsClass, "BLOCKED_REASON__BUSY", "Ljava/lang/String;");
545     _PrintServiceStringsField__BLOCKED_REASON__CANCELLED = (*env)->GetStaticFieldID(
546             env, _PrintServiceStringsClass, "BLOCKED_REASON__CANCELLED", "Ljava/lang/String;");
547     _PrintServiceStringsField__BLOCKED_REASON__OUT_OF_PAPER = (*env)->GetStaticFieldID(
548             env, _PrintServiceStringsClass, "BLOCKED_REASON__OUT_OF_PAPER", "Ljava/lang/String;");
549     _PrintServiceStringsField__BLOCKED_REASON__OUT_OF_INK = (*env)->GetStaticFieldID(
550             env, _PrintServiceStringsClass, "BLOCKED_REASON__OUT_OF_INK", "Ljava/lang/String;");
551     _PrintServiceStringsField__BLOCKED_REASON__OUT_OF_TONER = (*env)->GetStaticFieldID(
552             env, _PrintServiceStringsClass, "BLOCKED_REASON__OUT_OF_TONER", "Ljava/lang/String;");
553     _PrintServiceStringsField__BLOCKED_REASON__JAMMED = (*env)->GetStaticFieldID(
554             env, _PrintServiceStringsClass, "BLOCKED_REASON__JAMMED", "Ljava/lang/String;");
555     _PrintServiceStringsField__BLOCKED_REASON__DOOR_OPEN = (*env)->GetStaticFieldID(
556             env, _PrintServiceStringsClass, "BLOCKED_REASON__DOOR_OPEN", "Ljava/lang/String;");
557     _PrintServiceStringsField__BLOCKED_REASON__SERVICE_REQUEST = (*env)->GetStaticFieldID(
558             env, _PrintServiceStringsClass, "BLOCKED_REASON__SERVICE_REQUEST",
559             "Ljava/lang/String;");
560     _PrintServiceStringsField__BLOCKED_REASON__LOW_ON_INK = (*env)->GetStaticFieldID(
561             env, _PrintServiceStringsClass, "BLOCKED_REASON__LOW_ON_INK", "Ljava/lang/String;");
562     _PrintServiceStringsField__BLOCKED_REASON__LOW_ON_TONER = (*env)->GetStaticFieldID(
563             env, _PrintServiceStringsClass, "BLOCKED_REASON__LOW_ON_TONER", "Ljava/lang/String;");
564     _PrintServiceStringsField__BLOCKED_REASON__REALLY_LOW_ON_INK = (*env)->GetStaticFieldID(
565             env, _PrintServiceStringsClass, "BLOCKED_REASON__REALLY_LOW_ON_INK",
566             "Ljava/lang/String;");
567     _PrintServiceStringsField__BLOCKED_REASON__BAD_CERTIFICATE = (*env)->GetStaticFieldID(
568             env, _PrintServiceStringsClass, "BLOCKED_REASON__BAD_CERTIFICATE",
569             "Ljava/lang/String;");
570     _PrintServiceStringsField__BLOCKED_REASON__UNKNOWN = (*env)->GetStaticFieldID(
571             env, _PrintServiceStringsClass, "BLOCKED_REASON__UNKNOWN", "Ljava/lang/String;");
572 
573     _PrintServiceStringsField__ALIGNMENT__CENTER = (*env)->GetStaticFieldID(
574             env, _PrintServiceStringsClass, "ALIGN_CENTER", "I");
575     _PrintServiceStringsField__ALIGNMENT__CENTER_HORIZONTAL = (*env)->GetStaticFieldID(
576             env, _PrintServiceStringsClass, "ALIGN_CENTER_HORIZONTAL", "I");
577     _PrintServiceStringsField__ALIGNMENT__CENTER_VERTICAL = (*env)->GetStaticFieldID(
578             env, _PrintServiceStringsClass, "ALIGN_CENTER_VERTICIAL", "I");
579     _PrintServiceStringsField__ALIGNMENT__CENTER_HORIZONTAL_ON_ORIENTATION =
580             (*env)->GetStaticFieldID(env, _PrintServiceStringsClass,
581                     "ALIGN_CENTER_HORIZONTAL_ON_ORIENTATION", "I");
582 
583     pdf_render_init(env);
584 }
585 
586 /*
587  * Converts java printer caps to c and saves them to wprintPrinterCaps
588  */
_convertPrinterCaps_to_C(JNIEnv * env,jobject javaPrinterCaps,printer_capabilities_t * wprintPrinterCaps)589 static int _convertPrinterCaps_to_C(JNIEnv *env, jobject javaPrinterCaps,
590         printer_capabilities_t *wprintPrinterCaps) {
591     if (!javaPrinterCaps || !wprintPrinterCaps) {
592         return ERROR;
593     }
594 
595     jbyteArray nativeDataObject = (jbyteArray) (*env)->GetObjectField(
596             env, javaPrinterCaps, _LocalPrinterCapabilitiesField__nativeData);
597     if (!nativeDataObject) {
598         return ERROR;
599     }
600     jbyte *nativeDataPtr = (*env)->GetByteArrayElements(env, nativeDataObject, NULL);
601     memcpy(wprintPrinterCaps, (const void *) nativeDataPtr, sizeof(printer_capabilities_t));
602     (*env)->ReleaseByteArrayElements(env, nativeDataObject, nativeDataPtr, 0);
603 
604     return OK;
605 }
606 
607 /*
608  * Converts printer caps to java and saves them to javaPrinterCaps
609  */
_convertPrinterCaps_to_Java(JNIEnv * env,jobject javaPrinterCaps,const printer_capabilities_t * wprintPrinterCaps)610 static int _convertPrinterCaps_to_Java(JNIEnv *env, jobject javaPrinterCaps,
611         const printer_capabilities_t *wprintPrinterCaps) {
612     if (!javaPrinterCaps || !wprintPrinterCaps) {
613         return ERROR;
614     }
615 
616     int arrayCreated = 0;
617     jbyteArray nativeDataObject = (jbyteArray) (*env)->GetObjectField(
618             env, javaPrinterCaps, _LocalPrinterCapabilitiesField__nativeData);
619     if (!nativeDataObject) {
620         arrayCreated = 1;
621         nativeDataObject = (*env)->NewByteArray(env, sizeof(printer_capabilities_t));
622     }
623 
624     jbyte *nativeDataPtr = (*env)->GetByteArrayElements(env, nativeDataObject, NULL);
625     memcpy((void *) nativeDataPtr, wprintPrinterCaps, sizeof(printer_capabilities_t));
626     (*env)->ReleaseByteArrayElements(env, nativeDataObject, nativeDataPtr, 0);
627 
628     if (arrayCreated) {
629         (*env)->SetObjectField(env, javaPrinterCaps, _LocalPrinterCapabilitiesField__nativeData,
630                 nativeDataObject);
631         (*env)->DeleteLocalRef(env, nativeDataObject);
632     }
633 
634     (*env)->SetBooleanField(env, javaPrinterCaps, _LocalPrinterCapabilitiesField__duplex,
635             (jboolean) wprintPrinterCaps->duplex);
636     (*env)->SetBooleanField(env, javaPrinterCaps,
637             _LocalPrinterCapabilitiesField__borderless,
638             (jboolean) wprintPrinterCaps->borderless);
639     (*env)->SetBooleanField(env, javaPrinterCaps, _LocalPrinterCapabilitiesField__color,
640             (jboolean) wprintPrinterCaps->color);
641     (*env)->SetBooleanField(env, javaPrinterCaps, _LocalPrinterCapabilitiesField__isSupported,
642             (jboolean) wprintPrinterCaps->isSupported);
643 
644     stringToJava(env, javaPrinterCaps, _LocalPrinterCapabilitiesField__mediaDefault,
645             wprintPrinterCaps->mediaDefault);
646     stringToJava(env, javaPrinterCaps, _LocalPrinterCapabilitiesField__path,
647             wprintPrinterCaps->printerUri);
648     stringToJava(env, javaPrinterCaps, _LocalPrinterCapabilitiesField__name,
649             wprintPrinterCaps->name);
650     stringToJava(env, javaPrinterCaps, _LocalPrinterCapabilitiesField__uuid,
651             wprintPrinterCaps->uuid);
652     stringToJava(env, javaPrinterCaps, _LocalPrinterCapabilitiesField__location,
653             wprintPrinterCaps->location);
654 
655     jintArray intArray;
656     int *intArrayPtr;
657     int index;
658 
659     intArray = (*env)->NewIntArray(env, wprintPrinterCaps->numSupportedMediaTypes);
660     intArrayPtr = (*env)->GetIntArrayElements(env, intArray, NULL);
661     for (index = 0; index < wprintPrinterCaps->numSupportedMediaTypes; index++) {
662         intArrayPtr[index] = (int) wprintPrinterCaps->supportedMediaTypes[index];
663     }
664     (*env)->ReleaseIntArrayElements(env, intArray, intArrayPtr, 0);
665     (*env)->SetObjectField(env, javaPrinterCaps,
666             _LocalPrinterCapabilitiesField__supportedMediaTypes, intArray);
667     (*env)->DeleteLocalRef(env, intArray);
668 
669     intArray = (*env)->NewIntArray(env, wprintPrinterCaps->numSupportedMediaSizes);
670     intArrayPtr = (*env)->GetIntArrayElements(env, intArray, NULL);
671     for (index = 0; index < wprintPrinterCaps->numSupportedMediaSizes; index++) {
672         intArrayPtr[index] = (int) wprintPrinterCaps->supportedMediaSizes[index];
673     }
674     (*env)->ReleaseIntArrayElements(env, intArray, intArrayPtr, 0);
675     (*env)->SetObjectField(env, javaPrinterCaps,
676             _LocalPrinterCapabilitiesField__supportedMediaSizes, intArray);
677     (*env)->DeleteLocalRef(env, intArray);
678 
679     int count;
680     for (count = index = 0; index < (sizeof(int) * 8); index++) {
681         if ((wprintPrinterCaps->supportedInputMimeTypes & (1 << index)) != 0) {
682             count++;
683         }
684     }
685 
686     return OK;
687 }
688 
689 /*
690  * Converts str to a java string
691  */
stringToJava(JNIEnv * env,jobject obj,jfieldID id,const char * str)692 static void stringToJava(JNIEnv *env, jobject obj, jfieldID id, const char *str) {
693     jstring jStr;
694 
695     // If null, copy an empty string
696     if (!str) str = "";
697 
698     jStr = (*env)->NewStringUTF(env, str);
699     (*env)->SetObjectField(env, obj, id, jStr);
700     (*env)->DeleteLocalRef(env, jStr);
701 }
702 
703 /*
704  * Converts javaJobParams to C and saves them to wprintJobParams
705  */
_convertJobParams_to_C(JNIEnv * env,jobject javaJobParams,wprint_job_params_t * wprintJobParams)706 static int _convertJobParams_to_C(JNIEnv *env, jobject javaJobParams,
707         wprint_job_params_t *wprintJobParams) {
708     if (!javaJobParams || !wprintJobParams) {
709         return ERROR;
710     }
711 
712     jbyteArray nativeDataObject = (jbyteArray) (*env)->GetObjectField(
713             env, javaJobParams, _LocalJobParamsField__nativeData);
714     if (nativeDataObject == 0) {
715         return ERROR;
716     }
717 
718     jbyte *nativeDataPtr = (*env)->GetByteArrayElements(env, nativeDataObject, NULL);
719     memcpy(wprintJobParams, (const void *) nativeDataPtr, sizeof(wprint_job_params_t));
720     (*env)->ReleaseByteArrayElements(env, nativeDataObject, nativeDataPtr, JNI_ABORT);
721 
722     wprintJobParams->media_size = (media_size_t) (*env)->GetIntField(
723             env, javaJobParams, _LocalJobParamsField__media_size);
724     wprintJobParams->media_type = (media_type_t) (*env)->GetIntField(
725             env, javaJobParams, _LocalJobParamsField__media_type);
726     wprintJobParams->duplex = (duplex_t) (*env)->GetIntField(
727             env, javaJobParams, _LocalJobParamsField__duplex);
728     wprintJobParams->color_space = (color_space_t) (*env)->GetIntField(
729             env, javaJobParams, _LocalJobParamsField__color_space);
730     wprintJobParams->media_tray = (media_tray_t) (*env)->GetIntField(
731             env, javaJobParams, _LocalJobParamsField__media_tray);
732     wprintJobParams->num_copies = (unsigned int) (*env)->GetIntField(
733             env, javaJobParams, _LocalJobParamsField__num_copies);
734     wprintJobParams->borderless = (bool) (*env)->GetIntField(env, javaJobParams,
735             _LocalJobParamsField__borderless);
736     wprintJobParams->render_flags = (unsigned int) (*env)->GetIntField(
737             env, javaJobParams, _LocalJobParamsField__render_flags);
738     wprintJobParams->pdf_render_resolution =
739             (unsigned int) (*env)->GetIntField(env, javaJobParams,
740                     _LocalJobParamsField__pdf_render_resolution);
741     // job margin setting
742     wprintJobParams->job_top_margin = (float) (*env)->GetFloatField(
743             env, javaJobParams, _LocalJobParamsField__job_margin_top);
744     wprintJobParams->job_left_margin = (float) (*env)->GetFloatField(
745             env, javaJobParams, _LocalJobParamsField__job_margin_left);
746     wprintJobParams->job_right_margin = (float) (*env)->GetFloatField(
747             env, javaJobParams, _LocalJobParamsField__job_margin_right);
748     wprintJobParams->job_bottom_margin = (float) (*env)->GetFloatField(
749             env, javaJobParams, _LocalJobParamsField__job_margin_bottom);
750 
751     if ((*env)->GetBooleanField(env, javaJobParams, _LocalJobParamsField__portrait_mode)) {
752         wprintJobParams->render_flags |= RENDER_FLAG_PORTRAIT_MODE;
753     } else if ((*env)->GetBooleanField(env, javaJobParams, _LocalJobParamsField__landscape_mode)) {
754         wprintJobParams->render_flags |= RENDER_FLAG_LANDSCAPE_MODE;
755     } else if ((*env)->GetBooleanField(env, javaJobParams, _LocalJobParamsField__auto_rotate)) {
756         wprintJobParams->render_flags |= RENDER_FLAG_AUTO_ROTATE;
757     }
758     if ((*env)->GetBooleanField(env, javaJobParams, _LocalJobParamsField__fill_page)) {
759         wprintJobParams->render_flags |= AUTO_SCALE_RENDER_FLAGS;
760     } else if ((*env)->GetBooleanField(env, javaJobParams, _LocalJobParamsField__fit_to_page)) {
761         wprintJobParams->render_flags |= AUTO_FIT_RENDER_FLAGS;
762         if ((*env)->GetBooleanField(env, javaJobParams, _LocalJobParamsField__document_scaling)) {
763             wprintJobParams->render_flags |= RENDER_FLAG_DOCUMENT_SCALING;
764         }
765     }
766 
767     int alignment = ((*env)->GetIntField(env, javaJobParams, _LocalJobParamsField__alignment));
768     if (alignment != 0) {
769         wprintJobParams->render_flags &= ~(RENDER_FLAG_CENTER_VERTICAL |
770                 RENDER_FLAG_CENTER_HORIZONTAL |
771                 RENDER_FLAG_CENTER_ON_ORIENTATION);
772         if (alignment & ((*env)->GetStaticIntField(
773                 env, _PrintServiceStringsClass,
774                 _PrintServiceStringsField__ALIGNMENT__CENTER_HORIZONTAL))) {
775             wprintJobParams->render_flags |= RENDER_FLAG_CENTER_HORIZONTAL;
776         }
777         if (alignment & ((*env)->GetStaticIntField(
778                 env, _PrintServiceStringsClass,
779                 _PrintServiceStringsField__ALIGNMENT__CENTER_VERTICAL))) {
780             wprintJobParams->render_flags |= RENDER_FLAG_CENTER_VERTICAL;
781         }
782         if (alignment & ((*env)->GetStaticIntField(
783                 env, _PrintServiceStringsClass,
784                 _PrintServiceStringsField__ALIGNMENT__CENTER_HORIZONTAL_ON_ORIENTATION))) {
785             wprintJobParams->render_flags |= RENDER_FLAG_CENTER_ON_ORIENTATION;
786         }
787         if ((alignment & ((*env)->GetStaticIntField(
788                 env, _PrintServiceStringsClass, _PrintServiceStringsField__ALIGNMENT__CENTER))) ==
789                 ((*env)->GetStaticIntField(env, _PrintServiceStringsClass,
790                         _PrintServiceStringsField__ALIGNMENT__CENTER))) {
791             wprintJobParams->render_flags &= ~RENDER_FLAG_CENTER_ON_ORIENTATION;
792             wprintJobParams->render_flags |= (RENDER_FLAG_CENTER_VERTICAL |
793                     RENDER_FLAG_CENTER_HORIZONTAL);
794         }
795     }
796 
797     jstring docCategory = (jstring) (*env)->GetObjectField(env, javaJobParams,
798             _LocalJobParamsField__document_category);
799     if (docCategory != NULL) {
800         const char *category = (*env)->GetStringUTFChars(env, docCategory, NULL);
801         if (category != NULL) {
802             strncpy(wprintJobParams->docCategory, category,
803                     sizeof(wprintJobParams->docCategory) - 1);
804             (*env)->ReleaseStringUTFChars(env, docCategory, category);
805         }
806     }
807     // job name
808     jstring jobName = (jstring) (*env)->GetObjectField(env, javaJobParams,
809             _LocalJobParamsField__job_name);
810     if (jobName != NULL) {
811         const char *name = (*env)->GetStringUTFChars(env, jobName, NULL);
812         if (name != NULL) {
813             strncpy(wprintJobParams->job_name, name, sizeof(wprintJobParams->job_name) - 1);
814             (*env)->ReleaseStringUTFChars(env, jobName, name);
815         }
816     }
817     // job originating user name
818     jstring jobOriginatingUserName = (jstring) (*env)->GetObjectField(
819             env, javaJobParams, _LocalJobParamsField__job_originating_user_name);
820     if (jobOriginatingUserName != NULL) {
821         const char *name = (*env)->GetStringUTFChars(env, jobOriginatingUserName, NULL);
822         if (name != NULL) {
823             strncpy(wprintJobParams->job_originating_user_name, name,
824                     sizeof(wprintJobParams->job_originating_user_name) - 1);
825             (*env)->ReleaseStringUTFChars(env, jobOriginatingUserName, name);
826         }
827     }
828 
829     free(wprintJobParams->page_range);
830     wprintJobParams->page_range = NULL;
831     jstring pageRangeObject = (jstring) (*env)->GetObjectField(env, javaJobParams,
832             _LocalJobParamsField__page_range);
833     if (pageRangeObject) {
834         int page_range_size = (*env)->GetStringLength(env, pageRangeObject);
835         const jbyte *pageRange = (jbyte *) (*env)->GetStringUTFChars(env, pageRangeObject, 0);
836         if (strcmp((char *) pageRange, "") != 0) {
837             wprintJobParams->page_range = (char *) malloc(page_range_size + 1);
838             memset(wprintJobParams->page_range, 0, page_range_size + 1);
839             strncpy(wprintJobParams->page_range, (char *) pageRange, page_range_size);
840 
841             (*env)->ReleaseStringUTFChars(env, pageRangeObject, (const char *) pageRange);
842         }
843     }
844 
845     return OK;
846 }
847 
848 /*
849  * Converts wprintJobParams to java and saves them to javaJobParams
850  */
_covertJobParams_to_Java(JNIEnv * env,jobject javaJobParams,wprint_job_params_t * wprintJobParams)851 static int _covertJobParams_to_Java(JNIEnv *env, jobject javaJobParams,
852         wprint_job_params_t *wprintJobParams) {
853     if (!javaJobParams || !wprintJobParams) {
854         return ERROR;
855     }
856 
857     jbyteArray nativeDataObject = (jbyteArray) (*env)->GetObjectField(
858             env, javaJobParams, _LocalJobParamsField__nativeData);
859     if (!nativeDataObject) {
860         nativeDataObject = (*env)->NewByteArray(env, sizeof(wprint_job_params_t));
861         (*env)->SetObjectField(env, javaJobParams, _LocalJobParamsField__nativeData,
862                 nativeDataObject);
863         nativeDataObject = (jbyteArray) (*env)->GetObjectField(env, javaJobParams,
864                 _LocalJobParamsField__nativeData);
865     }
866 
867     jbyte *nativeDataPtr = (*env)->GetByteArrayElements(env, nativeDataObject, NULL);
868     memcpy((void *) nativeDataPtr, wprintJobParams, sizeof(wprint_job_params_t));
869     (*env)->ReleaseByteArrayElements(env, nativeDataObject, nativeDataPtr, 0);
870 
871     // update job parameters
872     (*env)->SetIntField(env, javaJobParams, _LocalJobParamsField__media_size,
873             (int) wprintJobParams->media_size);
874     (*env)->SetIntField(env, javaJobParams, _LocalJobParamsField__media_type,
875             (int) wprintJobParams->media_type);
876     (*env)->SetIntField(env, javaJobParams, _LocalJobParamsField__duplex,
877             (int) wprintJobParams->duplex);
878     (*env)->SetIntField(env, javaJobParams, _LocalJobParamsField__color_space,
879             (int) wprintJobParams->color_space);
880     (*env)->SetIntField(env, javaJobParams, _LocalJobParamsField__media_tray,
881             (int) wprintJobParams->media_tray);
882     (*env)->SetIntField(env, javaJobParams, _LocalJobParamsField__num_copies,
883             (int) wprintJobParams->num_copies);
884     (*env)->SetIntField(env, javaJobParams, _LocalJobParamsField__borderless,
885             (int) wprintJobParams->borderless);
886     (*env)->SetIntField(env, javaJobParams, _LocalJobParamsField__render_flags,
887             (int) wprintJobParams->render_flags);
888     (*env)->SetIntField(env, javaJobParams, _LocalJobParamsField__pdf_render_resolution,
889             wprintJobParams->pdf_render_resolution);
890     (*env)->SetBooleanField(env, javaJobParams, _LocalJobParamsField__fit_to_page,
891             (jboolean) ((wprintJobParams->render_flags & AUTO_FIT_RENDER_FLAGS) ==
892                     AUTO_FIT_RENDER_FLAGS));
893     (*env)->SetBooleanField(env, javaJobParams, _LocalJobParamsField__fill_page,
894             (jboolean) ((wprintJobParams->render_flags & AUTO_SCALE_RENDER_FLAGS) ==
895                     AUTO_SCALE_RENDER_FLAGS));
896     (*env)->SetBooleanField(env, javaJobParams, _LocalJobParamsField__auto_rotate,
897             (jboolean) ((wprintJobParams->render_flags & RENDER_FLAG_AUTO_ROTATE) != 0));
898     (*env)->SetBooleanField(env, javaJobParams, _LocalJobParamsField__portrait_mode, (jboolean) (
899             (wprintJobParams->render_flags & RENDER_FLAG_PORTRAIT_MODE) != 0));
900     (*env)->SetBooleanField(env, javaJobParams, _LocalJobParamsField__landscape_mode, (jboolean) (
901             (wprintJobParams->render_flags & RENDER_FLAG_LANDSCAPE_MODE) != 0));
902 
903     // update the printable area & DPI information
904     (*env)->SetIntField(env, javaJobParams, _LocalJobParamsField__print_resolution,
905             (int) wprintJobParams->pixel_units);
906     (*env)->SetIntField(env, javaJobParams, _LocalJobParamsField__printable_width,
907             (int) wprintJobParams->width);
908     (*env)->SetIntField(env, javaJobParams, _LocalJobParamsField__printable_height,
909             (int) wprintJobParams->height);
910 
911     // update the page size information
912     (*env)->SetFloatField(env, javaJobParams, _LocalJobParamsField__page_width,
913             wprintJobParams->page_width);
914     (*env)->SetFloatField(env, javaJobParams, _LocalJobParamsField__page_height,
915             wprintJobParams->page_height);
916     (*env)->SetFloatField(env, javaJobParams, _LocalJobParamsField__page_margin_top,
917             wprintJobParams->page_top_margin);
918     (*env)->SetFloatField(env, javaJobParams, _LocalJobParamsField__page_margin_left,
919             wprintJobParams->page_left_margin);
920     (*env)->SetFloatField(env, javaJobParams, _LocalJobParamsField__page_margin_right,
921             wprintJobParams->page_right_margin);
922     (*env)->SetFloatField(env, javaJobParams, _LocalJobParamsField__page_margin_bottom,
923             wprintJobParams->page_bottom_margin);
924 
925     (*env)->SetFloatField(env, javaJobParams, _LocalJobParamsField__job_margin_top,
926             wprintJobParams->job_top_margin);
927     (*env)->SetFloatField(env, javaJobParams, _LocalJobParamsField__job_margin_left,
928             wprintJobParams->job_left_margin);
929     (*env)->SetFloatField(env, javaJobParams, _LocalJobParamsField__job_margin_right,
930             wprintJobParams->job_right_margin);
931     (*env)->SetFloatField(env, javaJobParams, _LocalJobParamsField__job_margin_bottom,
932             wprintJobParams->job_bottom_margin);
933 
934     return OK;
935 }
936 
937 /*
938  * Handles print job callbacks. Handles job states and blocked reasons
939  */
_wprint_callback_fn(wJob_t job_handle,void * param)940 static void _wprint_callback_fn(wJob_t job_handle, void *param) {
941     jstring jStr;
942     wprint_job_callback_params_t *cb_param = (wprint_job_callback_params_t *) param;
943     if (!cb_param) {
944         return;
945     }
946 
947     int needDetach = 0;
948     JNIEnv *env;
949     if ((*_JVM)->GetEnv(_JVM, (void **) &env, JNI_VERSION_1_6) < 0) {
950         needDetach = 1;
951         if ((*_JVM)->AttachCurrentThread(_JVM, &env, NULL) < 0) {
952             return;
953         }
954     }
955 
956     jobject callbackParams = (*env)->NewObject(env, _JobCallbackParamsClass,
957             _JobCallbackParamsMethod__init);
958     if (callbackParams != 0) {
959         switch (cb_param->state) {
960             case JOB_QUEUED:
961                 jStr = (jstring) (*env)->GetStaticObjectField(
962                         env, _PrintServiceStringsClass,
963                         _PrintServiceStringsField__JOB_STATE_QUEUED);
964                 break;
965             case JOB_RUNNING:
966                 jStr = (jstring) (*env)->GetStaticObjectField(
967                         env, _PrintServiceStringsClass,
968                         _PrintServiceStringsField__JOB_STATE_RUNNING);
969                 break;
970             case JOB_BLOCKED:
971                 jStr = (jstring) (*env)->GetStaticObjectField(
972                         env, _PrintServiceStringsClass,
973                         _PrintServiceStringsField__JOB_STATE_BLOCKED);
974                 break;
975             case JOB_DONE:
976                 jStr = (jstring) (*env)->GetStaticObjectField(
977                         env, _PrintServiceStringsClass,
978                         _PrintServiceStringsField__JOB_STATE_DONE);
979                 break;
980             default:
981                 jStr = (jstring) (*env)->GetStaticObjectField(
982                         env, _PrintServiceStringsClass,
983                         _PrintServiceStringsField__JOB_STATE_OTHER);
984                 break;
985         }
986         (*env)->SetObjectField(env, callbackParams, _JobCallbackParamsField__jobState, jStr);
987 
988         if (cb_param->state == JOB_DONE) {
989             switch (cb_param->job_done_result) {
990                 case OK:
991                     jStr = (jstring) (*env)->GetStaticObjectField(
992                             env, _PrintServiceStringsClass,
993                             _PrintServiceStringsField__JOB_DONE_OK);
994                     break;
995                 case ERROR:
996                     jStr = (jstring) (*env)->GetStaticObjectField(
997                             env, _PrintServiceStringsClass,
998                             _PrintServiceStringsField__JOB_DONE_ERROR);
999                     break;
1000                 case CANCELLED:
1001                     jStr = (jstring) (*env)->GetStaticObjectField(
1002                             env, _PrintServiceStringsClass,
1003                             _PrintServiceStringsField__JOB_DONE_CANCELLED);
1004                     break;
1005                 case CORRUPT:
1006                     jStr = (jstring) (*env)->GetStaticObjectField(
1007                             env, _PrintServiceStringsClass,
1008                             _PrintServiceStringsField__JOB_DONE_CORRUPT);
1009                     break;
1010                 default:
1011                     jStr = (jstring) (*env)->GetStaticObjectField(
1012                             env, _PrintServiceStringsClass,
1013                             _PrintServiceStringsField__JOB_DONE_OTHER);
1014                     break;
1015             }
1016 
1017             (*env)->SetObjectField(env, callbackParams,
1018                     _JobCallbackParamsField__jobDoneResult, jStr);
1019         }
1020 
1021         int i, count;
1022         for (count = i = 0; i < PRINT_STATUS_MAX_STATE; i++) {
1023             if (cb_param->blocked_reasons & (1 << i)) {
1024                 count++;
1025             }
1026         }
1027 
1028         if (count > 0) {
1029             jStr = (*env)->NewStringUTF(env, "");
1030             jobjectArray stringArray = (*env)->NewObjectArray(env, count, (*env)->FindClass(
1031                     env, "java/lang/String"), jStr);
1032             (*env)->DeleteLocalRef(env, jStr);
1033 
1034             unsigned int blocked_reasons = cb_param->blocked_reasons;
1035             for (count = i = 0; i < PRINT_STATUS_MAX_STATE; i++) {
1036                 jStr = NULL;
1037 
1038                 if ((blocked_reasons & (1 << i)) == 0) {
1039                     jStr = NULL;
1040                 } else if (blocked_reasons & BLOCKED_REASON_UNABLE_TO_CONNECT) {
1041                     jStr = (jstring) (*env)->GetStaticObjectField(
1042                             env, _PrintServiceStringsClass,
1043                             _PrintServiceStringsField__BLOCKED_REASON__OFFLINE);
1044                 } else if (blocked_reasons & BLOCKED_REASON_BUSY) {
1045                     jStr = (jstring) (*env)->GetStaticObjectField(
1046                             env, _PrintServiceStringsClass,
1047                             _PrintServiceStringsField__BLOCKED_REASON__BUSY);
1048                 } else if (blocked_reasons & BLOCKED_REASONS_CANCELLED) {
1049                     jStr = (jstring) (*env)->GetStaticObjectField(
1050                             env, _PrintServiceStringsClass,
1051                             _PrintServiceStringsField__BLOCKED_REASON__CANCELLED);
1052                 } else if (blocked_reasons & BLOCKED_REASON_JAMMED) {
1053                     jStr = (jstring) (*env)->GetStaticObjectField(
1054                             env, _PrintServiceStringsClass,
1055                             _PrintServiceStringsField__BLOCKED_REASON__JAMMED);
1056                 } else if (blocked_reasons & BLOCKED_REASON_OUT_OF_PAPER) {
1057                     jStr = (jstring) (*env)->GetStaticObjectField(
1058                             env, _PrintServiceStringsClass,
1059                             _PrintServiceStringsField__BLOCKED_REASON__OUT_OF_PAPER);
1060                 } else if (blocked_reasons & BLOCKED_REASON_OUT_OF_INK) {
1061                     jStr = (jstring) (*env)->GetStaticObjectField(
1062                             env, _PrintServiceStringsClass,
1063                             _PrintServiceStringsField__BLOCKED_REASON__OUT_OF_INK);
1064                 } else if (blocked_reasons & BLOCKED_REASON_OUT_OF_TONER) {
1065                     jStr = (jstring) (*env)->GetStaticObjectField(
1066                             env, _PrintServiceStringsClass,
1067                             _PrintServiceStringsField__BLOCKED_REASON__OUT_OF_TONER);
1068                 } else if (blocked_reasons & BLOCKED_REASON_DOOR_OPEN) {
1069                     jStr = (jstring) (*env)->GetStaticObjectField(
1070                             env, _PrintServiceStringsClass,
1071                             _PrintServiceStringsField__BLOCKED_REASON__DOOR_OPEN);
1072                 } else if (blocked_reasons & BLOCKED_REASON_SVC_REQUEST) {
1073                     jStr = (jstring) (*env)->GetStaticObjectField(
1074                             env, _PrintServiceStringsClass,
1075                             _PrintServiceStringsField__BLOCKED_REASON__SERVICE_REQUEST);
1076                 } else if (blocked_reasons & BLOCKED_REASON_LOW_ON_INK) {
1077                     jStr = (jstring) (*env)->GetStaticObjectField(
1078                             env, _PrintServiceStringsClass,
1079                             _PrintServiceStringsField__BLOCKED_REASON__LOW_ON_INK);
1080                 } else if (blocked_reasons & BLOCKED_REASON_LOW_ON_TONER) {
1081                     jStr = (jstring) (*env)->GetStaticObjectField(
1082                             env, _PrintServiceStringsClass,
1083                             _PrintServiceStringsField__BLOCKED_REASON__LOW_ON_TONER);
1084                 } else if (blocked_reasons &
1085                         BLOCKED_REASON_PRINT_STATUS_VERY_LOW_ON_INK) {
1086                     jStr = (jstring) (*env)->GetStaticObjectField(
1087                             env, _PrintServiceStringsClass,
1088                             _PrintServiceStringsField__BLOCKED_REASON__REALLY_LOW_ON_INK);
1089                 } else if (blocked_reasons & BLOCKED_REASON_BAD_CERTIFICATE) {
1090                     jStr = (jstring) (*env)->GetStaticObjectField(
1091                             env, _PrintServiceStringsClass,
1092                             _PrintServiceStringsField__BLOCKED_REASON__BAD_CERTIFICATE);
1093                 } else if (blocked_reasons & BLOCKED_REASON_UNKNOWN) {
1094                     jStr = (jstring) (*env)->GetStaticObjectField(
1095                             env, _PrintServiceStringsClass,
1096                             _PrintServiceStringsField__BLOCKED_REASON__UNKNOWN);
1097                 }
1098 
1099                 blocked_reasons &= ~(1 << i);
1100                 if (jStr != 0) {
1101                     (*env)->SetObjectArrayElement(env, stringArray, count++, jStr);
1102                 }
1103             }
1104 
1105             (*env)->SetObjectField(env, callbackParams, _JobCallbackParamsField__blockedReasons,
1106                     stringArray);
1107         }
1108 
1109         (*env)->SetIntField(env, callbackParams, _JobCallbackParamsField__jobId,
1110                 (jint) job_handle);
1111 
1112         if (cb_param->certificate) {
1113             LOGI("_wprint_callback_fn: copying certificate len=%d", cb_param->certificate_len);
1114             jbyteArray certificate = (*env)->NewByteArray(env, cb_param->certificate_len);
1115             jbyte *certificateBytes = (*env)->GetByteArrayElements(env, certificate, 0);
1116             memcpy(certificateBytes, (const void *) cb_param->certificate,
1117                 cb_param->certificate_len);
1118             (*env)->ReleaseByteArrayElements(env, certificate, certificateBytes, 0);
1119             (*env)->SetObjectField(env, callbackParams, _JobCallbackParamsField__certificate,
1120                 certificate);
1121             (*env)->DeleteLocalRef(env, certificate);
1122         } else {
1123             LOGI("_wprint_callback_fn: there is no certificate");
1124             // No cert, set NULL
1125             (*env)->SetObjectField(env, callbackParams, _JobCallbackParamsField__certificate,
1126                 NULL);
1127         }
1128 
1129         (*env)->CallVoidMethod(env, _callbackReceiver, _JobCallbackMethod__jobCallback,
1130                 (jint) job_handle, callbackParams);
1131         (*env)->DeleteLocalRef(env, callbackParams);
1132     }
1133 
1134     if (needDetach) {
1135         (*_JVM)->DetachCurrentThread(_JVM);
1136     }
1137 }
1138 
1139 /*
1140  * Initialize wprint JNI
1141  */
Java_com_android_bips_ipp_Backend_nativeInit(JNIEnv * env,jobject obj,jobject callbackReceiver,jstring fakeDir,jint apiVersion)1142 JNIEXPORT jint JNICALL Java_com_android_bips_ipp_Backend_nativeInit(
1143         JNIEnv *env, jobject obj, jobject callbackReceiver, jstring fakeDir,
1144         jint apiVersion) {
1145     LOGI("nativeInit JNIenv is %p", env);
1146     int result;
1147 
1148     // Setup the global JavaVM reference first.
1149     (*env)->GetJavaVM(env, &_JVM);
1150 
1151     // Initialize the Android API version value
1152     g_API_version = apiVersion;
1153 
1154     _initJNI(env, callbackReceiver, fakeDir);
1155 
1156     // initialize wprint library
1157     result = wprintInit();
1158 
1159     // return the result
1160     return result;
1161 }
1162 
1163 /*
1164  * Copies a given string and returns the copy
1165  */
copyToNewString(JNIEnv * env,jstring source)1166 static char *copyToNewString(JNIEnv *env, jstring source) {
1167     const char *fromJava;
1168     char *newString;
1169 
1170     fromJava = (*env)->GetStringUTFChars(env, source, NULL);
1171     if (fromJava == NULL) return NULL;
1172 
1173     newString = (char *) malloc(strlen(fromJava) + 1);
1174     strcpy(newString, fromJava);
1175     (*env)->ReleaseStringUTFChars(env, source, fromJava);
1176 
1177     return newString;
1178 }
1179 
1180 /*
1181  * JNI call to wprint to get capabilities. Returns caps converted to java.
1182  */
Java_com_android_bips_ipp_Backend_nativeGetCapabilities(JNIEnv * env,jobject obj,jstring address,jint port,jstring httpResource,jstring uriScheme,jlong timeout,jobject printerCaps)1183 JNIEXPORT jint JNICALL Java_com_android_bips_ipp_Backend_nativeGetCapabilities(
1184         JNIEnv *env, jobject obj, jstring address, jint port, jstring httpResource,
1185         jstring uriScheme, jlong timeout, jobject printerCaps) {
1186     jint result;
1187     printer_capabilities_t caps;
1188     wprint_connect_info_t connect_info;
1189 
1190     connect_info.printer_addr = copyToNewString(env, address);
1191     connect_info.uri_path = copyToNewString(env, httpResource);
1192     connect_info.uri_scheme = copyToNewString(env, uriScheme);
1193     connect_info.port_num = port;
1194     connect_info.timeout = timeout;
1195     connect_info.validate_certificate = NULL;
1196 
1197     LOGI("nativeGetCapabilities for %s JNIenv is %p", connect_info.printer_addr, env);
1198 
1199     // This call may take a while, and the JNI may be torn down when we return
1200     result = wprintGetCapabilities(&connect_info, &caps);
1201 
1202     if (connect_info.printer_addr) free((char *) connect_info.printer_addr);
1203     if (connect_info.uri_path) free((char *) connect_info.uri_path);
1204     if (connect_info.uri_scheme) free((char *) connect_info.uri_scheme);
1205 
1206     if (!wprintIsRunning() && result == 0) {
1207         result = ERROR;
1208     }
1209 
1210     // additional IPP checks
1211     if (result == 0) {
1212         if (caps.isSupported && (caps.ippVersionMajor < 1)) {
1213             caps.isSupported = 0;
1214         }
1215         _convertPrinterCaps_to_Java(env, printerCaps, &caps);
1216     }
1217 
1218     return result;
1219 }
1220 
1221 /*
1222  * JNI call to wprint to get default job params. Returns job params converted to java.
1223  */
Java_com_android_bips_ipp_Backend_nativeGetDefaultJobParameters(JNIEnv * env,jobject obj,jobject jobParams)1224 JNIEXPORT jint JNICALL Java_com_android_bips_ipp_Backend_nativeGetDefaultJobParameters(
1225         JNIEnv *env, jobject obj, jobject jobParams) {
1226     LOGI("nativeGetDefaultJobParameters, JNIenv is %p", env);
1227     jint result;
1228     wprint_job_params_t params;
1229 
1230     result = wprintGetDefaultJobParams(&params);
1231 
1232     _covertJobParams_to_Java(env, jobParams, &params);
1233     return result;
1234 }
1235 
1236 /*
1237  * JNI call to wprint to get final job params. Returns final params converted to java.
1238  */
Java_com_android_bips_ipp_Backend_nativeGetFinalJobParameters(JNIEnv * env,jobject obj,jobject jobParams,jobject printerCaps)1239 JNIEXPORT jint JNICALL Java_com_android_bips_ipp_Backend_nativeGetFinalJobParameters(
1240         JNIEnv *env, jobject obj, jobject jobParams, jobject printerCaps) {
1241     LOGI("nativeGetFinalJobParameters, JNIenv is %p", env);
1242     jint result;
1243     wprint_job_params_t params;
1244     printer_capabilities_t caps;
1245 
1246     _convertJobParams_to_C(env, jobParams, &params);
1247     _convertPrinterCaps_to_C(env, printerCaps, &caps);
1248 
1249     LOGD("nativeGetFinalJobParameters: After _convertJobParams_to_C: res=%d, name=%s",
1250             params.pdf_render_resolution, params.job_name);
1251     result = wprintGetFinalJobParams(&params, &caps);
1252 
1253     _covertJobParams_to_Java(env, jobParams, &params);
1254     return result;
1255 }
1256 
1257 /*
1258  * Convert certificate (if present) from printer capabilities into job_params.
1259  */
_convertCertificate(JNIEnv * env,jobject printerCaps,wprint_job_params_t * params)1260 static void _convertCertificate(JNIEnv *env, jobject printerCaps, wprint_job_params_t *params) {
1261     params->certificate = NULL;
1262     jbyteArray certificate = (jbyteArray) (*env)->GetObjectField(env, printerCaps,
1263             _LocalPrinterCapabilitiesField__certificate);
1264     if (certificate) {
1265         params->certificate_len = (*env)->GetArrayLength(env, certificate);
1266         params->certificate = malloc(params->certificate_len);
1267         if (params->certificate) {
1268             jbyte *certificateBytes = (*env)->GetByteArrayElements(env, certificate, NULL);
1269             memcpy(params->certificate, certificateBytes, params->certificate_len);
1270             (*env)->ReleaseByteArrayElements(env, certificate, certificateBytes, JNI_ABORT);
1271         }
1272     }
1273 }
1274 
1275 /*
1276  * JNI call to wprint to start a print job. Takes connection params, job params, caps, and file
1277  * array to complete the job
1278  */
Java_com_android_bips_ipp_Backend_nativeStartJob(JNIEnv * env,jobject obj,jstring address,jint port,jstring mimeType,jobject jobParams,jobject printerCaps,jobject fileArray,jstring jobDebugDir,jstring scheme)1279 JNIEXPORT jint JNICALL Java_com_android_bips_ipp_Backend_nativeStartJob(
1280         JNIEnv *env, jobject obj, jstring address, jint port, jstring mimeType, jobject jobParams,
1281         jobject printerCaps, jobject fileArray, jstring jobDebugDir, jstring scheme) {
1282     LOGI("nativeStartJob, JNIenv is %p", env);
1283     jint result = ERROR;
1284     wJob_t job_handle = ERROR;
1285     bool hasFiles = false;
1286 
1287     wprint_job_params_t params;
1288     printer_capabilities_t caps;
1289 
1290     _convertJobParams_to_C(env, jobParams, &params);
1291     _convertPrinterCaps_to_C(env, printerCaps, &caps);
1292     _convertCertificate(env, printerCaps, &params);
1293 
1294     LOGD("nativeStartJob: After _convertJobParams_to_C: res=%d, name=%s",
1295             params.pdf_render_resolution, params.job_name);
1296 
1297     const char *addressStr = (*env)->GetStringUTFChars(env, address, NULL);
1298     const char *mimeTypeStr = (*env)->GetStringUTFChars(env, mimeType, NULL);
1299     const char *dataDirStr = (*env)->GetStringUTFChars(env, _fakeDir, NULL);
1300     const char *schemeStr = (*env)->GetStringUTFChars(env, scheme, NULL);
1301 
1302     jsize len = 0;
1303     jobjectArray array;
1304 
1305     if (fileArray) {
1306         array = (jobjectArray) fileArray;
1307         len = (*env)->GetArrayLength(env, array);
1308         hasFiles = (len > 0);
1309     }
1310 
1311     int index = 0, pageIndex, incrementor;
1312     int page_range_arr[len];
1313 
1314     // Initialize page_range_arr (address defect reported by Coverity scans)
1315     memset((char *) page_range_arr, 0, sizeof(int) * len);
1316 
1317     int pdf_pages_ary[len];
1318     int pages_ary[len][MAX_NUM_PAGES];
1319 
1320     if (hasFiles) {
1321         result = OK;
1322         for (pageIndex = 0; ((result == OK) && (pageIndex < len)); pageIndex++) {
1323             jstring page = (jstring) (*env)->GetObjectArrayElement(env, array, pageIndex);
1324             const char *pageStr = (*env)->GetStringUTFChars(env, page, NULL);
1325             if (pageStr == NULL) {
1326                 result = ERROR;
1327             } else {
1328                 int page_count = 0;
1329                 if (_get_pdf_page_count(mimeTypeStr, &page_count, pageStr)) {
1330                     pdf_pages_ary[pageIndex] = page_count;
1331                     page_range_arr[pageIndex] = 0;
1332                     char page_range_str[MAX_NUM_PAGES];
1333                     memset(page_range_str, 0, MAX_NUM_PAGES);
1334                     _get_pdf_page_range(env, jobParams, &pages_ary[pageIndex][0],
1335                             pdf_pages_ary[pageIndex], &page_range_arr[pageIndex], page_range_str);
1336                 }
1337             }
1338             (*env)->ReleaseStringUTFChars(env, page, pageStr);
1339         }
1340 
1341         jstring page = (jstring) (*env)->GetObjectArrayElement(env, array, index);
1342         const char *pageStr = (*env)->GetStringUTFChars(env, page, NULL);
1343         if (pageStr == NULL) {
1344             result = ERROR;
1345         }
1346 
1347         if (len == 1) {
1348             if (_is_pdf_doc((char *) mimeTypeStr, (char *) pageStr)) {
1349                 if (page_range_arr[0] == 1) {
1350                     LOGI("smart duplex, disabling duplex");
1351                     params.duplex = DUPLEX_MODE_NONE;
1352                 }
1353             } else {
1354                 LOGI("smart duplex, disabling duplex");
1355                 params.duplex = DUPLEX_MODE_NONE;
1356             }
1357         }
1358 
1359         (*env)->ReleaseStringUTFChars(env, page, pageStr);
1360         const char *jobDebugDirStr = NULL;
1361         if (jobDebugDir != NULL) {
1362             jobDebugDirStr = (*env)->GetStringUTFChars(env, jobDebugDir, NULL);
1363         }
1364         result = wprintStartJob(addressStr, port, &params, &caps, (char *) mimeTypeStr,
1365                 (char *) dataDirStr, _wprint_callback_fn, jobDebugDirStr, schemeStr);
1366         if (result == ERROR) {
1367             LOGE("failed to start job: error code :%d", errno);
1368         }
1369         if ((jobDebugDir != NULL) && (jobDebugDirStr != NULL)) {
1370             (*env)->ReleaseStringUTFChars(env, jobDebugDir, jobDebugDirStr);
1371         }
1372     } else {
1373         LOGE("empty file list");
1374     }
1375     if (result != ERROR) {
1376         job_handle = (wJob_t) result;
1377 
1378         // register job handle with service
1379         if (caps.faceDownTray || params.duplex) {
1380             index = 0;
1381             incrementor = 1;
1382         } else {
1383             index = len - 1;
1384             incrementor = -1;
1385         }
1386 
1387         result = OK;
1388         for (pageIndex = 1; ((result == OK) && (pageIndex <= len)); pageIndex++) {
1389             jstring page = (jstring) (*env)->GetObjectArrayElement(env, array, index);
1390             const char *pageStr = (*env)->GetStringUTFChars(env, page, NULL);
1391             if (pageStr == NULL) {
1392                 result = ERROR;
1393             } else {
1394                 if (_is_pdf_doc((char *) mimeTypeStr, (char *) pageStr)) {
1395                     result = _print_pdf_pages(job_handle, &caps, params.duplex, (char *) pageStr,
1396                             page_range_arr[index], pages_ary[index]);
1397                 } else {
1398                     result = wprintPage(job_handle, pageIndex, (char *) pageStr, false, false,
1399                             0, 0, 0, 0);
1400                 }
1401             }
1402             (*env)->ReleaseStringUTFChars(env, page, pageStr);
1403             index += incrementor;
1404         }
1405 
1406         wprintPage(job_handle, pageIndex, NULL, true, false, 0, 0, 0, 0);
1407         if (result != OK) {
1408             LOGE("failed to add some pages, aborting job");
1409             wprintCancelJob(job_handle);
1410             wprintEndJob(job_handle);
1411             job_handle = ERROR;
1412         }
1413     }
1414 
1415     if (params.certificate) {
1416         free(params.certificate);
1417     }
1418     (*env)->ReleaseStringUTFChars(env, mimeType, mimeTypeStr);
1419     (*env)->ReleaseStringUTFChars(env, address, addressStr);
1420     (*env)->ReleaseStringUTFChars(env, _fakeDir, dataDirStr);
1421     (*env)->ReleaseStringUTFChars(env, scheme, schemeStr);
1422     return job_handle;
1423 }
1424 
1425 /*
1426  * JNI call to wprint to end a print job
1427  */
Java_com_android_bips_ipp_Backend_nativeEndJob(JNIEnv * env,jobject obj,jint job_handle)1428 JNIEXPORT jint JNICALL Java_com_android_bips_ipp_Backend_nativeEndJob(
1429         JNIEnv *env, jobject obj, jint job_handle) {
1430     LOGI("nativeEndJob, JNIenv is %p", env);
1431     return wprintEndJob((wJob_t) job_handle);
1432 }
1433 
1434 /*
1435  * JNI call to wprint to cancel a print job
1436  */
Java_com_android_bips_ipp_Backend_nativeCancelJob(JNIEnv * env,jobject obj,jint job_handle)1437 JNIEXPORT jint JNICALL Java_com_android_bips_ipp_Backend_nativeCancelJob(
1438         JNIEnv *env, jobject obj, jint job_handle) {
1439     LOGI("nativeCancelJob, JNIenv is %p", env);
1440     return wprintCancelJob((wJob_t) job_handle);
1441 }
1442 
1443 /*
1444  * JNI call to wprint to exit
1445  */
Java_com_android_bips_ipp_Backend_nativeExit(JNIEnv * env,jobject obj)1446 JNIEXPORT jint JNICALL Java_com_android_bips_ipp_Backend_nativeExit(JNIEnv *env, jobject obj) {
1447     LOGI("nativeExit, JNIenv is %p", env);
1448 
1449     (*env)->DeleteGlobalRef(env, _LocalJobParamsClass);
1450     (*env)->DeleteGlobalRef(env, _LocalPrinterCapabilitiesClass);
1451     (*env)->DeleteGlobalRef(env, _JobCallbackParamsClass);
1452     if (_callbackReceiver) {
1453         (*env)->DeleteGlobalRef(env, _callbackReceiver);
1454     }
1455     if (_JobCallbackClass) {
1456         (*env)->DeleteGlobalRef(env, _JobCallbackClass);
1457     }
1458     (*env)->DeleteGlobalRef(env, _fakeDir);
1459     (*env)->DeleteGlobalRef(env, _PrintServiceStringsClass);
1460 
1461     pdf_render_deinit(env);
1462     return wprintExit();
1463 }
1464 
1465 /*
1466  * Sets app name/version and os name
1467  */
Java_com_android_bips_ipp_Backend_nativeSetSourceInfo(JNIEnv * env,jobject obj,jstring appName,jstring appVersion,jstring osName)1468 JNIEXPORT void JNICALL Java_com_android_bips_ipp_Backend_nativeSetSourceInfo(
1469         JNIEnv *env, jobject obj, jstring appName, jstring appVersion, jstring osName) {
1470     LOGI("nativeSetSourceInfo, JNIenv is %p", env);
1471     const char *appNameStr = (*env)->GetStringUTFChars(env, appName, NULL);
1472     const char *appVersionStr = (*env)->GetStringUTFChars(env, appVersion, NULL);
1473     const char *osNameStr = (*env)->GetStringUTFChars(env, osName, NULL);
1474     wprintSetSourceInfo(appNameStr, appVersionStr, osNameStr);
1475     (*env)->ReleaseStringUTFChars(env, appName, appNameStr);
1476     (*env)->ReleaseStringUTFChars(env, appVersion, appVersionStr);
1477     (*env)->ReleaseStringUTFChars(env, osName, osNameStr);
1478 }