You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
201 lines
5.6 KiB
201 lines
5.6 KiB
/* |
|
* Copyright (C) 2008 The Android Open Source Project |
|
* |
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
* you may not use this file except in compliance with the License. |
|
* You may obtain a copy of the License at |
|
* |
|
* http://www.apache.org/licenses/LICENSE-2.0 |
|
* |
|
* Unless required by applicable law or agreed to in writing, software |
|
* distributed under the License is distributed on an "AS IS" BASIS, |
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
* See the License for the specific language governing permissions and |
|
* limitations under the License. |
|
*/ |
|
|
|
#ifndef LIBZIPARCHIVE_ZIPARCHIVE_PRIVATE_H_ |
|
#define LIBZIPARCHIVE_ZIPARCHIVE_PRIVATE_H_ |
|
|
|
#include <stdint.h> |
|
#include <stdlib.h> |
|
#include <unistd.h> |
|
|
|
#include <memory> |
|
#include <vector> |
|
|
|
#include <utils/FileMap.h> |
|
#include <ziparchive/zip_archive.h> |
|
#include "android-base/macros.h" |
|
|
|
static const char* kErrorMessages[] = { |
|
"Success", |
|
"Iteration ended", |
|
"Zlib error", |
|
"Invalid file", |
|
"Invalid handle", |
|
"Duplicate entries in archive", |
|
"Empty archive", |
|
"Entry not found", |
|
"Invalid offset", |
|
"Inconsistent information", |
|
"Invalid entry name", |
|
"I/O error", |
|
"File mapping failed", |
|
}; |
|
|
|
enum ErrorCodes : int32_t { |
|
kIterationEnd = -1, |
|
|
|
// We encountered a Zlib error when inflating a stream from this file. |
|
// Usually indicates file corruption. |
|
kZlibError = -2, |
|
|
|
// The input file cannot be processed as a zip archive. Usually because |
|
// it's too small, too large or does not have a valid signature. |
|
kInvalidFile = -3, |
|
|
|
// An invalid iteration / ziparchive handle was passed in as an input |
|
// argument. |
|
kInvalidHandle = -4, |
|
|
|
// The zip archive contained two (or possibly more) entries with the same |
|
// name. |
|
kDuplicateEntry = -5, |
|
|
|
// The zip archive contains no entries. |
|
kEmptyArchive = -6, |
|
|
|
// The specified entry was not found in the archive. |
|
kEntryNotFound = -7, |
|
|
|
// The zip archive contained an invalid local file header pointer. |
|
kInvalidOffset = -8, |
|
|
|
// The zip archive contained inconsistent entry information. This could |
|
// be because the central directory & local file header did not agree, or |
|
// if the actual uncompressed length or crc32 do not match their declared |
|
// values. |
|
kInconsistentInformation = -9, |
|
|
|
// An invalid entry name was encountered. |
|
kInvalidEntryName = -10, |
|
|
|
// An I/O related system call (read, lseek, ftruncate, map) failed. |
|
kIoError = -11, |
|
|
|
// We were not able to mmap the central directory or entry contents. |
|
kMmapFailed = -12, |
|
|
|
kLastErrorCode = kMmapFailed, |
|
}; |
|
|
|
class MappedZipFile { |
|
public: |
|
explicit MappedZipFile(const int fd) |
|
: has_fd_(true), fd_(fd), base_ptr_(nullptr), data_length_(0), read_pos_(0) {} |
|
|
|
explicit MappedZipFile(void* address, size_t length) |
|
: has_fd_(false), |
|
fd_(-1), |
|
base_ptr_(address), |
|
data_length_(static_cast<off64_t>(length)), |
|
read_pos_(0) {} |
|
|
|
bool HasFd() const { return has_fd_; } |
|
|
|
int GetFileDescriptor() const; |
|
|
|
void* GetBasePtr() const; |
|
|
|
off64_t GetFileLength() const; |
|
|
|
bool SeekToOffset(off64_t offset); |
|
|
|
bool ReadData(uint8_t* buffer, size_t read_amount); |
|
|
|
bool ReadAtOffset(uint8_t* buf, size_t len, off64_t off); |
|
|
|
private: |
|
// If has_fd_ is true, fd is valid and we'll read contents of a zip archive |
|
// from the file. Otherwise, we're opening the archive from a memory mapped |
|
// file. In that case, base_ptr_ points to the start of the memory region and |
|
// data_length_ defines the file length. |
|
const bool has_fd_; |
|
|
|
const int fd_; |
|
|
|
void* const base_ptr_; |
|
const off64_t data_length_; |
|
// read_pos_ is the offset to the base_ptr_ where we read data from. |
|
size_t read_pos_; |
|
}; |
|
|
|
class CentralDirectory { |
|
public: |
|
CentralDirectory(void) : base_ptr_(nullptr), length_(0) {} |
|
|
|
const uint8_t* GetBasePtr() const { return base_ptr_; } |
|
|
|
size_t GetMapLength() const { return length_; } |
|
|
|
void Initialize(void* map_base_ptr, off64_t cd_start_offset, size_t cd_size); |
|
|
|
private: |
|
const uint8_t* base_ptr_; |
|
size_t length_; |
|
}; |
|
|
|
struct ZipArchive { |
|
// open Zip archive |
|
mutable MappedZipFile mapped_zip; |
|
const bool close_file; |
|
|
|
// mapped central directory area |
|
off64_t directory_offset; |
|
CentralDirectory central_directory; |
|
std::unique_ptr<android::FileMap> directory_map; |
|
|
|
// number of entries in the Zip archive |
|
uint16_t num_entries; |
|
|
|
// We know how many entries are in the Zip archive, so we can have a |
|
// fixed-size hash table. We define a load factor of 0.75 and over |
|
// allocate so the maximum number entries can never be higher than |
|
// ((4 * UINT16_MAX) / 3 + 1) which can safely fit into a uint32_t. |
|
uint32_t hash_table_size; |
|
ZipString* hash_table; |
|
|
|
ZipArchive(const int fd, bool assume_ownership) |
|
: mapped_zip(fd), |
|
close_file(assume_ownership), |
|
directory_offset(0), |
|
central_directory(), |
|
directory_map(new android::FileMap()), |
|
num_entries(0), |
|
hash_table_size(0), |
|
hash_table(nullptr) {} |
|
|
|
ZipArchive(void* address, size_t length) |
|
: mapped_zip(address, length), |
|
close_file(false), |
|
directory_offset(0), |
|
central_directory(), |
|
directory_map(new android::FileMap()), |
|
num_entries(0), |
|
hash_table_size(0), |
|
hash_table(nullptr) {} |
|
|
|
~ZipArchive() { |
|
if (close_file && mapped_zip.GetFileDescriptor() >= 0) { |
|
close(mapped_zip.GetFileDescriptor()); |
|
} |
|
|
|
free(hash_table); |
|
} |
|
|
|
bool InitializeCentralDirectory(const char* debug_file_name, off64_t cd_start_offset, |
|
size_t cd_size); |
|
}; |
|
|
|
#endif // LIBZIPARCHIVE_ZIPARCHIVE_PRIVATE_H_
|
|
|