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/jni_macros.h>
26 #include <nativehelper/JNIHelp.h>
27 #include <nativehelper/ScopedLocalRef.h>
28 #include <nativehelper/ScopedUtfChars.h>
29
30 #include "core_jni_helpers.h"
31 #include "ziparchive/zip_archive.h"
32
33 namespace {
34
35 jclass zipEntryClass;
36 // The method ID for ZipEntry.<init>(String,String,JJJIII[BJJ)
37 jmethodID zipEntryCtor;
38
throwIoException(JNIEnv * env,const int32_t errorCode)39 void throwIoException(JNIEnv* env, const int32_t errorCode) {
40 jniThrowException(env, "java/io/IOException", ErrorCodeString(errorCode));
41 }
42
newZipEntry(JNIEnv * env,const ZipEntry & entry,jstring entryName)43 jobject newZipEntry(JNIEnv* env, const ZipEntry& entry, jstring entryName) {
44 return env->NewObject(zipEntryClass,
45 zipEntryCtor,
46 entryName,
47 NULL, // comment
48 static_cast<jlong>(entry.crc32),
49 static_cast<jlong>(entry.compressed_length),
50 static_cast<jlong>(entry.uncompressed_length),
51 static_cast<jint>(entry.method),
52 static_cast<jint>(0), // time
53 NULL, // byte[] extra
54 static_cast<jlong>(entry.offset));
55 }
56
StrictJarFile_nativeOpenJarFile(JNIEnv * env,jobject,jstring name,jint fd)57 jlong StrictJarFile_nativeOpenJarFile(JNIEnv* env, jobject, jstring name, jint fd) {
58 // Name argument is used for logging, and can be any string.
59 ScopedUtfChars nameChars(env, name);
60 if (nameChars.c_str() == NULL) {
61 return static_cast<jlong>(-1);
62 }
63
64 ZipArchiveHandle handle;
65 int32_t error = OpenArchiveFd(fd, nameChars.c_str(), &handle,
66 false /* owned by Java side */);
67 if (error) {
68 CloseArchive(handle);
69 throwIoException(env, error);
70 return static_cast<jlong>(-1);
71 }
72
73 return reinterpret_cast<jlong>(handle);
74 }
75
76 class IterationHandle {
77 public:
IterationHandle()78 IterationHandle() :
79 cookie_(NULL) {
80 }
81
CookieAddress()82 void** CookieAddress() {
83 return &cookie_;
84 }
85
~IterationHandle()86 ~IterationHandle() {
87 EndIteration(cookie_);
88 }
89
90 private:
91 void* cookie_;
92 };
93
94
StrictJarFile_nativeStartIteration(JNIEnv * env,jobject,jlong nativeHandle,jstring prefix)95 jlong StrictJarFile_nativeStartIteration(JNIEnv* env, jobject, jlong nativeHandle,
96 jstring prefix) {
97 ScopedUtfChars prefixChars(env, prefix);
98 if (prefixChars.c_str() == NULL) {
99 return static_cast<jlong>(-1);
100 }
101
102 IterationHandle* handle = new IterationHandle();
103 int32_t error = StartIteration(reinterpret_cast<ZipArchiveHandle>(nativeHandle),
104 handle->CookieAddress(), prefixChars.c_str(), "");
105 if (error) {
106 throwIoException(env, error);
107 return static_cast<jlong>(-1);
108 }
109
110 return reinterpret_cast<jlong>(handle);
111 }
112
StrictJarFile_nativeNextEntry(JNIEnv * env,jobject,jlong iterationHandle)113 jobject StrictJarFile_nativeNextEntry(JNIEnv* env, jobject, jlong iterationHandle) {
114 ZipEntry data;
115 std::string entryName;
116
117 IterationHandle* handle = reinterpret_cast<IterationHandle*>(iterationHandle);
118 const int32_t error = Next(*handle->CookieAddress(), &data, &entryName);
119 if (error) {
120 delete handle;
121 return NULL;
122 }
123
124 ScopedLocalRef<jstring> entryNameString(env, env->NewStringUTF(entryName.c_str()));
125
126 return newZipEntry(env, data, entryNameString.get());
127 }
128
StrictJarFile_nativeFindEntry(JNIEnv * env,jobject,jlong nativeHandle,jstring entryName)129 jobject StrictJarFile_nativeFindEntry(JNIEnv* env, jobject, jlong nativeHandle,
130 jstring entryName) {
131 ScopedUtfChars entryNameChars(env, entryName);
132 if (entryNameChars.c_str() == NULL) {
133 return NULL;
134 }
135
136 ZipEntry data;
137 const int32_t error = FindEntry(reinterpret_cast<ZipArchiveHandle>(nativeHandle),
138 entryNameChars.c_str(), &data);
139 if (error) {
140 return NULL;
141 }
142
143 return newZipEntry(env, data, entryName);
144 }
145
StrictJarFile_nativeClose(JNIEnv *,jobject,jlong nativeHandle)146 void StrictJarFile_nativeClose(JNIEnv*, jobject, jlong nativeHandle) {
147 CloseArchive(reinterpret_cast<ZipArchiveHandle>(nativeHandle));
148 }
149
150 JNINativeMethod gMethods[] = {
151 NATIVE_METHOD(StrictJarFile, nativeOpenJarFile, "(Ljava/lang/String;I)J"),
152 NATIVE_METHOD(StrictJarFile, nativeStartIteration, "(JLjava/lang/String;)J"),
153 NATIVE_METHOD(StrictJarFile, nativeNextEntry, "(J)Ljava/util/zip/ZipEntry;"),
154 NATIVE_METHOD(StrictJarFile, nativeFindEntry, "(JLjava/lang/String;)Ljava/util/zip/ZipEntry;"),
155 NATIVE_METHOD(StrictJarFile, nativeClose, "(J)V"),
156 };
157
158 } // namespace
159
160 namespace android {
161
register_android_util_jar_StrictJarFile(JNIEnv * env)162 int register_android_util_jar_StrictJarFile(JNIEnv* env) {
163 zipEntryClass = MakeGlobalRefOrDie(env, FindClassOrDie(env, "java/util/zip/ZipEntry"));
164 zipEntryCtor = GetMethodIDOrDie(env, zipEntryClass, "<init>",
165 "(Ljava/lang/String;Ljava/lang/String;JJJII[BJ)V");
166 return jniRegisterNativeMethods(env, "android/util/jar/StrictJarFile", gMethods, NELEM(gMethods));
167 }
168
169 }; // namespace android
170