1 /* 2 * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #include <string.h> 27 28 #include "jni.h" 29 #include "jni_util.h" 30 #include "jdk_util.h" 31 #include "endian.hpp" 32 #include "imageDecompressor.hpp" 33 #include "imageFile.hpp" 34 #include "inttypes.hpp" 35 #include "jimage.hpp" 36 #include "osSupport.hpp" 37 38 #include "jdk_internal_jimage_ImageNativeSubstrate.h" 39 40 extern bool MemoryMapImage; 41 42 // jdk.internal.jimage ///////////////////////////////////////////////////////// 43 44 // Java entry to open an image file for sharing. 45 46 static jlong JIMAGE_Open(JNIEnv *env, const char *nativePath, jboolean big_endian) { 47 // Open image file for reading. 48 ImageFileReader* reader = ImageFileReader::open(nativePath, big_endian != JNI_FALSE); 49 // Return image ID as a jlong. 50 return ImageFileReader::readerToID(reader); 51 } 52 53 // Java entry for closing a shared image file. 54 55 static void JIMAGE_Close(JNIEnv *env, jlong id) { 56 // Convert image ID to image reader structure. 57 ImageFileReader* reader = ImageFileReader::idToReader(id); 58 // If valid reader the close. 59 if (reader != NULL) { 60 ImageFileReader::close(reader); 61 } 62 } 63 64 // Java entry for accessing the base address of the image index. 65 66 static jlong JIMAGE_GetIndexAddress(JNIEnv *env, jlong id) { 67 // Convert image ID to image reader structure. 68 ImageFileReader* reader = ImageFileReader::idToReader(id); 69 // If valid reader return index base address (as jlong) else zero. 70 return reader != NULL ? (jlong) reader->get_index_address() : 0L; 71 } 72 73 // Java entry for accessing the base address of the image data. 74 75 static jlong JIMAGE_GetDataAddress(JNIEnv *env, jlong id) { 76 // Convert image ID to image reader structure. 77 ImageFileReader* reader = ImageFileReader::idToReader(id); 78 // If valid reader return data base address (as jlong) else zero. 79 return MemoryMapImage && reader != NULL ? (jlong) reader->get_data_address() : 0L; 80 } 81 82 // Java entry for reading an uncompressed resource from the image. 83 84 static jboolean JIMAGE_Read(JNIEnv *env, jlong id, jlong offset, 85 unsigned char* uncompressedAddress, jlong uncompressed_size) { 86 // Convert image ID to image reader structure. 87 ImageFileReader* reader = ImageFileReader::idToReader(id);\ 88 // If not a valid reader the fail the read. 89 if (reader == NULL) return false; 90 // Get the file offset of resource data. 91 u8 file_offset = reader->get_index_size() + offset; 92 // Check validity of arguments. 93 if (offset < 0 || 94 uncompressed_size < 0 || 95 file_offset > reader->file_size() - uncompressed_size) { 96 return false; 97 } 98 // Read file content into buffer. 99 return (jboolean) reader->read_at((u1*) uncompressedAddress, uncompressed_size, 100 file_offset); 101 } 102 103 // Java entry for reading a compressed resource from the image. 104 105 static jboolean JIMAGE_ReadCompressed(JNIEnv *env, 106 jlong id, jlong offset, 107 unsigned char* compressedAddress, jlong compressed_size, 108 unsigned char* uncompressedAddress, jlong uncompressed_size) { 109 // Convert image ID to image reader structure. 110 ImageFileReader* reader = ImageFileReader::idToReader(id); 111 // If not a valid reader the fail the read. 112 if (reader == NULL) return false; 113 // Get the file offset of resource data. 114 u8 file_offset = reader->get_index_size() + offset; 115 // Check validity of arguments. 116 if (offset < 0 || 117 compressed_size < 0 || 118 uncompressed_size < 0 || 119 file_offset > reader->file_size() - compressed_size) { 120 return false; 121 } 122 123 // Read file content into buffer. 124 bool is_read = reader->read_at(compressedAddress, compressed_size, 125 file_offset); 126 // If successfully read then decompress. 127 if (is_read) { 128 const ImageStrings strings = reader->get_strings(); 129 ImageDecompressor::decompress_resource(compressedAddress, uncompressedAddress, 130 (u4) uncompressed_size, &strings); 131 } 132 return (jboolean) is_read; 133 } 134 135 // Java entry for retrieving UTF-8 bytes from image string table. 136 137 static const char* JIMAGE_GetStringBytes(JNIEnv *env, jlong id, jint offset) { 138 // Convert image ID to image reader structure. 139 ImageFileReader* reader = ImageFileReader::idToReader(id); 140 // Fail if not valid reader. 141 if (reader == NULL) return NULL; 142 // Manage image string table. 143 ImageStrings strings = reader->get_strings(); 144 // Retrieve string adrress from table. 145 const char* data = strings.get(offset); 146 return data; 147 } 148 149 // Utility function to copy location information into a jlong array. 150 // WARNING: This function is experimental and temporary during JDK 9 development 151 // cycle. It will not be supported in the eventual JDK 9 release. 152 153 static void image_expand_location(JNIEnv *env, jlong* rawAttributes, ImageLocation& location) { 154 // Copy attributes from location. 155 for (int kind = ImageLocation::ATTRIBUTE_END + 1; 156 kind < ImageLocation::ATTRIBUTE_COUNT; 157 kind++) { 158 rawAttributes[kind] = location.get_attribute(kind); 159 } 160 } 161 162 // Java entry for retrieving location attributes for attribute offset. 163 164 static jlong* JIMAGE_GetAttributes(JNIEnv *env, jlong* rawAttributes, jlong id, jint offset) { 165 // Convert image ID to image reader structure. 166 ImageFileReader* reader = ImageFileReader::idToReader(id); 167 // Fail if not valid reader. 168 if (reader == NULL) return NULL; 169 // Retrieve first byte address of resource's location attribute stream. 170 u1* data = reader->get_location_offset_data(offset); 171 // Fail if not valid offset. 172 if (data == NULL) return NULL; 173 // Expand stream into array. 174 ImageLocation location(data); 175 image_expand_location(env, rawAttributes, location); 176 return rawAttributes; 177 } 178 179 // Java entry for retrieving location attributes count for attribute offset. 180 181 static jsize JIMAGE_GetAttributesCount(JNIEnv *env) { 182 return ImageLocation::ATTRIBUTE_COUNT; 183 } 184 185 // Java entry for retrieving location attributes for named resource. 186 187 static jlong* JIMAGE_FindAttributes(JNIEnv *env, jlong* rawAttributes, jbyte* rawBytes, jsize size, jlong id) { 188 // Convert image ID to image reader structure. 189 ImageFileReader* reader = ImageFileReader::idToReader(id); 190 // Fail if not valid reader. 191 if (reader == NULL) return NULL; 192 // Convert byte array to a cstring. 193 char* path = new char[size + 1]; 194 memcpy(path, rawBytes, size); 195 path[size] = '\0'; 196 // Locate resource location data. 197 ImageLocation location; 198 bool found = reader->find_location(path, location); 199 delete path; 200 // Resource not found. 201 if (!found) return NULL; 202 // Expand stream into array. 203 image_expand_location(env, rawAttributes, location); 204 return rawAttributes; 205 } 206 207 // Java entry for retrieving all the attribute stream offsets from an image. 208 209 static jint* JIMAGE_AttributeOffsets(JNIEnv *env, jint* rawOffsets, unsigned int length, jlong id) { 210 // Convert image ID to image reader structure. 211 ImageFileReader* reader = ImageFileReader::idToReader(id); 212 // Fail if not valid reader. 213 if (reader == NULL) return NULL; 214 // Determine endian for reader. 215 Endian* endian = reader->endian(); 216 // Get base address of attribute stream offsets table. 217 u4* offsets_table = reader->offsets_table(); 218 // Allocate int array result. 219 // Copy values to result (converting endian.) 220 for (u4 i = 0; i < length; i++) { 221 rawOffsets[i] = endian->get(offsets_table[i]); 222 } 223 return rawOffsets; 224 } 225 226 // Java entry for retrieving all the attribute stream offsets length from an image. 227 228 static unsigned int JIMAGE_AttributeOffsetsLength(JNIEnv *env, jlong id) { 229 // Convert image ID to image reader structure. 230 ImageFileReader* reader = ImageFileReader::idToReader(id); 231 // Fail if not valid reader. 232 if (reader == NULL) return 0; 233 // Get perfect hash table length. 234 u4 length = reader->table_length(); 235 return (jint) length; 236 } 237 238 JNIEXPORT jint JNICALL 239 DEF_JNI_OnLoad(JavaVM *vm, void *reserved) { 240 JNIEnv *env; 241 242 if (vm->GetEnv((void**) &env, JNI_VERSION_1_2) != JNI_OK) { 243 return JNI_EVERSION; /* JNI version not supported */ 244 } 245 246 return JNI_VERSION_1_2; 247 } 248 249 JNIEXPORT jlong JNICALL 250 Java_jdk_internal_jimage_ImageNativeSubstrate_openImage(JNIEnv *env, 251 jclass cls, jstring path, jboolean big_endian) { 252 const char *nativePath; 253 jlong ret; 254 255 nativePath = env->GetStringUTFChars(path, NULL); 256 ret = JIMAGE_Open(env, nativePath, big_endian); 257 env->ReleaseStringUTFChars(path, nativePath); 258 return ret; 259 } 260 261 JNIEXPORT void JNICALL 262 Java_jdk_internal_jimage_ImageNativeSubstrate_closeImage(JNIEnv *env, 263 jclass cls, jlong id) { 264 JIMAGE_Close(env, id); 265 } 266 267 JNIEXPORT jlong JNICALL 268 Java_jdk_internal_jimage_ImageNativeSubstrate_getIndexAddress(JNIEnv *env, 269 jclass cls, jlong id) { 270 return JIMAGE_GetIndexAddress(env, id); 271 } 272 273 JNIEXPORT jlong JNICALL 274 Java_jdk_internal_jimage_ImageNativeSubstrate_getDataAddress(JNIEnv *env, 275 jclass cls, jlong id) { 276 return JIMAGE_GetDataAddress(env, id); 277 } 278 279 JNIEXPORT jboolean JNICALL 280 Java_jdk_internal_jimage_ImageNativeSubstrate_read(JNIEnv *env, 281 jclass cls, jlong id, jlong offset, 282 jobject uncompressedBuffer, jlong uncompressed_size) { 283 unsigned char* uncompressedAddress; 284 285 uncompressedAddress = (unsigned char*) env->GetDirectBufferAddress(uncompressedBuffer); 286 if (uncompressedAddress == NULL) { 287 return JNI_FALSE; 288 } 289 return JIMAGE_Read(env, id, offset, uncompressedAddress, uncompressed_size); 290 } 291 292 JNIEXPORT jboolean JNICALL 293 Java_jdk_internal_jimage_ImageNativeSubstrate_readCompressed(JNIEnv *env, 294 jclass cls, jlong id, jlong offset, 295 jobject compressedBuffer, jlong compressed_size, 296 jobject uncompressedBuffer, jlong uncompressed_size) { 297 // Get address of read direct buffer. 298 unsigned char* compressedAddress; 299 unsigned char* uncompressedAddress; 300 301 compressedAddress = (unsigned char*) env->GetDirectBufferAddress(compressedBuffer); 302 // Get address of decompression direct buffer. 303 uncompressedAddress = (unsigned char*) env->GetDirectBufferAddress(uncompressedBuffer); 304 if (compressedAddress == NULL || uncompressedAddress == NULL) { 305 return JNI_FALSE; 306 } 307 return JIMAGE_ReadCompressed(env, id, offset, compressedAddress, compressed_size, 308 uncompressedAddress, uncompressed_size); 309 } 310 311 JNIEXPORT jbyteArray JNICALL 312 Java_jdk_internal_jimage_ImageNativeSubstrate_getStringBytes(JNIEnv *env, 313 jclass cls, jlong id, jint offset) { 314 const char* data; 315 size_t size; 316 jbyteArray byteArray; 317 jbyte* rawBytes; 318 319 data = JIMAGE_GetStringBytes(env, id, offset); 320 // Determine String length. 321 size = strlen(data); 322 // Allocate byte array. 323 byteArray = env->NewByteArray((jsize) size); 324 if (byteArray == NULL) { 325 return NULL; 326 } 327 // Get array base address. 328 rawBytes = env->GetByteArrayElements(byteArray, NULL); 329 // Copy bytes from image string table. 330 memcpy(rawBytes, data, size); 331 // Release byte array base address. 332 env->ReleaseByteArrayElements(byteArray, rawBytes, 0); 333 return byteArray; 334 } 335 336 JNIEXPORT jlongArray JNICALL 337 Java_jdk_internal_jimage_ImageNativeSubstrate_getAttributes(JNIEnv *env, 338 jclass cls, jlong id, jint offset) { 339 // Allocate a jlong large enough for all location attributes. 340 jlongArray attributes; 341 jlong* rawAttributes; 342 jlong* ret; 343 344 attributes = env->NewLongArray(JIMAGE_GetAttributesCount(env)); 345 if (attributes == NULL) { 346 return NULL; 347 } 348 // Get base address for jlong array. 349 rawAttributes = env->GetLongArrayElements(attributes, NULL); 350 ret = JIMAGE_GetAttributes(env, rawAttributes, id, offset); 351 // Release jlong array base address. 352 env->ReleaseLongArrayElements(attributes, rawAttributes, 0); 353 return ret == NULL ? NULL : attributes; 354 } 355 356 JNIEXPORT jlongArray JNICALL 357 Java_jdk_internal_jimage_ImageNativeSubstrate_findAttributes(JNIEnv *env, 358 jclass cls, jlong id, jbyteArray utf8) { 359 // Allocate a jlong large enough for all location attributes. 360 jsize count; 361 jlongArray attributes; 362 jlong* rawAttributes; 363 jsize size; 364 jbyte* rawBytes; 365 jlong* ret; 366 367 count = JIMAGE_GetAttributesCount(env); 368 attributes = env->NewLongArray(JIMAGE_GetAttributesCount(env)); 369 if (attributes == NULL) { 370 return NULL; 371 } 372 // Get base address for jlong array. 373 rawAttributes = env->GetLongArrayElements(attributes, NULL); 374 size = env->GetArrayLength(utf8); 375 rawBytes = env->GetByteArrayElements(utf8, NULL); 376 ret = JIMAGE_FindAttributes(env, rawAttributes, rawBytes, size, id); 377 env->ReleaseByteArrayElements(utf8, rawBytes, 0); 378 // Release jlong array base address. 379 env->ReleaseLongArrayElements(attributes, rawAttributes, 0); 380 return ret == NULL ? NULL : attributes; 381 382 } 383 384 JNIEXPORT jintArray JNICALL 385 Java_jdk_internal_jimage_ImageNativeSubstrate_attributeOffsets(JNIEnv *env, 386 jclass cls, jlong id) { 387 unsigned int length; 388 jintArray offsets; 389 jint* rawOffsets; 390 jint* ret; 391 392 length = JIMAGE_AttributeOffsetsLength(env, id); 393 offsets = env->NewIntArray(length); 394 if (offsets == NULL) { 395 return NULL; 396 } 397 // Get base address of result. 398 rawOffsets = env->GetIntArrayElements(offsets, NULL); 399 ret = JIMAGE_AttributeOffsets(env, rawOffsets, length, id); 400 if (length == 0) { 401 return NULL; 402 } 403 // Release result base address. 404 env->ReleaseIntArrayElements(offsets, rawOffsets, 0); 405 return ret == NULL ? NULL : offsets; 406 } 407 408 /* 409 * Class: jdk_internal_jimage_ImageNativeSubstrate 410 * Method: JIMAGE_open 411 * Signature: (Ljava/lang/String;)J 412 */ 413 JNIEXPORT jlong JNICALL Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1Open 414 (JNIEnv *env, jclass, jstring path) { 415 const char *nativePath = env->GetStringUTFChars(path, NULL); 416 if (nativePath == NULL) 417 return 0; // Exception already thrown 418 jint error; 419 jlong ret = (jlong) JIMAGE_Open(nativePath, &error); 420 env->ReleaseStringUTFChars(path, nativePath); 421 return ret; 422 } 423 424 /* 425 * Class: jdk_internal_jimage_ImageNativeSubstrate 426 * Method: JIMAGE_Close 427 * Signature: (J)J 428 */ 429 JNIEXPORT void JNICALL Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1Close 430 (JNIEnv *env, jclass, jlong jimageHandle) { 431 JIMAGE_Close((JImageFile*) jimageHandle); 432 } 433 434 /* 435 * Class: jdk_internal_jimage_ImageNativeSubstrate 436 * Method: JIMAGE_FindResource 437 * Signature: (JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;[J)J 438 */ 439 JNIEXPORT jlong JNICALL Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1FindResource 440 (JNIEnv *env, jclass, jlong jimageHandle, jstring moduleName, 441 jstring version, jstring path, jlongArray output_size) { 442 const char *native_module = NULL; 443 const char *native_version = NULL; 444 const char *native_path = NULL; 445 jlong * native_array = NULL; 446 jlong size = 0; 447 jlong ret = 0; 448 449 do { 450 native_module = env->GetStringUTFChars(moduleName, NULL); 451 if (native_module == NULL) 452 break; 453 native_version = env->GetStringUTFChars(version, NULL); 454 if (native_version == NULL) 455 break; 456 native_path = env->GetStringUTFChars(path, NULL); 457 if (native_path == NULL) 458 break; 459 if (env->GetArrayLength(output_size) < 1) 460 break; 461 // Get base address for jlong array. 462 native_array = env->GetLongArrayElements(output_size, NULL); 463 if (native_array == NULL) 464 break; 465 466 ret = (jlong) JIMAGE_FindResource((JImageFile *) jimageHandle, 467 native_module, native_version, native_path, &size); 468 if (ret != 0) 469 *native_array = size; 470 } while (0); 471 472 if (native_array != NULL) 473 env->ReleaseLongArrayElements(output_size, native_array, 0); 474 if (native_path != NULL) 475 env->ReleaseStringUTFChars(path, native_path); 476 if (native_version != NULL) 477 env->ReleaseStringUTFChars(path, native_version); 478 if (native_module != NULL) 479 env->ReleaseStringUTFChars(path, native_module); 480 481 return ret; 482 } 483 484 /* 485 * Class: jdk_internal_jimage_ImageNativeSubstrate 486 * Method: JIMAGE_GetResource 487 * Signature: (JJ[BJ)J 488 */ 489 JNIEXPORT jlong JNICALL Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1GetResource 490 (JNIEnv *env, jclass, jlong jimageHandle, jlong jlocationHandle, jbyteArray buffer, jlong size) { 491 jbyte * native_buffer = NULL; 492 jlong actual_size = 0; 493 do { 494 if (env->GetArrayLength(buffer) < size) 495 break; 496 497 native_buffer = env->GetByteArrayElements(buffer, NULL); 498 if (native_buffer == NULL) 499 break; 500 501 actual_size = JIMAGE_GetResource((JImageFile*) jimageHandle, 502 (JImageLocationRef) jlocationHandle, 503 (char *) native_buffer, size); 504 } while (0); 505 // Release byte array 506 if (native_buffer != NULL) 507 env->ReleaseByteArrayElements(buffer, native_buffer, 0); 508 509 return actual_size; 510 } 511 512 // Structure passed from iterator to a visitor to accumulate the results 513 514 struct VisitorData { 515 JNIEnv *env; 516 int size; // current number of strings 517 int max; // Maximum number of strings 518 jobjectArray array; // String array to store the strings 519 }; 520 521 // Visitor to accumulate fully qualified resource names 522 523 static bool resourceVisitor(JImageFile* image, 524 const char* module, const char* version, const char* package, 525 const char* name, const char* extension, void* arg) { 526 struct VisitorData *vdata = (struct VisitorData *) arg; 527 JNIEnv* env = vdata->env; 528 if (vdata->size < vdata->max) { 529 // Store if there is room in the array 530 // Concatenate to get full path 531 char fullpath[IMAGE_MAX_PATH]; 532 fullpath[0] = '\0'; 533 if (*module != '\0') { 534 strncpy(fullpath, "/", IMAGE_MAX_PATH - 1); 535 strncat(fullpath, module, IMAGE_MAX_PATH - 1); 536 strncat(fullpath, "/", IMAGE_MAX_PATH - 1); 537 } 538 if (*package != '\0') { 539 strncat(fullpath, package, IMAGE_MAX_PATH - 1); 540 strncat(fullpath, "/", IMAGE_MAX_PATH - 1); 541 } 542 strncat(fullpath, name, IMAGE_MAX_PATH - 1); 543 if (*extension != '\0') { 544 strncat(fullpath, ".", IMAGE_MAX_PATH - 1); 545 strncat(fullpath, extension, IMAGE_MAX_PATH - 1); 546 } 547 jobject str = env->NewStringUTF(fullpath); 548 JNU_CHECK_EXCEPTION_RETURN(env, true); 549 env->SetObjectArrayElement(vdata->array, vdata->size, str); 550 JNU_CHECK_EXCEPTION_RETURN(env, true); 551 } 552 vdata->size++; // always count so the total size is returned 553 return true; 554 } 555 556 /* 557 * Class: jdk_internal_jimage_ImageNativeSubstrate 558 * Method: JIMAGE_Resources 559 * Signature: (J)V 560 */ 561 JNIEXPORT jint JNICALL Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1Resources 562 (JNIEnv *env, jclass, jlong jimageHandle, 563 jobjectArray outputNames) { 564 struct VisitorData vdata; 565 vdata.env = env; 566 vdata.max = 0; 567 vdata.size = 0; 568 vdata.array = outputNames; 569 570 vdata.max = (outputNames != NULL) ? env->GetArrayLength(outputNames) : 0; 571 JIMAGE_ResourceIterator((JImageFile*) jimageHandle, &resourceVisitor, &vdata); 572 return vdata.size; 573 } 574 575 /* 576 * Class: jdk_internal_jimage_ImageNativeSubstrate 577 * Method: JIMAGE_PackageToModule 578 * Signature: (JLjava/lang/String;)Ljava/lang/String; 579 */ 580 JNIEXPORT jstring JNICALL Java_jdk_internal_jimage_ImageNativeSubstrate_JIMAGE_1PackageToModule 581 (JNIEnv *env, jclass, jlong jimageHandle, jstring package_name) { 582 const char *native_package = NULL; 583 const char *native_module = NULL; 584 jstring module = NULL; 585 586 native_package = env->GetStringUTFChars(package_name, NULL); 587 JNU_CHECK_EXCEPTION_RETURN(env, NULL); 588 589 native_module = JIMAGE_PackageToModule((JImageFile*) jimageHandle, native_package); 590 if (native_module != NULL) { 591 module = env->NewStringUTF(native_module); 592 } 593 env->ReleaseStringUTFChars(package_name, native_package); 594 return module; 595 } 596 597 JNIEXPORT void JNICALL DEF_JNI_OnUnload(JavaVM *vm, void *reserved) { 598 ImageDecompressor::image_decompressor_close(); 599 }