1 #include <string.h> 2 #include <jni.h> 3 #include "org_clearsilver_HDF.h" 4 5 #include "cs_config.h" 6 #include "util/neo_err.h" 7 #include "util/neo_misc.h" 8 #include "util/neo_str.h" 9 #include "util/neo_hdf.h" 10 #include "cgi/cgi.h" 11 #include "cgi/cgiwrap.h" 12 #include "cgi/date.h" 13 #include "cgi/html.h" 14 15 #include "j_neo_util.h" 16 17 void throwException(JNIEnv *env, const char* class_name, const char *message) { 18 jclass ex_class = (*env)->FindClass(env, class_name); 19 if (ex_class == NULL) { 20 // Unable to find proper class! 21 return; 22 } 23 (*env)->ThrowNew(env, ex_class, message); 24 } 25 26 void throwNullPointerException(JNIEnv *env, const char *message) { 27 throwException(env, "java/lang/NullPointerException", message); 28 } 29 30 void throwRuntimeException(JNIEnv *env, const char *message) { 31 throwException(env, "java/lang/RuntimeException", message); 32 } 33 34 void throwIOException(JNIEnv *env, const char *message) { 35 throwException(env, "java/io/IOException", message); 36 } 37 38 void throwFileNotFoundException(JNIEnv *env, const char *message) { 39 throwException(env, "java/io/FileNotFoundException", message); 40 } 41 42 void throwOutOfMemoryError(JNIEnv *env, const char *message) { 43 throwException(env, "java/lang/OutOfMemoryError", message); 44 } 45 46 // Throws a runtime exception back to the Java VM appropriate for the type of 47 // error and frees the NEOERR that is passed in. 48 // TODO: throw more specific exceptions for errors like NERR_IO and NERR_NOMEM 49 int jNeoErr(JNIEnv *env, NEOERR *err) { 50 STRING str; 51 52 string_init(&str); 53 if (nerr_match(err, NERR_PARSE)) { 54 nerr_error_string(err, &str); 55 throwRuntimeException(env, str.buf); 56 } else if (nerr_match(err, NERR_IO)) { 57 nerr_error_string(err, &str); 58 throwIOException(env, str.buf); 59 } else if (nerr_match(err, NERR_NOMEM)) { 60 nerr_error_string(err, &str); 61 throwOutOfMemoryError(env, str.buf); 62 } else { 63 nerr_error_traceback(err, &str); 64 throwRuntimeException(env, str.buf); 65 } 66 67 nerr_ignore(&err); // free err, otherwise it would leak 68 string_clear(&str); 69 70 return 0; 71 } 72 73 JNIEXPORT jlong JNICALL Java_org_clearsilver_HDF__1init( 74 JNIEnv *env, jclass objClass) { 75 HDF *hdf = NULL; 76 NEOERR *err; 77 78 err = hdf_init(&hdf); 79 if (err != STATUS_OK) { 80 return jNeoErr(env, err); 81 } 82 return (jlong) hdf; 83 } 84 85 JNIEXPORT void JNICALL Java_org_clearsilver_HDF__1dealloc( 86 JNIEnv *env, jclass objClass, jlong hdf_obj_ptr) { 87 HDF *hdf = (HDF *)hdf_obj_ptr; 88 hdf_destroy(&hdf); 89 } 90 91 JNIEXPORT jint JNICALL Java_org_clearsilver_HDF__1getIntValue( 92 JNIEnv *env, jclass objClass, jlong hdf_obj_ptr, jstring j_hdfname, 93 jint default_value) { 94 HDF *hdf = (HDF *)hdf_obj_ptr; 95 int r; 96 const char *hdfname; 97 98 if (!j_hdfname) { 99 throwNullPointerException(env, "hdfname argument was null"); 100 return 0; 101 } 102 103 hdfname = (*env)->GetStringUTFChars(env,j_hdfname, 0); 104 105 r = hdf_get_int_value(hdf, hdfname, default_value); 106 107 (*env)->ReleaseStringUTFChars(env,j_hdfname,hdfname); 108 return r; 109 } 110 111 JNIEXPORT jstring JNICALL Java_org_clearsilver_HDF__1getValue( 112 JNIEnv *env, jclass objClass, jlong hdf_obj_ptr, jstring j_hdfname, 113 jstring j_default_value) { 114 HDF *hdf = (HDF *)hdf_obj_ptr; 115 const char *r; 116 const char *hdfname; 117 const char *default_value; 118 jstring retval; 119 120 if (!j_hdfname) { 121 throwNullPointerException(env, "hdfname argument was null"); 122 return 0; 123 } 124 hdfname = (*env)->GetStringUTFChars(env,j_hdfname,0); 125 if (!j_default_value) { 126 default_value = NULL; 127 } else { 128 default_value = (*env)->GetStringUTFChars(env, j_default_value, 0); 129 } 130 131 r = hdf_get_value(hdf, hdfname, default_value); 132 133 (*env)->ReleaseStringUTFChars(env, j_hdfname, hdfname); 134 retval = (r ? (*env)->NewStringUTF(env, r) : 0); 135 if (default_value) { 136 (*env)->ReleaseStringUTFChars(env, j_default_value, default_value); 137 } 138 return retval; 139 } 140 141 JNIEXPORT void JNICALL Java_org_clearsilver_HDF__1setValue( 142 JNIEnv *env, jclass objClass, 143 jlong hdf_obj_ptr, jstring j_hdfname, jstring j_value) { 144 HDF *hdf = (HDF *)hdf_obj_ptr; 145 NEOERR *err; 146 const char *hdfname; 147 const char *value; 148 149 if (!j_hdfname) { 150 throwNullPointerException(env, "hdfname argument was null"); 151 return; 152 } 153 hdfname = (*env)->GetStringUTFChars(env, j_hdfname, 0); 154 if (j_value) { 155 value = (*env)->GetStringUTFChars(env, j_value, 0); 156 } else { 157 value = NULL; 158 } 159 err = hdf_set_value(hdf, hdfname, value); 160 161 (*env)->ReleaseStringUTFChars(env, j_hdfname, hdfname); 162 if (value) { 163 (*env)->ReleaseStringUTFChars(env, j_value, value); 164 } 165 166 if (err != STATUS_OK) { 167 // Throw an exception 168 jNeoErr(env, err); 169 } 170 } 171 172 JNIEXPORT void JNICALL Java_org_clearsilver_HDF__1removeTree( 173 JNIEnv *env, jclass objClass, 174 jlong hdf_obj_ptr, jstring j_hdfname) { 175 HDF *hdf = (HDF *)hdf_obj_ptr; 176 NEOERR *err; 177 const char *hdfname; 178 179 if (!j_hdfname) { 180 throwNullPointerException(env, "hdfname argument was null"); 181 return; 182 } 183 hdfname = (*env)->GetStringUTFChars(env, j_hdfname, 0); 184 err = hdf_remove_tree(hdf, hdfname); 185 186 (*env)->ReleaseStringUTFChars(env, j_hdfname, hdfname); 187 188 if (err != STATUS_OK) { 189 // Throw an exception 190 jNeoErr(env, err); 191 } 192 } 193 194 JNIEXPORT void JNICALL Java_org_clearsilver_HDF__1setSymLink( 195 JNIEnv *env, jclass objClass, 196 jlong hdf_obj_ptr, jstring j_hdf_name_src, jstring j_hdf_name_dest) { 197 HDF *hdf = (HDF *)hdf_obj_ptr; 198 NEOERR *err; 199 const char *hdf_name_src; 200 const char *hdf_name_dest; 201 202 if (!j_hdf_name_src) { 203 throwNullPointerException(env, "hdf_name_src argument was null"); 204 return; 205 } 206 hdf_name_src = (*env)->GetStringUTFChars(env, j_hdf_name_src, 0); 207 208 if (!j_hdf_name_dest) { 209 throwNullPointerException(env, "hdf_name_dest argument was null"); 210 return; 211 } 212 hdf_name_dest = (*env)->GetStringUTFChars(env, j_hdf_name_dest, 0); 213 214 err = hdf_set_symlink(hdf, hdf_name_src, hdf_name_dest); 215 216 (*env)->ReleaseStringUTFChars(env, j_hdf_name_src, hdf_name_src); 217 (*env)->ReleaseStringUTFChars(env, j_hdf_name_dest, hdf_name_dest); 218 219 if (err != STATUS_OK) { 220 // Throw an exception 221 jNeoErr(env, err); 222 } 223 } 224 225 JNIEXPORT jstring JNICALL Java_org_clearsilver_HDF__1dump( 226 JNIEnv *env, jclass objClass, 227 jlong hdf_obj_ptr) { 228 HDF *hdf = (HDF *)hdf_obj_ptr; 229 NEOERR *err; 230 STRING str; 231 jstring retval; 232 233 string_init(&str); 234 err = hdf_dump_str(hdf, NULL, 0, &str); 235 if (err != STATUS_OK) { 236 // Throw an exception 237 jNeoErr(env, err); 238 retval = NULL; 239 } else { 240 retval = (*env)->NewStringUTF(env,str.buf); 241 } 242 string_clear(&str); 243 244 return retval; 245 } 246 247 NEOERR *jni_fileload_cb(void *ctx, HDF *hdf, const char *filename, 248 char **contents) { 249 FILELOAD_INFO *info = (FILELOAD_INFO *)ctx; 250 jstring filename_str; 251 jstring loaded_string; 252 const char *c_loaded_string; 253 254 // We assume that the hdf passed back is actually the hdf we already 255 // have... 256 if (hdf != info->hdf) 257 return nerr_raise(NERR_ASSERT, 258 "jni_fileload_cb: passed HDF pointer doesn't match hdf_obj_ptr"); 259 260 filename_str = (*info->env)->NewStringUTF(info->env, filename); 261 (*info->env)->NewLocalRef(info->env, filename_str); 262 263 loaded_string = (*info->env)->CallObjectMethod(info->env, info->fl_obj, 264 info->fl_method, filename_str); 265 if ((*info->env)->ExceptionCheck(info->env)) { 266 (*info->env)->ExceptionDescribe(info->env); 267 (*info->env)->ExceptionClear(info->env); 268 return nerr_raise(NERR_ASSERT, 269 "jni_fileload_cb: HDF.fileLoad returned exception, see STDERR"); 270 } 271 c_loaded_string = (*info->env)->GetStringUTFChars(info->env, loaded_string, 272 0); 273 if (c_loaded_string) { 274 *contents = strdup(c_loaded_string); 275 } 276 (*info->env)->ReleaseStringUTFChars(info->env, loaded_string, 277 c_loaded_string); 278 279 return STATUS_OK; 280 } 281 282 JNIEXPORT jboolean JNICALL Java_org_clearsilver_HDF__1readFile( 283 JNIEnv *env, jobject objClass, jlong hdf_obj_ptr, jstring j_filename, 284 jboolean use_cb) { 285 HDF *hdf = (HDF *)hdf_obj_ptr; 286 NEOERR *err; 287 const char *filename; 288 jboolean retval; 289 FILELOAD_INFO fl_info; 290 291 if (use_cb == JNI_TRUE) { 292 jclass hdfClass; 293 294 fl_info.env = env; 295 fl_info.fl_obj = objClass; 296 fl_info.hdf = hdf; 297 298 hdfClass = (*env)->GetObjectClass(env, objClass); 299 if (hdfClass == NULL) return JNI_FALSE; 300 301 fl_info.fl_method = (*env)->GetMethodID(env, hdfClass, 302 "fileLoad", "(Ljava/lang/String;)Ljava/lang/String;"); 303 if (fl_info.fl_method == NULL) return JNI_FALSE; 304 305 hdf_register_fileload(hdf, &fl_info, jni_fileload_cb); 306 } 307 308 filename = (*env)->GetStringUTFChars(env, j_filename, 0); 309 err = hdf_read_file(hdf, filename); 310 (*env)->ReleaseStringUTFChars(env, j_filename, filename); 311 if (use_cb == JNI_TRUE) hdf_register_fileload(hdf, NULL, NULL); 312 if (err != STATUS_OK) { 313 // Throw an exception. jNeoErr handles all types of errors other than 314 // NOT_FOUND, since that can mean different things in different contexts. 315 // In this context, it means "file not found". 316 if (nerr_match(err, NERR_NOT_FOUND)) { 317 STRING str; 318 string_init(&str); 319 nerr_error_string(err, &str); 320 throwFileNotFoundException(env, str.buf); 321 string_clear(&str); 322 } else { 323 jNeoErr(env, err); 324 } 325 } 326 retval = (err == STATUS_OK); 327 return retval; 328 } 329 330 JNIEXPORT jboolean JNICALL Java_org_clearsilver_HDF__1writeFile( 331 JNIEnv *env, jobject objClass, jlong hdf_obj_ptr, jstring j_filename) { 332 HDF *hdf = (HDF *)hdf_obj_ptr; 333 NEOERR *err; 334 const char *filename; 335 jboolean retval; 336 337 filename = (*env)->GetStringUTFChars(env, j_filename, 0); 338 err = hdf_write_file(hdf, filename); 339 (*env)->ReleaseStringUTFChars(env, j_filename, filename); 340 if (err != STATUS_OK) { 341 jNeoErr(env, err); 342 } 343 retval = (err == STATUS_OK); 344 return retval; 345 } 346 347 JNIEXPORT jboolean JNICALL Java_org_clearsilver_HDF__1writeFileAtomic( 348 JNIEnv *env, jobject objClass, jlong hdf_obj_ptr, jstring j_filename) { 349 HDF *hdf = (HDF *)hdf_obj_ptr; 350 NEOERR *err; 351 const char *filename; 352 jboolean retval; 353 354 filename = (*env)->GetStringUTFChars(env, j_filename, 0); 355 err = hdf_write_file_atomic(hdf, filename); 356 (*env)->ReleaseStringUTFChars(env, j_filename, filename); 357 if (err != STATUS_OK) { 358 jNeoErr(env, err); 359 } 360 retval = (err == STATUS_OK); 361 return retval; 362 } 363 364 JNIEXPORT jboolean JNICALL Java_org_clearsilver_HDF__1readString( 365 JNIEnv *env, jobject objClass, jlong hdf_obj_ptr, jstring j_data) { 366 HDF *hdf = (HDF *)hdf_obj_ptr; 367 NEOERR *err; 368 const char *data; 369 jboolean retval; 370 371 data = (*env)->GetStringUTFChars(env, j_data, 0); 372 err = hdf_read_string(hdf, data); 373 (*env)->ReleaseStringUTFChars(env, j_data, data); 374 if (err != STATUS_OK) { 375 jNeoErr(env, err); 376 } 377 retval = (err == STATUS_OK); 378 return retval; 379 } 380 381 JNIEXPORT jstring JNICALL Java_org_clearsilver_HDF__1writeString( 382 JNIEnv *env, jclass objClass, jlong hdf_obj_ptr) { 383 HDF *hdf = (HDF *)hdf_obj_ptr; 384 NEOERR *err; 385 char *output = NULL; 386 jstring retval = NULL; 387 388 err = hdf_write_string(hdf, &output); 389 if (err != STATUS_OK) { 390 jNeoErr(env, err); 391 } else if (output) { 392 retval = (*env)->NewStringUTF(env, output); 393 free(output); 394 } 395 return retval; 396 } 397 398 JNIEXPORT jlong JNICALL Java_org_clearsilver_HDF__1getObj( 399 JNIEnv *env, jclass objClass, jlong hdf_obj_ptr, jstring j_hdf_path) { 400 HDF *hdf = (HDF *)hdf_obj_ptr; 401 HDF *obj_hdf = NULL; 402 const char *hdf_path; 403 404 hdf_path = (*env)->GetStringUTFChars(env, j_hdf_path, 0); 405 obj_hdf = hdf_get_obj(hdf, (char*)hdf_path); 406 (*env)->ReleaseStringUTFChars(env, j_hdf_path, hdf_path); 407 return (jlong)obj_hdf; 408 } 409 410 JNIEXPORT jlong JNICALL Java_org_clearsilver_HDF__1getChild( 411 JNIEnv *env, jclass objClass, jlong hdf_obj_ptr, jstring j_hdf_path) { 412 HDF *hdf = (HDF *)hdf_obj_ptr; 413 HDF *obj_hdf = NULL; 414 const char *hdf_path; 415 416 hdf_path = (*env)->GetStringUTFChars(env, j_hdf_path, 0); 417 obj_hdf = hdf_get_child(hdf, (char*)hdf_path); 418 (*env)->ReleaseStringUTFChars(env, j_hdf_path, hdf_path); 419 return (jlong)obj_hdf; 420 } 421 422 JNIEXPORT jlong JNICALL Java_org_clearsilver_HDF__1objChild( 423 JNIEnv *env, jclass objClass, jlong hdf_obj_ptr) { 424 HDF *hdf = (HDF *)hdf_obj_ptr; 425 HDF *child_hdf = NULL; 426 427 child_hdf = hdf_obj_child(hdf); 428 return (jlong)child_hdf; 429 } 430 431 JNIEXPORT jlong JNICALL Java_org_clearsilver_HDF__1objNext( 432 JNIEnv *env, jclass objClass, jlong hdf_obj_ptr) { 433 HDF *hdf = (HDF *)hdf_obj_ptr; 434 HDF *next_hdf = NULL; 435 436 next_hdf = hdf_obj_next(hdf); 437 return (jlong)next_hdf; 438 } 439 440 JNIEXPORT jstring JNICALL Java_org_clearsilver_HDF__1objName( 441 JNIEnv *env, jclass objClass, jlong hdf_obj_ptr) { 442 HDF *hdf = (HDF *)hdf_obj_ptr; 443 char *name; 444 jstring retval = NULL; 445 446 name = hdf_obj_name(hdf); 447 if (name != NULL) { 448 retval = (*env)->NewStringUTF(env, name); 449 } 450 return retval; 451 } 452 453 JNIEXPORT jstring JNICALL Java_org_clearsilver_HDF__1objValue( 454 JNIEnv *env, jclass objClass, jlong hdf_obj_ptr) { 455 HDF *hdf = (HDF *)hdf_obj_ptr; 456 char *name; 457 jstring retval = NULL; 458 459 name = hdf_obj_value(hdf); 460 if (name != NULL) { 461 retval = (*env)->NewStringUTF(env, name); 462 } 463 return retval; 464 } 465 466 JNIEXPORT void JNICALL Java_org_clearsilver_HDF__1copy 467 (JNIEnv *env, jclass objClass, jlong hdf_dest_ptr, jstring j_hdf_path, 468 jlong hdf_src_ptr) { 469 HDF *dest = (HDF *)hdf_dest_ptr; 470 HDF *src = (HDF *)hdf_src_ptr; 471 const char *hdf_path; 472 473 hdf_path = (*env)->GetStringUTFChars(env, j_hdf_path, 0); 474 hdf_copy(dest, hdf_path, src); 475 (*env)->ReleaseStringUTFChars(env, j_hdf_path, hdf_path); 476 } 477 478