1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 #define LOG_TAG "StrictJarFile" 19 20 #include <memory> 21 #include <string> 22 23 #include <log/log.h> 24 25 #include <nativehelper/JNIHelp.h> 26 #include <nativehelper/JniConstants.h> 27 #include <nativehelper/ScopedLocalRef.h> 28 #include <nativehelper/ScopedUtfChars.h> 29 #include "jni.h" 30 #include "ziparchive/zip_archive.h" 31 32 namespace android { 33 34 // The method ID for ZipEntry.<init>(String,String,JJJIII[BJJ) 35 static jmethodID zipEntryCtor; 36 37 static void throwIoException(JNIEnv* env, const int32_t errorCode) { 38 jniThrowException(env, "java/io/IOException", ErrorCodeString(errorCode)); 39 } 40 41 static jobject newZipEntry(JNIEnv* env, const ZipEntry& entry, jstring entryName) { 42 return env->NewObject(JniConstants::zipEntryClass, 43 zipEntryCtor, 44 entryName, 45 NULL, // comment 46 static_cast<jlong>(entry.crc32), 47 static_cast<jlong>(entry.compressed_length), 48 static_cast<jlong>(entry.uncompressed_length), 49 static_cast<jint>(entry.method), 50 static_cast<jint>(0), // time 51 NULL, // byte[] extra 52 static_cast<jlong>(entry.offset)); 53 } 54 55 static jlong StrictJarFile_nativeOpenJarFile(JNIEnv* env, jobject, jstring name, jint fd) { 56 // Name argument is used for logging, and can be any string. 57 ScopedUtfChars nameChars(env, name); 58 if (nameChars.c_str() == NULL) { 59 return static_cast<jlong>(-1); 60 } 61 62 ZipArchiveHandle handle; 63 int32_t error = OpenArchiveFd(fd, nameChars.c_str(), &handle, 64 false /* owned by Java side */); 65 if (error) { 66 CloseArchive(handle); 67 throwIoException(env, error); 68 return static_cast<jlong>(-1); 69 } 70 71 return reinterpret_cast<jlong>(handle); 72 } 73 74 class IterationHandle { 75 public: 76 IterationHandle() : 77 cookie_(NULL) { 78 } 79 80 void** CookieAddress() { 81 return &cookie_; 82 } 83 84 ~IterationHandle() { 85 EndIteration(cookie_); 86 } 87 88 private: 89 void* cookie_; 90 }; 91 92 93 static jlong StrictJarFile_nativeStartIteration(JNIEnv* env, jobject, jlong nativeHandle, 94 jstring prefix) { 95 ScopedUtfChars prefixChars(env, prefix); 96 if (prefixChars.c_str() == NULL) { 97 return static_cast<jlong>(-1); 98 } 99 100 IterationHandle* handle = new IterationHandle(); 101 int32_t error = 0; 102 if (prefixChars.size() == 0) { 103 error = StartIteration(reinterpret_cast<ZipArchiveHandle>(nativeHandle), 104 handle->CookieAddress(), NULL, NULL); 105 } else { 106 ZipString entry_name(prefixChars.c_str()); 107 error = StartIteration(reinterpret_cast<ZipArchiveHandle>(nativeHandle), 108 handle->CookieAddress(), &entry_name, NULL); 109 } 110 111 if (error) { 112 throwIoException(env, error); 113 return static_cast<jlong>(-1); 114 } 115 116 return reinterpret_cast<jlong>(handle); 117 } 118 119 static jobject StrictJarFile_nativeNextEntry(JNIEnv* env, jobject, jlong iterationHandle) { 120 ZipEntry data; 121 ZipString entryName; 122 123 IterationHandle* handle = reinterpret_cast<IterationHandle*>(iterationHandle); 124 const int32_t error = Next(*handle->CookieAddress(), &data, &entryName); 125 if (error) { 126 delete handle; 127 return NULL; 128 } 129 130 std::unique_ptr<char[]> entryNameCString(new char[entryName.name_length + 1]); 131 memcpy(entryNameCString.get(), entryName.name, entryName.name_length); 132 entryNameCString[entryName.name_length] = '\0'; 133 ScopedLocalRef<jstring> entryNameString(env, env->NewStringUTF(entryNameCString.get())); 134 135 return newZipEntry(env, data, entryNameString.get()); 136 } 137 138 static jobject StrictJarFile_nativeFindEntry(JNIEnv* env, jobject, jlong nativeHandle, 139 jstring entryName) { 140 ScopedUtfChars entryNameChars(env, entryName); 141 if (entryNameChars.c_str() == NULL) { 142 return NULL; 143 } 144 145 ZipEntry data; 146 const int32_t error = FindEntry(reinterpret_cast<ZipArchiveHandle>(nativeHandle), 147 ZipString(entryNameChars.c_str()), &data); 148 if (error) { 149 return NULL; 150 } 151 152 return newZipEntry(env, data, entryName); 153 } 154 155 static void StrictJarFile_nativeClose(JNIEnv*, jobject, jlong nativeHandle) { 156 CloseArchive(reinterpret_cast<ZipArchiveHandle>(nativeHandle)); 157 } 158 159 static JNINativeMethod gMethods[] = { 160 NATIVE_METHOD(StrictJarFile, nativeOpenJarFile, "(Ljava/lang/String;I)J"), 161 NATIVE_METHOD(StrictJarFile, nativeStartIteration, "(JLjava/lang/String;)J"), 162 NATIVE_METHOD(StrictJarFile, nativeNextEntry, "(J)Ljava/util/zip/ZipEntry;"), 163 NATIVE_METHOD(StrictJarFile, nativeFindEntry, "(JLjava/lang/String;)Ljava/util/zip/ZipEntry;"), 164 NATIVE_METHOD(StrictJarFile, nativeClose, "(J)V"), 165 }; 166 167 int register_android_util_jar_StrictJarFile(JNIEnv* env) { 168 jniRegisterNativeMethods(env, "android/util/jar/StrictJarFile", gMethods, NELEM(gMethods)); 169 170 zipEntryCtor = env->GetMethodID(JniConstants::zipEntryClass, "<init>", 171 "(Ljava/lang/String;Ljava/lang/String;JJJII[BJ)V"); 172 LOG_ALWAYS_FATAL_IF(zipEntryCtor == NULL, "Unable to find ZipEntry.<init>"); 173 174 return 0; 175 } 176 177 }; // namespace android 178