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