• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
throwIoException(JNIEnv * env,const int32_t errorCode)37 static void throwIoException(JNIEnv* env, const int32_t errorCode) {
38   jniThrowException(env, "java/io/IOException", ErrorCodeString(errorCode));
39 }
40 
newZipEntry(JNIEnv * env,const ZipEntry & entry,jstring entryName)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 
StrictJarFile_nativeOpenJarFile(JNIEnv * env,jobject,jstring name,jint fd)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:
IterationHandle()76   IterationHandle() :
77     cookie_(NULL) {
78   }
79 
CookieAddress()80   void** CookieAddress() {
81     return &cookie_;
82   }
83 
~IterationHandle()84   ~IterationHandle() {
85     EndIteration(cookie_);
86   }
87 
88  private:
89   void* cookie_;
90 };
91 
92 
StrictJarFile_nativeStartIteration(JNIEnv * env,jobject,jlong nativeHandle,jstring prefix)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 
StrictJarFile_nativeNextEntry(JNIEnv * env,jobject,jlong iterationHandle)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 
StrictJarFile_nativeFindEntry(JNIEnv * env,jobject,jlong nativeHandle,jstring entryName)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 
StrictJarFile_nativeClose(JNIEnv *,jobject,jlong nativeHandle)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 
register_android_util_jar_StrictJarFile(JNIEnv * env)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