blob: 4f1f926c8a2252e5fa4e2ddf7c627628224c01fd [file] [log] [blame]
Przemyslaw Szczepaniak8a7c1602015-11-03 09:47:56 +00001/*
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
Mark Salyzyn52eb4e02016-09-28 16:15:30 -070023#include <log/log.h>
24
Przemyslaw Szczepaniak8a7c1602015-11-03 09:47:56 +000025#include "JNIHelp.h"
26#include "JniConstants.h"
27#include "ScopedLocalRef.h"
28#include "ScopedUtfChars.h"
29#include "jni.h"
30#include "ziparchive/zip_archive.h"
Przemyslaw Szczepaniak8a7c1602015-11-03 09:47:56 +000031
32namespace android {
33
34// The method ID for ZipEntry.<init>(String,String,JJJIII[BJJ)
35static jmethodID zipEntryCtor;
36
37static void throwIoException(JNIEnv* env, const int32_t errorCode) {
38 jniThrowException(env, "java/io/IOException", ErrorCodeString(errorCode));
39}
40
41static 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
Tomasz Mikolajewski6c3df152016-10-20 10:49:53 +090055static 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) {
Przemyslaw Szczepaniak8a7c1602015-11-03 09:47:56 +000059 return static_cast<jlong>(-1);
60 }
61
62 ZipArchiveHandle handle;
Tomasz Mikolajewski6c3df152016-10-20 10:49:53 +090063 int32_t error = OpenArchiveFd(fd, nameChars.c_str(), &handle,
64 false /* owned by Java side */);
Przemyslaw Szczepaniak8a7c1602015-11-03 09:47:56 +000065 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
74class 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
93static 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
119static 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
138static 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
155static void StrictJarFile_nativeClose(JNIEnv*, jobject, jlong nativeHandle) {
156 CloseArchive(reinterpret_cast<ZipArchiveHandle>(nativeHandle));
157}
158
159static JNINativeMethod gMethods[] = {
Tomasz Mikolajewski6c3df152016-10-20 10:49:53 +0900160 NATIVE_METHOD(StrictJarFile, nativeOpenJarFile, "(Ljava/lang/String;I)J"),
Przemyslaw Szczepaniak8a7c1602015-11-03 09:47:56 +0000161 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
Andreas Gampefaa10332016-02-16 10:09:31 -0800167int register_android_util_jar_StrictJarFile(JNIEnv* env) {
Przemyslaw Szczepaniak8a7c1602015-11-03 09:47:56 +0000168 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>");
Andreas Gampefaa10332016-02-16 10:09:31 -0800173
174 return 0;
Przemyslaw Szczepaniak8a7c1602015-11-03 09:47:56 +0000175}
176
177}; // namespace android