Home | History | Annotate | Download | only in jni
      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