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 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 JNI_OnUnload(JavaVM *vm, void *reserved) {
 598     ImageDecompressor::image_decompressor_close();
 599 }