1/* sane - Scanner Access Now Easy. 2 Copyright (C) 1997 Jeffrey S. Freedman 3 This file is part of the SANE package. 4 5 This program is free software; you can redistribute it and/or 6 modify it under the terms of the GNU General Public License as 7 published by the Free Software Foundation; either version 2 of the 8 License, or (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, but 11 WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program. If not, see <https://www.gnu.org/licenses/>. 17 18 As a special exception, the authors of SANE give permission for 19 additional uses of the libraries contained in this release of SANE. 20 21 The exception is that, if you link a SANE library with other files 22 to produce an executable, this does not by itself cause the 23 resulting executable to be covered by the GNU General Public 24 License. Your use of that executable is in no way restricted on 25 account of linking the SANE library code into it. 26 27 This exception does not, however, invalidate any other reasons why 28 the executable file might be covered by the GNU General Public 29 License. 30 31 If you submit changes to SANE to the maintainers to be included in 32 a subsequent release, you agree by submitting the changes that 33 those changes may be distributed with this exception intact. 34 35 If you write modifications of your own for SANE, it is your choice 36 whether to permit this exception to apply to your modifications. 37 If you do not wish that, delete this exception notice. */ 38 39/** 40 ** Sane.c - Native methods for the SANE Java API. 41 ** 42 ** Written: 10/9/97 - JSF 43 **/ 44 45#include "Sane.h" 46#include <sane/sane.h> 47#include <string.h> 48 49#include <stdio.h> /* Debugging */ 50 51#ifdef __cplusplus 52extern "C" { 53#endif 54/* 55 * Class: Sane 56 * Method: init 57 * Signature: ([I)I 58 */ 59JNIEXPORT jint JNICALL Java_Sane_init 60 (JNIEnv *env, jobject jobj, jintArray versionCode) 61 { 62 jsize len; /* Gets array length. */ 63 jint *versionCodeBody; /* Gets ->array. */ 64 SANE_Int version; /* Gets version. */ 65 SANE_Status status; /* Get SANE return. */ 66 67 status = sane_init(&version, 0); 68 len = (*env)->GetArrayLength(env, versionCode); 69 versionCodeBody = (*env)->GetIntArrayElements(env, versionCode, 0); 70 if (len > 0) /* Return version. */ 71 versionCodeBody[0] = version; 72 (*env)->ReleaseIntArrayElements(env, versionCode, versionCodeBody, 0); 73 return (status); 74 } 75/* 76 * Class: Sane 77 * Method: exit 78 * Signature: ()V 79 */ 80JNIEXPORT void JNICALL Java_Sane_exit 81 (JNIEnv *env, jobject jobj) 82 { 83 sane_exit(); 84 } 85 86 87/* 88 * Class: Sane 89 * Method: getDevices 90 * Signature: ([LSaneDevice;Z)I 91 */ 92JNIEXPORT jint JNICALL Java_Sane_getDevicesNative 93 (JNIEnv *env, jobject jobj, jobjectArray devList, jboolean localOnly) 94 { 95 /* Gets device list. */ 96 const SANE_Device **device_list; 97 SANE_Status status; /* Gets status. */ 98 int devListLen; /* Gets length of devList. */ 99 jobject devObj; /* Gets each SaneDevice object. */ 100 jclass devClass; /* Gets SaneDevice class. */ 101 jfieldID fid; /* Gets each field ID. */ 102 int i; 103 104 /* Get the list. */ 105 status = sane_get_devices(&device_list, localOnly); 106 if (status != SANE_STATUS_GOOD) 107 return (status); 108 /* Get length of Java array. */ 109 devListLen = (*env)->GetArrayLength(env, devList); 110 /* Return devices to user. */ 111 for (i = 0; i < devListLen - 1 && device_list[i]; i++) 112 { 113 /* Get Java object, class. */ 114 devObj = (*env)->GetObjectArrayElement(env, devList, i); 115 devClass = (*env)->GetObjectClass(env, devObj); 116 /* Fill in each member. */ 117 fid = (*env)->GetFieldID(env, devClass, "name", 118 "Ljava/lang/String;"); 119 (*env)->SetObjectField(env, devObj, fid, 120 (*env)->NewStringUTF(env, device_list[i]->name)); 121 fid = (*env)->GetFieldID(env, devClass, "vendor", 122 "Ljava/lang/String;"); 123 (*env)->SetObjectField(env, devObj, fid, 124 (*env)->NewStringUTF(env, device_list[i]->vendor)); 125 fid = (*env)->GetFieldID(env, devClass, "model", 126 "Ljava/lang/String;"); 127 (*env)->SetObjectField(env, devObj, fid, 128 (*env)->NewStringUTF(env, device_list[i]->model)); 129 fid = (*env)->GetFieldID(env, devClass, "type", 130 "Ljava/lang/String;"); 131 (*env)->SetObjectField(env, devObj, fid, 132 (*env)->NewStringUTF(env, device_list[i]->type)); 133 } 134 /* End list with a null. */ 135 (*env)->SetObjectArrayElement(env, devList, i, 0); 136 return (status); 137 } 138 139/* 140 * Class: Sane 141 * Method: open 142 * Signature: (Ljava/lang/String;[J)I 143 */ 144JNIEXPORT jint JNICALL Java_Sane_open 145 (JNIEnv *env, jobject jobj, jstring deviceName, jintArray handle) 146 { 147 SANE_Handle sane_handle; /* Gets handle. */ 148 jint s_handle; 149 const char *device_name; /* Gets dev. name. */ 150 int status; /* Gets return code. */ 151 152 device_name = (*env)->GetStringUTFChars(env, deviceName, 0); 153 /* Open it. */ 154 status = sane_open(device_name, &sane_handle); 155 (*env)->ReleaseStringUTFChars(env, deviceName, device_name); 156 /* Return handle. */ 157 s_handle = (jint) sane_handle; 158 (*env)->SetIntArrayRegion(env, handle, 0, 1, &s_handle); 159 return (status); 160 } 161 162/* 163 * Class: Sane 164 * Method: close 165 * Signature: (J)V 166 */ 167JNIEXPORT void JNICALL Java_Sane_close 168 (JNIEnv *env, jobject jobj, jint handle) 169 { 170 sane_close((SANE_Handle) handle); 171 } 172 173/* 174 * Class: Sane 175 * Method: getOptionNative 176 * Signature: (IILSaneOption;)V 177 */ 178JNIEXPORT void JNICALL Java_Sane_getOptionNative 179 (JNIEnv *env, jobject jobj, jint handle, jint option, jobject optObj) 180 { 181 jclass optClass; /* Gets its class. */ 182 jfieldID fid; /* Gets each field ID. */ 183 jstring str; /* Gets strings. */ 184 185 /* Get info from sane. */ 186 const SANE_Option_Descriptor *sopt = sane_get_option_descriptor( 187 (SANE_Handle) handle, option); 188 /* Get class info. */ 189 optClass = (*env)->GetObjectClass(env, optObj); 190 /* Fill in each member. */ 191 fid = (*env)->GetFieldID(env, optClass, "name", "Ljava/lang/String;"); 192 if (!sopt) /* Failed. */ 193 { /* Set name to null. */ 194 (*env)->SetObjectField(env, optObj, fid, 0); 195 return; 196 } 197 /* Return name. */ 198 (*env)->SetObjectField(env, optObj, fid, 199 (*env)->NewStringUTF(env, sopt->name)); 200 /* Return title. */ 201 fid = (*env)->GetFieldID(env, optClass, "title", "Ljava/lang/String;"); 202 str = sopt->title ? (*env)->NewStringUTF(env, sopt->title) : 0; 203 (*env)->SetObjectField(env, optObj, fid, str); 204 /* Return descr. */ 205 fid = (*env)->GetFieldID(env, optClass, "desc", "Ljava/lang/String;"); 206 (*env)->SetObjectField(env, optObj, fid, 207 (*env)->NewStringUTF(env, sopt->desc)); 208 /* Return type. */ 209 fid = (*env)->GetFieldID(env, optClass, "type", "I"); 210 (*env)->SetIntField(env, optObj, fid, sopt->type); 211 /* Return unit. */ 212 fid = (*env)->GetFieldID(env, optClass, "unit", "I"); 213 (*env)->SetIntField(env, optObj, fid, sopt->unit); 214 /* Return size. */ 215 fid = (*env)->GetFieldID(env, optClass, "size", "I"); 216 (*env)->SetIntField(env, optObj, fid, sopt->size); 217 /* Return cap. */ 218 fid = (*env)->GetFieldID(env, optClass, "cap", "I"); 219 (*env)->SetIntField(env, optObj, fid, sopt->cap); 220 /* Return constraint_type. */ 221 fid = (*env)->GetFieldID(env, optClass, "constraintType", "I"); 222 (*env)->SetIntField(env, optObj, fid, sopt->constraint_type); 223 /* 224 * Now for the constraint itself. 225 */ 226 if (sopt->constraint_type == SANE_CONSTRAINT_RANGE) 227 { 228 /* Create range object. */ 229 jclass rangeClass = (*env)->FindClass(env, "SaneRange"); 230 jobject range = (*env)->AllocObject(env, rangeClass); 231 /* Fill in fields. */ 232 fid = (*env)->GetFieldID(env, rangeClass, "min", "I"); 233 (*env)->SetIntField(env, range, fid, 234 sopt->constraint.range->min); 235 fid = (*env)->GetFieldID(env, rangeClass, "max", "I"); 236 (*env)->SetIntField(env, range, fid, 237 sopt->constraint.range->max); 238 fid = (*env)->GetFieldID(env, rangeClass, "quant", "I"); 239 (*env)->SetIntField(env, range, fid, 240 sopt->constraint.range->quant); 241 fid = (*env)->GetFieldID(env, optClass, "rangeConstraint", 242 "LSaneRange;"); 243 /* Store range. */ 244 (*env)->SetObjectField(env, optObj, fid, range); 245 } 246 else if (sopt->constraint_type == SANE_CONSTRAINT_WORD_LIST) 247 { /* Get array of integers. */ 248 jintArray wordList; 249 jint *elements; 250 int i; 251 /* First word. is the length. */ 252 wordList = (*env)->NewIntArray(env, 253 sopt->constraint.word_list[0]); 254 /* Copy in the integers. */ 255 elements = (*env)->GetIntArrayElements(env, wordList, 0); 256 for (i = 0; i < sopt->constraint.word_list[0]; i++) 257 elements[i] = sopt->constraint.word_list[i]; 258 (*env)->ReleaseIntArrayElements(env, wordList, elements, 0); 259 /* Set the field. */ 260 fid = (*env)->GetFieldID(env, optClass, "wordListConstraint", 261 "[I"); 262 (*env)->SetObjectField(env, optObj, fid, wordList); 263 } 264 else if (sopt->constraint_type == SANE_CONSTRAINT_STRING_LIST) 265 { 266 jclass stringClass = (*env)->FindClass(env, "java/lang/String"); 267 jobjectArray stringList; 268 int len; /* Gets # elements */ 269 int i; 270 271 for (len = 0; sopt->constraint.string_list[len]; len++) 272 ; 273 stringList = (*env)->NewObjectArray(env, len + 1, 274 stringClass, 0); 275 /* Add each string. */ 276 for (i = 0; i < len; i++) 277 { 278 (*env)->SetObjectArrayElement(env, stringList, i, 279 (*env)->NewStringUTF(env, 280 sopt->constraint.string_list[i])); 281 } 282 /* 0 at end. */ 283 (*env)->SetObjectArrayElement(env, stringList, len, 0); 284 /* Set the field. */ 285 fid = (*env)->GetFieldID(env, optClass, 286 "stringListConstraint", "[Ljava/lang/String;"); 287 (*env)->SetObjectField(env, optObj, fid, stringList); 288 } 289 } 290 291/* 292 * Class: Sane 293 * Method: getControlOption 294 * Signature: (II[I[I)I 295 */ 296JNIEXPORT jint JNICALL Java_Sane_getControlOption__II_3I_3I 297 (JNIEnv *env, jobject jobj, jint handle, jint option, jintArray value, 298 jintArray info) 299 { 300 SANE_Status status; /* Gets status. */ 301 SANE_Int i; /* Gets info. passed back. */ 302 int v; 303 304 status = sane_control_option((SANE_Handle) handle, option, 305 SANE_ACTION_GET_VALUE, &v, &i); 306 if (value) 307 (*env)->SetIntArrayRegion(env, value, 0, 1, &v); 308 if (info) 309 (*env)->SetIntArrayRegion(env, info, 0, 1, &i); 310 return (status); 311 } 312 313/* 314 * Class: Sane 315 * Method: getControlOption 316 * Signature: (II[B[I)I 317 */ 318JNIEXPORT jint JNICALL Java_Sane_getControlOption__II_3B_3I 319 (JNIEnv *env, jobject jobj, jint handle, jint option, jbyteArray value, 320 jintArray info) 321 { 322 SANE_Status status; /* Gets status. */ 323 SANE_Int i; /* Gets info. passed back. */ 324 char *str; 325 326 str = (*env)->GetByteArrayElements(env, value, 0); 327 status = sane_control_option((SANE_Handle) handle, option, 328 SANE_ACTION_GET_VALUE, str, &i); 329 (*env)->ReleaseByteArrayElements(env, value, str, 0); 330 if (info) 331 (*env)->SetIntArrayRegion(env, info, 0, 1, &i); 332 return (status); 333 } 334 335/* 336 * Class: Sane 337 * Method: setControlOption 338 * Signature: (IIII[I)I 339 */ 340JNIEXPORT jint JNICALL Java_Sane_setControlOption__IIII_3I 341 (JNIEnv *env, jobject jobj, jint handle, jint option, jint action, 342 jint value, jintArray info) 343 { 344 SANE_Status status; /* Gets status. */ 345 SANE_Int i; /* Gets info. passed back. */ 346 status = sane_control_option((SANE_Handle) handle, option, action, 347 &value, &i); 348 if (info) 349 (*env)->SetIntArrayRegion(env, info, 0, 1, &i); 350 return (status); 351 } 352 353/* 354 * Get string length. This exists because sometimes strings seem to be 355 * padded with negatives. 356 */ 357 358static int String_length 359 ( 360 const char *str 361 ) 362 { 363 const char *ptr; 364 for (ptr = str; *ptr > 0; ptr++) 365 ; 366 return ((int) (ptr - str)); 367 } 368 369/* 370 * Class: Sane 371 * Method: setControlOption 372 * Signature: (IIILjava/lang/String;[I)I 373 */ 374JNIEXPORT jint JNICALL Java_Sane_setControlOption__IIILjava_lang_String_2_3I 375 (JNIEnv *env, jobject jobj, jint handle, jint option, jint action, 376 jstring value, jintArray info) 377 { 378 SANE_Status status; /* Gets status. */ 379 SANE_Int i; /* Gets info. passed back. */ 380 const char *valuep; 381 char buf[512]; /* Hope this is big enough. */ 382 int len; /* Gets string length. */ 383 384 valuep = (*env)->GetStringUTFChars(env, value, 0); 385 len = String_length(valuep); 386 if (len >= sizeof(buf)) 387 len = sizeof(buf) - 1; 388 strncpy(buf, valuep, len); 389 buf[len] = 0; /* Insure it's 0-delimited. */ 390 status = sane_control_option((SANE_Handle) handle, option, action, 391 (void *) &buf[0], &i); 392 /* +++++++Want to return new val? */ 393 (*env)->ReleaseStringUTFChars(env, value, valuep); 394 if (info) 395 (*env)->SetIntArrayRegion(env, info, 0, 1, &i); 396 return (status); 397 } 398 399/* 400 * Class: Sane 401 * Method: getParameters 402 * Signature: (ILSaneParameters;)I 403 */ 404JNIEXPORT jint JNICALL Java_Sane_getParameters 405 (JNIEnv *env, jobject jobj, jint handle, jobject paramsObj) 406 { 407 SANE_Status status; /* Gets status. */ 408 SANE_Parameters params; /* Gets params. */ 409 jclass paramsClass; /* Gets its class. */ 410 jfieldID fid; /* Gets each field ID. */ 411 412 status = sane_get_parameters((SANE_Handle) handle, ¶ms); 413 /* Get class info. */ 414 paramsClass = (*env)->GetObjectClass(env, paramsObj); 415 /* Fill in each member. */ 416 fid = (*env)->GetFieldID(env, paramsClass, "format", "I"); 417 (*env)->SetIntField(env, paramsObj, fid, params.format); 418 fid = (*env)->GetFieldID(env, paramsClass, "lastFrame", "Z"); 419 (*env)->SetBooleanField(env, paramsObj, fid, params.last_frame); 420 fid = (*env)->GetFieldID(env, paramsClass, "bytesPerLine", "I"); 421 (*env)->SetIntField(env, paramsObj, fid, params.bytes_per_line); 422 fid = (*env)->GetFieldID(env, paramsClass, "pixelsPerLine", "I"); 423 (*env)->SetIntField(env, paramsObj, fid, params.pixels_per_line); 424 fid = (*env)->GetFieldID(env, paramsClass, "lines", "I"); 425 (*env)->SetIntField(env, paramsObj, fid, params.lines); 426 fid = (*env)->GetFieldID(env, paramsClass, "depth", "I"); 427 (*env)->SetIntField(env, paramsObj, fid, params.depth); 428 return (status); 429 } 430 431/* 432 * Class: Sane 433 * Method: start 434 * Signature: (I)I 435 */ 436JNIEXPORT jint JNICALL Java_Sane_start 437 (JNIEnv *env, jobject jobj, jint handle) 438 { 439 return (sane_start((SANE_Handle) handle)); 440 } 441 442/* 443 * Class: Sane 444 * Method: read 445 * Signature: (I[BI[I)I 446 */ 447JNIEXPORT jint JNICALL Java_Sane_read 448 (JNIEnv *env, jobject jobj, jint handle, jbyteArray data, jint maxLength, 449 jintArray length) 450 { 451 int status; 452 jbyte *dataElements; 453 int read_len; /* # bytes read. */ 454 455 /* Get actual data ptr. */ 456 dataElements = (*env)->GetByteArrayElements(env, data, 0); 457 /* Do the read. */ 458 status = sane_read((SANE_Handle) handle, dataElements, 459 maxLength, &read_len); 460 (*env)->ReleaseByteArrayElements(env, data, dataElements, 0); 461 /* Return # bytes read. */ 462 (*env)->SetIntArrayRegion(env, length, 0, 1, &read_len); 463 return (status); 464 } 465 466/* 467 * Class: Sane 468 * Method: cancel 469 * Signature: (I)V 470 */ 471JNIEXPORT void JNICALL Java_Sane_cancel 472 (JNIEnv *env, jobject jobj, jint handle) 473 { 474 sane_cancel((SANE_Handle) handle); 475 } 476 477/* 478 * Class: Sane 479 * Method: strstatus 480 * Signature: (I)Ljava/lang/String; 481 */ 482JNIEXPORT jstring JNICALL Java_Sane_strstatus 483 (JNIEnv *env, jobject jobj, jint status) 484 { 485 const char *str = sane_strstatus(status); 486 return ((*env)->NewStringUTF(env, str)); 487 } 488 489#ifdef __cplusplus 490} 491#endif 492