Path: blob/master/src/java.desktop/unix/native/common/awt/CUPSfuncs.c
66645 views
/*1* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425#include <jni.h>26#include <jni_util.h>27#include <jvm_md.h>28#include <dlfcn.h>29#include <cups/cups.h>30#include <cups/ppd.h>313233//#define CUPS_DEBUG3435#ifdef CUPS_DEBUG36#define DPRINTF(x, y) fprintf(stderr, x, y);37#else38#define DPRINTF(x, y)39#endif4041typedef const char* (*fn_cupsServer)(void);42typedef int (*fn_ippPort)(void);43typedef http_t* (*fn_httpConnect)(const char *, int);44typedef void (*fn_httpClose)(http_t *);45typedef char* (*fn_cupsGetPPD)(const char *);46typedef cups_dest_t* (*fn_cupsGetDest)(const char *name,47const char *instance, int num_dests, cups_dest_t *dests);48typedef int (*fn_cupsGetDests)(cups_dest_t **dests);49typedef void (*fn_cupsFreeDests)(int num_dests, cups_dest_t *dests);50typedef ppd_file_t* (*fn_ppdOpenFile)(const char *);51typedef void (*fn_ppdClose)(ppd_file_t *);52typedef ppd_option_t* (*fn_ppdFindOption)(ppd_file_t *, const char *);53typedef ppd_size_t* (*fn_ppdPageSize)(ppd_file_t *, char *);5455fn_cupsServer j2d_cupsServer;56fn_ippPort j2d_ippPort;57fn_httpConnect j2d_httpConnect;58fn_httpClose j2d_httpClose;59fn_cupsGetPPD j2d_cupsGetPPD;60fn_cupsGetDest j2d_cupsGetDest;61fn_cupsGetDests j2d_cupsGetDests;62fn_cupsFreeDests j2d_cupsFreeDests;63fn_ppdOpenFile j2d_ppdOpenFile;64fn_ppdClose j2d_ppdClose;65fn_ppdFindOption j2d_ppdFindOption;66fn_ppdPageSize j2d_ppdPageSize;676869/*70* Initialize library functions.71* // REMIND : move tab , add dlClose before return72*/73JNIEXPORT jboolean JNICALL74Java_sun_print_CUPSPrinter_initIDs(JNIEnv *env,75jobject printObj) {76void *handle = dlopen(VERSIONED_JNI_LIB_NAME("cups", "2"),77RTLD_LAZY | RTLD_GLOBAL);7879if (handle == NULL) {80handle = dlopen(JNI_LIB_NAME("cups"), RTLD_LAZY | RTLD_GLOBAL);81if (handle == NULL) {82return JNI_FALSE;83}84}8586j2d_cupsServer = (fn_cupsServer)dlsym(handle, "cupsServer");87if (j2d_cupsServer == NULL) {88dlclose(handle);89return JNI_FALSE;90}9192j2d_ippPort = (fn_ippPort)dlsym(handle, "ippPort");93if (j2d_ippPort == NULL) {94dlclose(handle);95return JNI_FALSE;96}9798j2d_httpConnect = (fn_httpConnect)dlsym(handle, "httpConnect");99if (j2d_httpConnect == NULL) {100dlclose(handle);101return JNI_FALSE;102}103104j2d_httpClose = (fn_httpClose)dlsym(handle, "httpClose");105if (j2d_httpClose == NULL) {106dlclose(handle);107return JNI_FALSE;108}109110j2d_cupsGetPPD = (fn_cupsGetPPD)dlsym(handle, "cupsGetPPD");111if (j2d_cupsGetPPD == NULL) {112dlclose(handle);113return JNI_FALSE;114}115116j2d_cupsGetDest = (fn_cupsGetDest)dlsym(handle, "cupsGetDest");117if (j2d_cupsGetDest == NULL) {118dlclose(handle);119return JNI_FALSE;120}121122j2d_cupsGetDests = (fn_cupsGetDests)dlsym(handle, "cupsGetDests");123if (j2d_cupsGetDests == NULL) {124dlclose(handle);125return JNI_FALSE;126}127128j2d_cupsFreeDests = (fn_cupsFreeDests)dlsym(handle, "cupsFreeDests");129if (j2d_cupsFreeDests == NULL) {130dlclose(handle);131return JNI_FALSE;132}133134j2d_ppdOpenFile = (fn_ppdOpenFile)dlsym(handle, "ppdOpenFile");135if (j2d_ppdOpenFile == NULL) {136dlclose(handle);137return JNI_FALSE;138139}140141j2d_ppdClose = (fn_ppdClose)dlsym(handle, "ppdClose");142if (j2d_ppdClose == NULL) {143dlclose(handle);144return JNI_FALSE;145146}147148j2d_ppdFindOption = (fn_ppdFindOption)dlsym(handle, "ppdFindOption");149if (j2d_ppdFindOption == NULL) {150dlclose(handle);151return JNI_FALSE;152}153154j2d_ppdPageSize = (fn_ppdPageSize)dlsym(handle, "ppdPageSize");155if (j2d_ppdPageSize == NULL) {156dlclose(handle);157return JNI_FALSE;158}159160return JNI_TRUE;161}162163/*164* Gets CUPS server name.165*166*/167JNIEXPORT jstring JNICALL168Java_sun_print_CUPSPrinter_getCupsServer(JNIEnv *env,169jobject printObj)170{171jstring cServer = NULL;172const char* server = j2d_cupsServer();173if (server != NULL) {174cServer = JNU_NewStringPlatform(env, server);175}176return cServer;177}178179/*180* Gets CUPS port name.181*182*/183JNIEXPORT jint JNICALL184Java_sun_print_CUPSPrinter_getCupsPort(JNIEnv *env,185jobject printObj)186{187int port = j2d_ippPort();188return (jint) port;189}190191192/*193* Gets CUPS default printer name.194*195*/196JNIEXPORT jstring JNICALL197Java_sun_print_CUPSPrinter_getCupsDefaultPrinter(JNIEnv *env,198jobject printObj)199{200jstring cDefPrinter = NULL;201cups_dest_t *dests;202char *defaultPrinter = NULL;203int num_dests = j2d_cupsGetDests(&dests);204int i = 0;205cups_dest_t *dest = j2d_cupsGetDest(NULL, NULL, num_dests, dests);206if (dest != NULL) {207defaultPrinter = dest->name;208if (defaultPrinter != NULL) {209cDefPrinter = JNU_NewStringPlatform(env, defaultPrinter);210}211}212j2d_cupsFreeDests(num_dests, dests);213return cDefPrinter;214}215216/*217* Returns list of default local printers218*/219JNIEXPORT jobjectArray JNICALL220Java_sun_print_CUPSPrinter_getCupsDefaultPrinters(JNIEnv *env,221jobject printObj)222{223cups_dest_t *dests;224int i, j, num_dests;225jstring utf_str;226jclass cls;227jobjectArray nameArray = NULL;228229cls = (*env)->FindClass(env, "java/lang/String");230CHECK_NULL_RETURN(cls, NULL);231232num_dests = j2d_cupsGetDests(&dests);233234if (dests == NULL) {235return NULL;236}237238nameArray = (*env)->NewObjectArray(env, num_dests, cls, NULL);239if (nameArray == NULL) {240j2d_cupsFreeDests(num_dests, dests);241DPRINTF("CUPSfuncs::bad alloc new array\n", "")242return NULL;243}244245for (i = 0; i < num_dests; i++) {246utf_str = JNU_NewStringPlatform(env, dests[i].name);247if (utf_str == NULL) {248(*env)->ExceptionClear(env);249for (j = i - 1; j >= 0; j--) {250utf_str = (*env)->GetObjectArrayElement(env, nameArray, j);251(*env)->SetObjectArrayElement(env, nameArray, j, NULL);252(*env)->DeleteLocalRef(env, utf_str);253utf_str = NULL;254}255j2d_cupsFreeDests(num_dests, dests);256(*env)->DeleteLocalRef(env, nameArray);257DPRINTF("CUPSfuncs::bad alloc new string ->name\n", "")258return NULL;259}260(*env)->SetObjectArrayElement(env, nameArray, i, utf_str);261(*env)->DeleteLocalRef(env, utf_str);262}263264j2d_cupsFreeDests(num_dests, dests);265return nameArray;266}267268/*269* Checks if connection can be made to the server.270*271*/272JNIEXPORT jboolean JNICALL273Java_sun_print_CUPSPrinter_canConnect(JNIEnv *env,274jobject printObj,275jstring server,276jint port)277{278const char *serverName;279serverName = (*env)->GetStringUTFChars(env, server, NULL);280if (serverName != NULL) {281http_t *http = j2d_httpConnect(serverName, (int)port);282(*env)->ReleaseStringUTFChars(env, server, serverName);283if (http != NULL) {284j2d_httpClose(http);285return JNI_TRUE;286}287}288return JNI_FALSE;289}290291292/*293* Returns list of media: pages + trays294*/295JNIEXPORT jobjectArray JNICALL296Java_sun_print_CUPSPrinter_getMedia(JNIEnv *env,297jobject printObj,298jstring printer)299{300ppd_file_t *ppd;301ppd_option_t *optionTray, *optionPage;302ppd_choice_t *choice;303const char *name;304const char *filename;305int i, nTrays=0, nPages=0, nTotal=0;306jstring utf_str;307jclass cls;308jobjectArray nameArray = NULL;309310name = (*env)->GetStringUTFChars(env, printer, NULL);311if (name == NULL) {312(*env)->ExceptionClear(env);313JNU_ThrowOutOfMemoryError(env, "Could not create printer name");314return NULL;315}316317// NOTE: cupsGetPPD returns a pointer to a filename of a temporary file.318// unlink() must be caled to remove the file when finished using it.319filename = j2d_cupsGetPPD(name);320(*env)->ReleaseStringUTFChars(env, printer, name);321CHECK_NULL_RETURN(filename, NULL);322323cls = (*env)->FindClass(env, "java/lang/String");324CHECK_NULL_RETURN(cls, NULL);325326if ((ppd = j2d_ppdOpenFile(filename)) == NULL) {327unlink(filename);328DPRINTF("CUPSfuncs::unable to open PPD %s\n", filename);329return NULL;330}331332optionPage = j2d_ppdFindOption(ppd, "PageSize");333if (optionPage != NULL) {334nPages = optionPage->num_choices;335}336337optionTray = j2d_ppdFindOption(ppd, "InputSlot");338if (optionTray != NULL) {339nTrays = optionTray->num_choices;340}341342if ((nTotal = (nPages+nTrays) *2) > 0) {343nameArray = (*env)->NewObjectArray(env, nTotal, cls, NULL);344if (nameArray == NULL) {345unlink(filename);346j2d_ppdClose(ppd);347DPRINTF("CUPSfuncs::bad alloc new array\n", "")348if (!(*env)->ExceptionCheck(env)) {349JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError");350}351return NULL;352}353354for (i = 0; optionPage!=NULL && i<nPages; i++) {355choice = (optionPage->choices)+i;356utf_str = JNU_NewStringPlatform(env, choice->text);357if (utf_str == NULL) {358unlink(filename);359j2d_ppdClose(ppd);360DPRINTF("CUPSfuncs::bad alloc new string ->text\n", "")361if (!(*env)->ExceptionCheck(env)) {362JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError");363}364return NULL;365}366(*env)->SetObjectArrayElement(env, nameArray, i*2, utf_str);367(*env)->DeleteLocalRef(env, utf_str);368utf_str = JNU_NewStringPlatform(env, choice->choice);369if (utf_str == NULL) {370unlink(filename);371j2d_ppdClose(ppd);372DPRINTF("CUPSfuncs::bad alloc new string ->choice\n", "")373if (!(*env)->ExceptionCheck(env)) {374JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError");375}376return NULL;377}378(*env)->SetObjectArrayElement(env, nameArray, i*2+1, utf_str);379(*env)->DeleteLocalRef(env, utf_str);380}381382for (i = 0; optionTray!=NULL && i<nTrays; i++) {383choice = (optionTray->choices)+i;384utf_str = JNU_NewStringPlatform(env, choice->text);385if (utf_str == NULL) {386unlink(filename);387j2d_ppdClose(ppd);388DPRINTF("CUPSfuncs::bad alloc new string text\n", "")389if (!(*env)->ExceptionCheck(env)) {390JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError");391}392return NULL;393}394(*env)->SetObjectArrayElement(env, nameArray,395(nPages+i)*2, utf_str);396(*env)->DeleteLocalRef(env, utf_str);397utf_str = JNU_NewStringPlatform(env, choice->choice);398if (utf_str == NULL) {399unlink(filename);400j2d_ppdClose(ppd);401DPRINTF("CUPSfuncs::bad alloc new string choice\n", "")402if (!(*env)->ExceptionCheck(env)) {403JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError");404}405return NULL;406}407(*env)->SetObjectArrayElement(env, nameArray,408(nPages+i)*2+1, utf_str);409(*env)->DeleteLocalRef(env, utf_str);410}411}412j2d_ppdClose(ppd);413unlink(filename);414return nameArray;415}416417418/*419* Returns list of page sizes and imageable area.420*/421JNIEXPORT jfloatArray JNICALL422Java_sun_print_CUPSPrinter_getPageSizes(JNIEnv *env,423jobject printObj,424jstring printer)425{426ppd_file_t *ppd;427ppd_option_t *option;428ppd_choice_t *choice;429ppd_size_t *size;430const char *filename = NULL;431int i;432jobjectArray sizeArray = NULL;433jfloat *dims;434435const char *name = (*env)->GetStringUTFChars(env, printer, NULL);436if (name == NULL) {437(*env)->ExceptionClear(env);438JNU_ThrowOutOfMemoryError(env, "Could not create printer name");439return NULL;440}441442// NOTE: cupsGetPPD returns a pointer to a filename of a temporary file.443// unlink() must be called to remove the file after using it.444filename = j2d_cupsGetPPD(name);445(*env)->ReleaseStringUTFChars(env, printer, name);446CHECK_NULL_RETURN(filename, NULL);447if ((ppd = j2d_ppdOpenFile(filename)) == NULL) {448unlink(filename);449DPRINTF("unable to open PPD %s\n", filename)450return NULL;451}452option = j2d_ppdFindOption(ppd, "PageSize");453if (option != NULL && option->num_choices > 0) {454// create array of dimensions - (num_choices * 6)455//to cover length & height456DPRINTF( "CUPSfuncs::option->num_choices %d\n", option->num_choices)457// +1 is for storing the default media index458sizeArray = (*env)->NewFloatArray(env, option->num_choices*6+1);459if (sizeArray == NULL) {460unlink(filename);461j2d_ppdClose(ppd);462DPRINTF("CUPSfuncs::bad alloc new float array\n", "")463(*env)->ExceptionClear(env);464JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError");465return NULL;466}467468dims = (*env)->GetFloatArrayElements(env, sizeArray, NULL);469if (dims == NULL) {470unlink(filename);471j2d_ppdClose(ppd);472(*env)->ExceptionClear(env);473JNU_ThrowOutOfMemoryError(env, "Could not create printer name");474return NULL;475}476for (i = 0; i<option->num_choices; i++) {477choice = (option->choices)+i;478// get the index of the default page479if (!strcmp(choice->choice, option->defchoice)) {480dims[option->num_choices*6] = (float)i;481}482size = j2d_ppdPageSize(ppd, choice->choice);483if (size != NULL) {484// paper width and height485dims[i*6] = size->width;486dims[(i*6)+1] = size->length;487// paper printable area488dims[(i*6)+2] = size->left;489dims[(i*6)+3] = size->top;490dims[(i*6)+4] = size->right;491dims[(i*6)+5] = size->bottom;492}493}494495(*env)->ReleaseFloatArrayElements(env, sizeArray, dims, 0);496}497498j2d_ppdClose(ppd);499unlink(filename);500return sizeArray;501}502503/*504* Populates the supplied ArrayList<Integer> with resolutions.505* The first pair of elements will be the default resolution.506* If resolution isn't supported the list will be empty.507* If needed we can add a 2nd ArrayList<String> which would508* be populated with the corresponding UI name.509* PPD specifies the syntax for resolution as either "Ndpi" or "MxNdpi",510* eg 300dpi or 600x600dpi. The former is a shorthand where xres==yres.511* We will always expand to the latter as we use a single array list.512* Note: getMedia() and getPageSizes() both open the ppd file513* This is not going to scale forever so if we add anymore we514* should look to consolidate this.515*/516JNIEXPORT void JNICALL517Java_sun_print_CUPSPrinter_getResolutions(JNIEnv *env,518jobject printObj,519jstring printer,520jobject arrayList)521{522ppd_file_t *ppd = NULL;523ppd_option_t *resolution;524int defx = 0, defy = 0;525int resx = 0, resy = 0;526jclass intCls, cls;527jmethodID intCtr, arrListAddMID;528int i;529const char *name = NULL;530const char *filename = NULL;531532intCls = (*env)->FindClass(env, "java/lang/Integer");533CHECK_NULL(intCls);534intCtr = (*env)->GetMethodID(env, intCls, "<init>", "(I)V");535CHECK_NULL(intCtr);536cls = (*env)->FindClass(env, "java/util/ArrayList");537CHECK_NULL(cls);538arrListAddMID =539(*env)->GetMethodID(env, cls, "add", "(Ljava/lang/Object;)Z");540CHECK_NULL(arrListAddMID);541542name = (*env)->GetStringUTFChars(env, printer, NULL);543if (name == NULL) {544(*env)->ExceptionClear(env);545JNU_ThrowOutOfMemoryError(env, "Could not create printer name");546return;547}548549550// NOTE: cupsGetPPD returns a pointer to a filename of a temporary file.551// unlink() must be called to remove the file after using it.552filename = j2d_cupsGetPPD(name);553(*env)->ReleaseStringUTFChars(env, printer, name);554CHECK_NULL(filename);555if ((ppd = j2d_ppdOpenFile(filename)) == NULL) {556unlink(filename);557DPRINTF("unable to open PPD %s\n", filename)558}559resolution = j2d_ppdFindOption(ppd, "Resolution");560if (resolution != NULL) {561int matches = sscanf(resolution->defchoice, "%dx%ddpi", &defx, &defy);562if (matches == 2) {563if (defx <= 0 || defy <= 0) {564defx = 0;565defy = 0;566}567} else {568matches = sscanf(resolution->defchoice, "%ddpi", &defx);569if (matches == 1) {570if (defx <= 0) {571defx = 0;572} else {573defy = defx;574}575}576}577if (defx > 0) {578jobject rxObj, ryObj;579rxObj = (*env)->NewObject(env, intCls, intCtr, defx);580CHECK_NULL(rxObj);581ryObj = (*env)->NewObject(env, intCls, intCtr, defy);582CHECK_NULL(ryObj);583(*env)->CallBooleanMethod(env, arrayList, arrListAddMID, rxObj);584(*env)->CallBooleanMethod(env, arrayList, arrListAddMID, ryObj);585}586587for (i = 0; i < resolution->num_choices; i++) {588char *resStr = resolution->choices[i].choice;589int matches = sscanf(resStr, "%dx%ddpi", &resx, &resy);590if (matches == 2) {591if (resx <= 0 || resy <= 0) {592resx = 0;593resy = 0;594}595} else {596matches = sscanf(resStr, "%ddpi", &resx);597if (matches == 1) {598if (resx <= 0) {599resx = 0;600} else {601resy = resx;602}603}604}605if (resx > 0 && (resx != defx || resy != defy )) {606jobject rxObj, ryObj;607rxObj = (*env)->NewObject(env, intCls, intCtr, resx);608CHECK_NULL(rxObj);609ryObj = (*env)->NewObject(env, intCls, intCtr, resy);610CHECK_NULL(ryObj);611(*env)->CallBooleanMethod(env, arrayList, arrListAddMID, rxObj);612(*env)->CallBooleanMethod(env, arrayList, arrListAddMID, ryObj);613}614}615}616617j2d_ppdClose(ppd);618unlink(filename);619}620621622