Merge "Add a ZipArchiveStreamEntry class."
am: 9162c1496d
* commit '9162c1496dd6f6ce2a663352632c1de3c429a29a':
Add a ZipArchiveStreamEntry class.
This commit is contained in:
commit
64686bcd9e
8 changed files with 626 additions and 117 deletions
46
include/ziparchive/zip_archive_stream_entry.h
Normal file
46
include/ziparchive/zip_archive_stream_entry.h
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Read-only stream access to Zip archives entries.
|
||||||
|
#ifndef LIBZIPARCHIVE_ZIPARCHIVESTREAMENTRY_H_
|
||||||
|
#define LIBZIPARCHIVE_ZIPARCHIVESTREAMENTRY_H_
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <ziparchive/zip_archive.h>
|
||||||
|
|
||||||
|
class ZipArchiveStreamEntry {
|
||||||
|
public:
|
||||||
|
virtual ~ZipArchiveStreamEntry() {}
|
||||||
|
|
||||||
|
virtual const std::vector<uint8_t>* Read() = 0;
|
||||||
|
|
||||||
|
virtual bool Verify() = 0;
|
||||||
|
|
||||||
|
static ZipArchiveStreamEntry* Create(ZipArchiveHandle handle, const ZipEntry& entry);
|
||||||
|
static ZipArchiveStreamEntry* CreateRaw(ZipArchiveHandle handle, const ZipEntry& entry);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
ZipArchiveStreamEntry(ZipArchiveHandle handle) : handle_(handle) {}
|
||||||
|
|
||||||
|
virtual bool Init(const ZipEntry& entry);
|
||||||
|
|
||||||
|
ZipArchiveHandle handle_;
|
||||||
|
|
||||||
|
uint32_t crc32_;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // LIBZIPARCHIVE_ZIPARCHIVESTREAMENTRY_H_
|
||||||
|
|
@ -15,34 +15,46 @@
|
||||||
|
|
||||||
LOCAL_PATH := $(call my-dir)
|
LOCAL_PATH := $(call my-dir)
|
||||||
|
|
||||||
source_files := zip_archive.cc zip_writer.cc
|
libziparchive_source_files := \
|
||||||
test_files := zip_archive_test.cc zip_writer_test.cc entry_name_utils_test.cc
|
zip_archive.cc \
|
||||||
|
zip_archive_stream_entry.cc \
|
||||||
|
zip_writer.cc \
|
||||||
|
|
||||||
|
libziparchive_test_files := \
|
||||||
|
entry_name_utils_test.cc \
|
||||||
|
zip_archive_test.cc \
|
||||||
|
zip_writer_test.cc \
|
||||||
|
|
||||||
# ZLIB_CONST turns on const for input buffers, which is pretty standard.
|
# ZLIB_CONST turns on const for input buffers, which is pretty standard.
|
||||||
common_c_flags := -Werror -Wall -DZLIB_CONST
|
libziparchive_common_c_flags := \
|
||||||
|
-DZLIB_CONST \
|
||||||
|
-Werror \
|
||||||
|
-Wall \
|
||||||
|
|
||||||
# Incorrectly warns when C++11 empty brace {} initializer is used.
|
# Incorrectly warns when C++11 empty brace {} initializer is used.
|
||||||
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61489
|
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61489
|
||||||
common_cpp_flags := -Wold-style-cast -Wno-missing-field-initializers
|
libziparchive_common_cpp_flags := \
|
||||||
|
-Wold-style-cast \
|
||||||
|
-Wno-missing-field-initializers \
|
||||||
|
|
||||||
include $(CLEAR_VARS)
|
include $(CLEAR_VARS)
|
||||||
LOCAL_CPP_EXTENSION := .cc
|
LOCAL_CPP_EXTENSION := .cc
|
||||||
LOCAL_SRC_FILES := ${source_files}
|
LOCAL_SRC_FILES := $(libziparchive_source_files)
|
||||||
LOCAL_STATIC_LIBRARIES := libz
|
LOCAL_STATIC_LIBRARIES := libz
|
||||||
LOCAL_SHARED_LIBRARIES := libutils libbase
|
LOCAL_SHARED_LIBRARIES := libutils libbase
|
||||||
LOCAL_MODULE:= libziparchive
|
LOCAL_MODULE:= libziparchive
|
||||||
LOCAL_CFLAGS := $(common_c_flags)
|
LOCAL_CFLAGS := $(libziparchive_common_c_flags)
|
||||||
LOCAL_CPPFLAGS := $(common_cpp_flags)
|
LOCAL_CPPFLAGS := $(libziparchive_common_cpp_flags)
|
||||||
include $(BUILD_STATIC_LIBRARY)
|
include $(BUILD_STATIC_LIBRARY)
|
||||||
|
|
||||||
include $(CLEAR_VARS)
|
include $(CLEAR_VARS)
|
||||||
LOCAL_CPP_EXTENSION := .cc
|
LOCAL_CPP_EXTENSION := .cc
|
||||||
LOCAL_SRC_FILES := ${source_files}
|
LOCAL_SRC_FILES := $(libziparchive_source_files)
|
||||||
LOCAL_STATIC_LIBRARIES := libz libutils libbase
|
LOCAL_STATIC_LIBRARIES := libz libutils libbase
|
||||||
LOCAL_MODULE:= libziparchive-host
|
LOCAL_MODULE:= libziparchive-host
|
||||||
LOCAL_CFLAGS := $(common_c_flags)
|
LOCAL_CFLAGS := $(libziparchive_common_c_flags)
|
||||||
LOCAL_CFLAGS_windows := -mno-ms-bitfields
|
LOCAL_CFLAGS_windows := -mno-ms-bitfields
|
||||||
LOCAL_CPPFLAGS := $(common_cpp_flags)
|
LOCAL_CPPFLAGS := $(libziparchive_common_cpp_flags)
|
||||||
|
|
||||||
LOCAL_MULTILIB := both
|
LOCAL_MULTILIB := both
|
||||||
LOCAL_MODULE_HOST_OS := darwin linux windows
|
LOCAL_MODULE_HOST_OS := darwin linux windows
|
||||||
|
|
@ -50,12 +62,12 @@ include $(BUILD_HOST_STATIC_LIBRARY)
|
||||||
|
|
||||||
include $(CLEAR_VARS)
|
include $(CLEAR_VARS)
|
||||||
LOCAL_CPP_EXTENSION := .cc
|
LOCAL_CPP_EXTENSION := .cc
|
||||||
LOCAL_SRC_FILES := ${source_files}
|
LOCAL_SRC_FILES := $(libziparchive_source_files)
|
||||||
LOCAL_STATIC_LIBRARIES := libutils
|
LOCAL_STATIC_LIBRARIES := libutils
|
||||||
LOCAL_SHARED_LIBRARIES := libz-host liblog libbase
|
LOCAL_SHARED_LIBRARIES := libz-host liblog libbase
|
||||||
LOCAL_MODULE:= libziparchive-host
|
LOCAL_MODULE:= libziparchive-host
|
||||||
LOCAL_CFLAGS := $(common_c_flags)
|
LOCAL_CFLAGS := $(libziparchive_common_c_flags)
|
||||||
LOCAL_CPPFLAGS := $(common_cpp_flags)
|
LOCAL_CPPFLAGS := $(libziparchive_common_cpp_flags)
|
||||||
LOCAL_MULTILIB := both
|
LOCAL_MULTILIB := both
|
||||||
include $(BUILD_HOST_SHARED_LIBRARY)
|
include $(BUILD_HOST_SHARED_LIBRARY)
|
||||||
|
|
||||||
|
|
@ -63,21 +75,33 @@ include $(BUILD_HOST_SHARED_LIBRARY)
|
||||||
include $(CLEAR_VARS)
|
include $(CLEAR_VARS)
|
||||||
LOCAL_MODULE := ziparchive-tests
|
LOCAL_MODULE := ziparchive-tests
|
||||||
LOCAL_CPP_EXTENSION := .cc
|
LOCAL_CPP_EXTENSION := .cc
|
||||||
LOCAL_CFLAGS := $(common_c_flags)
|
LOCAL_CFLAGS := $(libziparchive_common_c_flags)
|
||||||
LOCAL_CPPFLAGS := $(common_cpp_flags)
|
LOCAL_CPPFLAGS := $(libziparchive_common_cpp_flags)
|
||||||
LOCAL_SRC_FILES := $(test_files)
|
LOCAL_SRC_FILES := $(libziparchive_test_files)
|
||||||
LOCAL_SHARED_LIBRARIES := liblog libbase
|
LOCAL_SHARED_LIBRARIES := \
|
||||||
LOCAL_STATIC_LIBRARIES := libziparchive libz libutils
|
libbase \
|
||||||
|
liblog \
|
||||||
|
|
||||||
|
LOCAL_STATIC_LIBRARIES := \
|
||||||
|
libziparchive \
|
||||||
|
libz \
|
||||||
|
libutils \
|
||||||
|
|
||||||
include $(BUILD_NATIVE_TEST)
|
include $(BUILD_NATIVE_TEST)
|
||||||
|
|
||||||
include $(CLEAR_VARS)
|
include $(CLEAR_VARS)
|
||||||
LOCAL_MODULE := ziparchive-tests-host
|
LOCAL_MODULE := ziparchive-tests-host
|
||||||
LOCAL_CPP_EXTENSION := .cc
|
LOCAL_CPP_EXTENSION := .cc
|
||||||
LOCAL_CFLAGS := $(common_c_flags)
|
LOCAL_CFLAGS := $(libziparchive_common_c_flags)
|
||||||
LOCAL_CPPFLAGS := -Wno-unnamed-type-template-args $(common_cpp_flags)
|
LOCAL_CPPFLAGS := -Wno-unnamed-type-template-args $(libziparchive_common_cpp_flags)
|
||||||
LOCAL_SRC_FILES := $(test_files)
|
LOCAL_SRC_FILES := $(libziparchive_test_files)
|
||||||
LOCAL_SHARED_LIBRARIES := libziparchive-host liblog libbase
|
LOCAL_SHARED_LIBRARIES := \
|
||||||
|
libziparchive-host \
|
||||||
|
liblog \
|
||||||
|
libbase \
|
||||||
|
|
||||||
LOCAL_STATIC_LIBRARIES := \
|
LOCAL_STATIC_LIBRARIES := \
|
||||||
|
libutils \
|
||||||
libz \
|
libz \
|
||||||
libutils
|
|
||||||
include $(BUILD_HOST_NATIVE_TEST)
|
include $(BUILD_HOST_NATIVE_TEST)
|
||||||
|
|
|
||||||
BIN
libziparchive/testdata/bad_crc.zip
vendored
Normal file
BIN
libziparchive/testdata/bad_crc.zip
vendored
Normal file
Binary file not shown.
BIN
libziparchive/testdata/large.zip
vendored
Normal file
BIN
libziparchive/testdata/large.zip
vendored
Normal file
Binary file not shown.
|
|
@ -36,11 +36,12 @@
|
||||||
#include "log/log.h"
|
#include "log/log.h"
|
||||||
#include "utils/Compat.h"
|
#include "utils/Compat.h"
|
||||||
#include "utils/FileMap.h"
|
#include "utils/FileMap.h"
|
||||||
|
#include "ziparchive/zip_archive.h"
|
||||||
#include "zlib.h"
|
#include "zlib.h"
|
||||||
|
|
||||||
#include "entry_name_utils-inl.h"
|
#include "entry_name_utils-inl.h"
|
||||||
#include "zip_archive_common.h"
|
#include "zip_archive_common.h"
|
||||||
#include "ziparchive/zip_archive.h"
|
#include "zip_archive_private.h"
|
||||||
|
|
||||||
using android::base::get_unaligned;
|
using android::base::get_unaligned;
|
||||||
|
|
||||||
|
|
@ -134,43 +135,6 @@ static const int32_t kErrorMessageLowerBound = -13;
|
||||||
* every page that the Central Directory touches. Easier to tuck a copy
|
* every page that the Central Directory touches. Easier to tuck a copy
|
||||||
* of the string length into the hash table entry.
|
* of the string length into the hash table entry.
|
||||||
*/
|
*/
|
||||||
struct ZipArchive {
|
|
||||||
/* open Zip archive */
|
|
||||||
const int fd;
|
|
||||||
const bool close_file;
|
|
||||||
|
|
||||||
/* mapped central directory area */
|
|
||||||
off64_t directory_offset;
|
|
||||||
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 overallocat
|
|
||||||
* 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) :
|
|
||||||
fd(fd),
|
|
||||||
close_file(assume_ownership),
|
|
||||||
directory_offset(0),
|
|
||||||
num_entries(0),
|
|
||||||
hash_table_size(0),
|
|
||||||
hash_table(NULL) {}
|
|
||||||
|
|
||||||
~ZipArchive() {
|
|
||||||
if (close_file && fd >= 0) {
|
|
||||||
close(fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(hash_table);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Round up to the next highest power of 2.
|
* Round up to the next highest power of 2.
|
||||||
|
|
|
||||||
63
libziparchive/zip_archive_private.h
Normal file
63
libziparchive/zip_archive_private.h
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
* 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 <utils/FileMap.h>
|
||||||
|
#include <ziparchive/zip_archive.h>
|
||||||
|
|
||||||
|
struct ZipArchive {
|
||||||
|
// open Zip archive
|
||||||
|
const int fd;
|
||||||
|
const bool close_file;
|
||||||
|
|
||||||
|
// mapped central directory area
|
||||||
|
off64_t directory_offset;
|
||||||
|
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) :
|
||||||
|
fd(fd),
|
||||||
|
close_file(assume_ownership),
|
||||||
|
directory_offset(0),
|
||||||
|
num_entries(0),
|
||||||
|
hash_table_size(0),
|
||||||
|
hash_table(NULL) {}
|
||||||
|
|
||||||
|
~ZipArchive() {
|
||||||
|
if (close_file && fd >= 0) {
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(hash_table);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // LIBZIPARCHIVE_ZIPARCHIVE_PRIVATE_H_
|
||||||
305
libziparchive/zip_archive_stream_entry.cc
Normal file
305
libziparchive/zip_archive_stream_entry.cc
Normal file
|
|
@ -0,0 +1,305 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Read-only stream access to Zip Archive entries.
|
||||||
|
#include <errno.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#define LOG_TAG "ZIPARCHIVE"
|
||||||
|
#include <android-base/file.h>
|
||||||
|
#include <log/log.h>
|
||||||
|
#include <ziparchive/zip_archive.h>
|
||||||
|
#include <ziparchive/zip_archive_stream_entry.h>
|
||||||
|
#include <zlib.h>
|
||||||
|
|
||||||
|
#include "zip_archive_private.h"
|
||||||
|
|
||||||
|
static constexpr size_t kBufSize = 65535;
|
||||||
|
|
||||||
|
bool ZipArchiveStreamEntry::Init(const ZipEntry& entry) {
|
||||||
|
ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle_);
|
||||||
|
off64_t data_offset = entry.offset;
|
||||||
|
if (lseek64(archive->fd, data_offset, SEEK_SET) != data_offset) {
|
||||||
|
ALOGW("lseek to data at %" PRId64 " failed: %s", data_offset, strerror(errno));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
crc32_ = entry.crc32;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ZipArchiveStreamEntryUncompressed : public ZipArchiveStreamEntry {
|
||||||
|
public:
|
||||||
|
ZipArchiveStreamEntryUncompressed(ZipArchiveHandle handle) : ZipArchiveStreamEntry(handle) {}
|
||||||
|
virtual ~ZipArchiveStreamEntryUncompressed() {}
|
||||||
|
|
||||||
|
const std::vector<uint8_t>* Read() override;
|
||||||
|
|
||||||
|
bool Verify() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool Init(const ZipEntry& entry) override;
|
||||||
|
|
||||||
|
uint32_t length_;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<uint8_t> data_;
|
||||||
|
uint32_t computed_crc32_;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool ZipArchiveStreamEntryUncompressed::Init(const ZipEntry& entry) {
|
||||||
|
if (!ZipArchiveStreamEntry::Init(entry)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
length_ = entry.uncompressed_length;
|
||||||
|
|
||||||
|
data_.resize(kBufSize);
|
||||||
|
computed_crc32_ = 0;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<uint8_t>* ZipArchiveStreamEntryUncompressed::Read() {
|
||||||
|
if (length_ == 0) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t bytes = (length_ > data_.size()) ? data_.size() : length_;
|
||||||
|
ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle_);
|
||||||
|
errno = 0;
|
||||||
|
if (!android::base::ReadFully(archive->fd, data_.data(), bytes)) {
|
||||||
|
if (errno != 0) {
|
||||||
|
ALOGE("Error reading from archive fd: %s", strerror(errno));
|
||||||
|
} else {
|
||||||
|
ALOGE("Short read of zip file, possibly corrupted zip?");
|
||||||
|
}
|
||||||
|
length_ = 0;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes < data_.size()) {
|
||||||
|
data_.resize(bytes);
|
||||||
|
}
|
||||||
|
computed_crc32_ = crc32(computed_crc32_, data_.data(), data_.size());
|
||||||
|
length_ -= bytes;
|
||||||
|
return &data_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ZipArchiveStreamEntryUncompressed::Verify() {
|
||||||
|
return length_ == 0 && crc32_ == computed_crc32_;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ZipArchiveStreamEntryCompressed : public ZipArchiveStreamEntry {
|
||||||
|
public:
|
||||||
|
ZipArchiveStreamEntryCompressed(ZipArchiveHandle handle) : ZipArchiveStreamEntry(handle) {}
|
||||||
|
virtual ~ZipArchiveStreamEntryCompressed();
|
||||||
|
|
||||||
|
const std::vector<uint8_t>* Read() override;
|
||||||
|
|
||||||
|
bool Verify() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool Init(const ZipEntry& entry) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool z_stream_init_ = false;
|
||||||
|
z_stream z_stream_;
|
||||||
|
std::vector<uint8_t> in_;
|
||||||
|
std::vector<uint8_t> out_;
|
||||||
|
uint32_t uncompressed_length_;
|
||||||
|
uint32_t compressed_length_;
|
||||||
|
uint32_t computed_crc32_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// This method is using libz macros with old-style-casts
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wold-style-cast"
|
||||||
|
static inline int zlib_inflateInit2(z_stream* stream, int window_bits) {
|
||||||
|
return inflateInit2(stream, window_bits);
|
||||||
|
}
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
|
||||||
|
bool ZipArchiveStreamEntryCompressed::Init(const ZipEntry& entry) {
|
||||||
|
if (!ZipArchiveStreamEntry::Init(entry)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize the zlib stream struct.
|
||||||
|
memset(&z_stream_, 0, sizeof(z_stream_));
|
||||||
|
z_stream_.zalloc = Z_NULL;
|
||||||
|
z_stream_.zfree = Z_NULL;
|
||||||
|
z_stream_.opaque = Z_NULL;
|
||||||
|
z_stream_.next_in = nullptr;
|
||||||
|
z_stream_.avail_in = 0;
|
||||||
|
z_stream_.avail_out = 0;
|
||||||
|
z_stream_.data_type = Z_UNKNOWN;
|
||||||
|
|
||||||
|
// Use the undocumented "negative window bits" feature to tell zlib
|
||||||
|
// that there's no zlib header waiting for it.
|
||||||
|
int zerr = zlib_inflateInit2(&z_stream_, -MAX_WBITS);
|
||||||
|
if (zerr != Z_OK) {
|
||||||
|
if (zerr == Z_VERSION_ERROR) {
|
||||||
|
ALOGE("Installed zlib is not compatible with linked version (%s)",
|
||||||
|
ZLIB_VERSION);
|
||||||
|
} else {
|
||||||
|
ALOGE("Call to inflateInit2 failed (zerr=%d)", zerr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
z_stream_init_ = true;
|
||||||
|
|
||||||
|
uncompressed_length_ = entry.uncompressed_length;
|
||||||
|
compressed_length_ = entry.compressed_length;
|
||||||
|
|
||||||
|
out_.resize(kBufSize);
|
||||||
|
in_.resize(kBufSize);
|
||||||
|
|
||||||
|
computed_crc32_ = 0;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZipArchiveStreamEntryCompressed::~ZipArchiveStreamEntryCompressed() {
|
||||||
|
if (z_stream_init_) {
|
||||||
|
inflateEnd(&z_stream_);
|
||||||
|
z_stream_init_ = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ZipArchiveStreamEntryCompressed::Verify() {
|
||||||
|
return z_stream_init_ && uncompressed_length_ == 0 && compressed_length_ == 0 &&
|
||||||
|
crc32_ == computed_crc32_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<uint8_t>* ZipArchiveStreamEntryCompressed::Read() {
|
||||||
|
if (z_stream_.avail_out == 0) {
|
||||||
|
z_stream_.next_out = out_.data();
|
||||||
|
z_stream_.avail_out = out_.size();;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if (z_stream_.avail_in == 0) {
|
||||||
|
if (compressed_length_ == 0) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
size_t bytes = (compressed_length_ > in_.size()) ? in_.size() : compressed_length_;
|
||||||
|
ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle_);
|
||||||
|
errno = 0;
|
||||||
|
if (!android::base::ReadFully(archive->fd, in_.data(), bytes)) {
|
||||||
|
if (errno != 0) {
|
||||||
|
ALOGE("Error reading from archive fd: %s", strerror(errno));
|
||||||
|
} else {
|
||||||
|
ALOGE("Short read of zip file, possibly corrupted zip?");
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
compressed_length_ -= bytes;
|
||||||
|
z_stream_.next_in = in_.data();
|
||||||
|
z_stream_.avail_in = bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
int zerr = inflate(&z_stream_, Z_NO_FLUSH);
|
||||||
|
if (zerr != Z_OK && zerr != Z_STREAM_END) {
|
||||||
|
ALOGE("inflate zerr=%d (nIn=%p aIn=%u nOut=%p aOut=%u)",
|
||||||
|
zerr, z_stream_.next_in, z_stream_.avail_in,
|
||||||
|
z_stream_.next_out, z_stream_.avail_out);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (z_stream_.avail_out == 0) {
|
||||||
|
uncompressed_length_ -= out_.size();
|
||||||
|
computed_crc32_ = crc32(computed_crc32_, out_.data(), out_.size());
|
||||||
|
return &out_;
|
||||||
|
}
|
||||||
|
if (zerr == Z_STREAM_END) {
|
||||||
|
if (z_stream_.avail_out != 0) {
|
||||||
|
// Resize the vector down to the actual size of the data.
|
||||||
|
out_.resize(out_.size() - z_stream_.avail_out);
|
||||||
|
computed_crc32_ = crc32(computed_crc32_, out_.data(), out_.size());
|
||||||
|
uncompressed_length_ -= out_.size();
|
||||||
|
return &out_;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ZipArchiveStreamEntryRawCompressed : public ZipArchiveStreamEntryUncompressed {
|
||||||
|
public:
|
||||||
|
ZipArchiveStreamEntryRawCompressed(ZipArchiveHandle handle)
|
||||||
|
: ZipArchiveStreamEntryUncompressed(handle) {}
|
||||||
|
virtual ~ZipArchiveStreamEntryRawCompressed() {}
|
||||||
|
|
||||||
|
bool Verify() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool Init(const ZipEntry& entry) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool ZipArchiveStreamEntryRawCompressed::Init(const ZipEntry& entry) {
|
||||||
|
if (!ZipArchiveStreamEntryUncompressed::Init(entry)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
length_ = entry.compressed_length;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ZipArchiveStreamEntryRawCompressed::Verify() {
|
||||||
|
return length_ == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZipArchiveStreamEntry* ZipArchiveStreamEntry::Create(
|
||||||
|
ZipArchiveHandle handle, const ZipEntry& entry) {
|
||||||
|
ZipArchiveStreamEntry* stream = nullptr;
|
||||||
|
if (entry.method != kCompressStored) {
|
||||||
|
stream = new ZipArchiveStreamEntryCompressed(handle);
|
||||||
|
} else {
|
||||||
|
stream = new ZipArchiveStreamEntryUncompressed(handle);
|
||||||
|
}
|
||||||
|
if (stream && !stream->Init(entry)) {
|
||||||
|
delete stream;
|
||||||
|
stream = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZipArchiveStreamEntry* ZipArchiveStreamEntry::CreateRaw(
|
||||||
|
ZipArchiveHandle handle, const ZipEntry& entry) {
|
||||||
|
ZipArchiveStreamEntry* stream = nullptr;
|
||||||
|
if (entry.method == kCompressStored) {
|
||||||
|
// Not compressed, don't need to do anything special.
|
||||||
|
stream = new ZipArchiveStreamEntryUncompressed(handle);
|
||||||
|
} else {
|
||||||
|
stream = new ZipArchiveStreamEntryRawCompressed(handle);
|
||||||
|
}
|
||||||
|
if (stream && !stream->Init(entry)) {
|
||||||
|
delete stream;
|
||||||
|
stream = nullptr;
|
||||||
|
}
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
@ -14,54 +14,49 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ziparchive/zip_archive.h"
|
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <android-base/file.h>
|
#include <android-base/file.h>
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
#include <ziparchive/zip_archive.h>
|
||||||
|
#include <ziparchive/zip_archive_stream_entry.h>
|
||||||
|
|
||||||
static std::string test_data_dir;
|
static std::string test_data_dir;
|
||||||
|
|
||||||
static const std::string kMissingZip = "missing.zip";
|
static const std::string kMissingZip = "missing.zip";
|
||||||
static const std::string kValidZip = "valid.zip";
|
static const std::string kValidZip = "valid.zip";
|
||||||
|
static const std::string kLargeZip = "large.zip";
|
||||||
|
static const std::string kBadCrcZip = "bad_crc.zip";
|
||||||
|
|
||||||
static const uint8_t kATxtContents[] = {
|
static const std::vector<uint8_t> kATxtContents {
|
||||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
|
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
|
||||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
|
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
|
||||||
'\n'
|
'\n'
|
||||||
};
|
};
|
||||||
|
|
||||||
static const uint8_t kBTxtContents[] = {
|
static const std::vector<uint8_t> kATxtContentsCompressed {
|
||||||
|
'K', 'L', 'J', 'N', 'I', 'M', 'K', 207, 'H',
|
||||||
|
132, 210, '\\', '\0'
|
||||||
|
};
|
||||||
|
|
||||||
|
static const std::vector<uint8_t> kBTxtContents {
|
||||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
|
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
|
||||||
'\n'
|
'\n'
|
||||||
};
|
};
|
||||||
|
|
||||||
static const uint16_t kATxtNameLength = 5;
|
static const std::string kATxtName("a.txt");
|
||||||
static const uint16_t kBTxtNameLength = 5;
|
static const std::string kBTxtName("b.txt");
|
||||||
static const uint16_t kNonexistentTxtNameLength = 15;
|
static const std::string kNonexistentTxtName("nonexistent.txt");
|
||||||
static const uint16_t kEmptyTxtNameLength = 9;
|
static const std::string kEmptyTxtName("empty.txt");
|
||||||
|
static const std::string kLargeCompressTxtName("compress.txt");
|
||||||
static const uint8_t kATxtName[kATxtNameLength] = {
|
static const std::string kLargeUncompressTxtName("uncompress.txt");
|
||||||
'a', '.', 't', 'x', 't'
|
|
||||||
};
|
|
||||||
|
|
||||||
static const uint8_t kBTxtName[kBTxtNameLength] = {
|
|
||||||
'b', '.', 't', 'x', 't'
|
|
||||||
};
|
|
||||||
|
|
||||||
static const uint8_t kNonexistentTxtName[kNonexistentTxtNameLength] = {
|
|
||||||
'n', 'o', 'n', 'e', 'x', 'i', 's', 't', 'e', 'n', 't', '.', 't', 'x' ,'t'
|
|
||||||
};
|
|
||||||
|
|
||||||
static const uint8_t kEmptyTxtName[kEmptyTxtNameLength] = {
|
|
||||||
'e', 'm', 'p', 't', 'y', '.', 't', 'x', 't'
|
|
||||||
};
|
|
||||||
|
|
||||||
static int32_t OpenArchiveWrapper(const std::string& name,
|
static int32_t OpenArchiveWrapper(const std::string& name,
|
||||||
ZipArchiveHandle* handle) {
|
ZipArchiveHandle* handle) {
|
||||||
|
|
@ -75,6 +70,11 @@ static void AssertNameEquals(const std::string& name_str,
|
||||||
ASSERT_EQ(0, memcmp(name_str.c_str(), name.name, name.name_length));
|
ASSERT_EQ(0, memcmp(name_str.c_str(), name.name, name.name_length));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void SetZipString(ZipString* zip_str, const std::string& str) {
|
||||||
|
zip_str->name = reinterpret_cast<const uint8_t*>(str.c_str());
|
||||||
|
zip_str->name_length = str.size();
|
||||||
|
}
|
||||||
|
|
||||||
TEST(ziparchive, Open) {
|
TEST(ziparchive, Open) {
|
||||||
ZipArchiveHandle handle;
|
ZipArchiveHandle handle;
|
||||||
ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
|
ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
|
||||||
|
|
@ -115,7 +115,7 @@ TEST(ziparchive, Iteration) {
|
||||||
ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
|
ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
|
||||||
|
|
||||||
void* iteration_cookie;
|
void* iteration_cookie;
|
||||||
ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, NULL, NULL));
|
ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, nullptr, nullptr));
|
||||||
|
|
||||||
ZipEntry data;
|
ZipEntry data;
|
||||||
ZipString name;
|
ZipString name;
|
||||||
|
|
@ -152,7 +152,7 @@ TEST(ziparchive, IterationWithPrefix) {
|
||||||
|
|
||||||
void* iteration_cookie;
|
void* iteration_cookie;
|
||||||
ZipString prefix("b/");
|
ZipString prefix("b/");
|
||||||
ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, &prefix, NULL));
|
ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, &prefix, nullptr));
|
||||||
|
|
||||||
ZipEntry data;
|
ZipEntry data;
|
||||||
ZipString name;
|
ZipString name;
|
||||||
|
|
@ -181,7 +181,7 @@ TEST(ziparchive, IterationWithSuffix) {
|
||||||
|
|
||||||
void* iteration_cookie;
|
void* iteration_cookie;
|
||||||
ZipString suffix(".txt");
|
ZipString suffix(".txt");
|
||||||
ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, NULL, &suffix));
|
ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, nullptr, &suffix));
|
||||||
|
|
||||||
ZipEntry data;
|
ZipEntry data;
|
||||||
ZipString name;
|
ZipString name;
|
||||||
|
|
@ -262,8 +262,7 @@ TEST(ziparchive, FindEntry) {
|
||||||
|
|
||||||
ZipEntry data;
|
ZipEntry data;
|
||||||
ZipString name;
|
ZipString name;
|
||||||
name.name = kATxtName;
|
SetZipString(&name, kATxtName);
|
||||||
name.name_length = kATxtNameLength;
|
|
||||||
ASSERT_EQ(0, FindEntry(handle, name, &data));
|
ASSERT_EQ(0, FindEntry(handle, name, &data));
|
||||||
|
|
||||||
// Known facts about a.txt, from zipinfo -v.
|
// Known facts about a.txt, from zipinfo -v.
|
||||||
|
|
@ -276,8 +275,7 @@ TEST(ziparchive, FindEntry) {
|
||||||
|
|
||||||
// An entry that doesn't exist. Should be a negative return code.
|
// An entry that doesn't exist. Should be a negative return code.
|
||||||
ZipString absent_name;
|
ZipString absent_name;
|
||||||
absent_name.name = kNonexistentTxtName;
|
SetZipString(&absent_name, kNonexistentTxtName);
|
||||||
absent_name.name_length = kNonexistentTxtNameLength;
|
|
||||||
ASSERT_LT(FindEntry(handle, absent_name, &data), 0);
|
ASSERT_LT(FindEntry(handle, absent_name, &data), 0);
|
||||||
|
|
||||||
CloseArchive(handle);
|
CloseArchive(handle);
|
||||||
|
|
@ -288,7 +286,7 @@ TEST(ziparchive, TestInvalidDeclaredLength) {
|
||||||
ASSERT_EQ(0, OpenArchiveWrapper("declaredlength.zip", &handle));
|
ASSERT_EQ(0, OpenArchiveWrapper("declaredlength.zip", &handle));
|
||||||
|
|
||||||
void* iteration_cookie;
|
void* iteration_cookie;
|
||||||
ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, NULL, NULL));
|
ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, nullptr, nullptr));
|
||||||
|
|
||||||
ZipString name;
|
ZipString name;
|
||||||
ZipEntry data;
|
ZipEntry data;
|
||||||
|
|
@ -306,26 +304,24 @@ TEST(ziparchive, ExtractToMemory) {
|
||||||
// An entry that's deflated.
|
// An entry that's deflated.
|
||||||
ZipEntry data;
|
ZipEntry data;
|
||||||
ZipString a_name;
|
ZipString a_name;
|
||||||
a_name.name = kATxtName;
|
SetZipString(&a_name, kATxtName);
|
||||||
a_name.name_length = kATxtNameLength;
|
|
||||||
ASSERT_EQ(0, FindEntry(handle, a_name, &data));
|
ASSERT_EQ(0, FindEntry(handle, a_name, &data));
|
||||||
const uint32_t a_size = data.uncompressed_length;
|
const uint32_t a_size = data.uncompressed_length;
|
||||||
ASSERT_EQ(a_size, sizeof(kATxtContents));
|
ASSERT_EQ(a_size, kATxtContents.size());
|
||||||
uint8_t* buffer = new uint8_t[a_size];
|
uint8_t* buffer = new uint8_t[a_size];
|
||||||
ASSERT_EQ(0, ExtractToMemory(handle, &data, buffer, a_size));
|
ASSERT_EQ(0, ExtractToMemory(handle, &data, buffer, a_size));
|
||||||
ASSERT_EQ(0, memcmp(buffer, kATxtContents, a_size));
|
ASSERT_EQ(0, memcmp(buffer, kATxtContents.data(), a_size));
|
||||||
delete[] buffer;
|
delete[] buffer;
|
||||||
|
|
||||||
// An entry that's stored.
|
// An entry that's stored.
|
||||||
ZipString b_name;
|
ZipString b_name;
|
||||||
b_name.name = kBTxtName;
|
SetZipString(&b_name, kBTxtName);
|
||||||
b_name.name_length = kBTxtNameLength;
|
|
||||||
ASSERT_EQ(0, FindEntry(handle, b_name, &data));
|
ASSERT_EQ(0, FindEntry(handle, b_name, &data));
|
||||||
const uint32_t b_size = data.uncompressed_length;
|
const uint32_t b_size = data.uncompressed_length;
|
||||||
ASSERT_EQ(b_size, sizeof(kBTxtContents));
|
ASSERT_EQ(b_size, kBTxtContents.size());
|
||||||
buffer = new uint8_t[b_size];
|
buffer = new uint8_t[b_size];
|
||||||
ASSERT_EQ(0, ExtractToMemory(handle, &data, buffer, b_size));
|
ASSERT_EQ(0, ExtractToMemory(handle, &data, buffer, b_size));
|
||||||
ASSERT_EQ(0, memcmp(buffer, kBTxtContents, b_size));
|
ASSERT_EQ(0, memcmp(buffer, kBTxtContents.data(), b_size));
|
||||||
delete[] buffer;
|
delete[] buffer;
|
||||||
|
|
||||||
CloseArchive(handle);
|
CloseArchive(handle);
|
||||||
|
|
@ -374,8 +370,7 @@ static const uint16_t kAbZip[] = {
|
||||||
0x0100, 0x4c00, 0x0000, 0x5b00, 0x0001, 0x0000, 0x0000
|
0x0100, 0x4c00, 0x0000, 0x5b00, 0x0001, 0x0000, 0x0000
|
||||||
};
|
};
|
||||||
|
|
||||||
static const uint8_t kAbTxtName[] = { 'a', 'b', '.', 't', 'x', 't' };
|
static const std::string kAbTxtName("ab.txt");
|
||||||
static const uint16_t kAbTxtNameLength = sizeof(kAbTxtName);
|
|
||||||
static const size_t kAbUncompressedSize = 270216;
|
static const size_t kAbUncompressedSize = 270216;
|
||||||
|
|
||||||
static int make_temporary_file(const char* file_name_pattern) {
|
static int make_temporary_file(const char* file_name_pattern) {
|
||||||
|
|
@ -405,8 +400,7 @@ TEST(ziparchive, EmptyEntries) {
|
||||||
|
|
||||||
ZipEntry entry;
|
ZipEntry entry;
|
||||||
ZipString empty_name;
|
ZipString empty_name;
|
||||||
empty_name.name = kEmptyTxtName;
|
SetZipString(&empty_name, kEmptyTxtName);
|
||||||
empty_name.name_length = kEmptyTxtNameLength;
|
|
||||||
ASSERT_EQ(0, FindEntry(handle, empty_name, &entry));
|
ASSERT_EQ(0, FindEntry(handle, empty_name, &entry));
|
||||||
ASSERT_EQ(static_cast<uint32_t>(0), entry.uncompressed_length);
|
ASSERT_EQ(static_cast<uint32_t>(0), entry.uncompressed_length);
|
||||||
uint8_t buffer[1];
|
uint8_t buffer[1];
|
||||||
|
|
@ -436,8 +430,7 @@ TEST(ziparchive, EntryLargerThan32K) {
|
||||||
|
|
||||||
ZipEntry entry;
|
ZipEntry entry;
|
||||||
ZipString ab_name;
|
ZipString ab_name;
|
||||||
ab_name.name = kAbTxtName;
|
SetZipString(&ab_name, kAbTxtName);
|
||||||
ab_name.name_length = kAbTxtNameLength;
|
|
||||||
ASSERT_EQ(0, FindEntry(handle, ab_name, &entry));
|
ASSERT_EQ(0, FindEntry(handle, ab_name, &entry));
|
||||||
ASSERT_EQ(kAbUncompressedSize, entry.uncompressed_length);
|
ASSERT_EQ(kAbUncompressedSize, entry.uncompressed_length);
|
||||||
|
|
||||||
|
|
@ -504,8 +497,7 @@ TEST(ziparchive, ExtractToFile) {
|
||||||
|
|
||||||
ZipEntry entry;
|
ZipEntry entry;
|
||||||
ZipString name;
|
ZipString name;
|
||||||
name.name = kATxtName;
|
SetZipString(&name, kATxtName);
|
||||||
name.name_length = kATxtNameLength;
|
|
||||||
ASSERT_EQ(0, FindEntry(handle, name, &entry));
|
ASSERT_EQ(0, FindEntry(handle, name, &entry));
|
||||||
ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, fd));
|
ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, fd));
|
||||||
|
|
||||||
|
|
@ -521,22 +513,131 @@ TEST(ziparchive, ExtractToFile) {
|
||||||
ASSERT_EQ(static_cast<ssize_t>(entry.uncompressed_length),
|
ASSERT_EQ(static_cast<ssize_t>(entry.uncompressed_length),
|
||||||
TEMP_FAILURE_RETRY(
|
TEMP_FAILURE_RETRY(
|
||||||
read(fd, &uncompressed_data[0], entry.uncompressed_length)));
|
read(fd, &uncompressed_data[0], entry.uncompressed_length)));
|
||||||
ASSERT_EQ(0, memcmp(&uncompressed_data[0], kATxtContents,
|
ASSERT_EQ(0, memcmp(&uncompressed_data[0], kATxtContents.data(),
|
||||||
sizeof(kATxtContents)));
|
kATxtContents.size()));
|
||||||
|
|
||||||
// Assert that the total length of the file is sane
|
// Assert that the total length of the file is sane
|
||||||
ASSERT_EQ(data_size + static_cast<ssize_t>(sizeof(kATxtContents)),
|
ASSERT_EQ(data_size + static_cast<ssize_t>(kATxtContents.size()),
|
||||||
lseek64(fd, 0, SEEK_END));
|
lseek64(fd, 0, SEEK_END));
|
||||||
|
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ZipArchiveStreamTest(
|
||||||
|
ZipArchiveHandle& handle, const std::string& entry_name, bool raw,
|
||||||
|
bool verified, ZipEntry* entry, std::vector<uint8_t>* read_data) {
|
||||||
|
ZipString name;
|
||||||
|
SetZipString(&name, entry_name);
|
||||||
|
ASSERT_EQ(0, FindEntry(handle, name, entry));
|
||||||
|
std::unique_ptr<ZipArchiveStreamEntry> stream;
|
||||||
|
if (raw) {
|
||||||
|
stream.reset(ZipArchiveStreamEntry::CreateRaw(handle, *entry));
|
||||||
|
if (entry->method == kCompressStored) {
|
||||||
|
read_data->resize(entry->uncompressed_length);
|
||||||
|
} else {
|
||||||
|
read_data->resize(entry->compressed_length);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
stream.reset(ZipArchiveStreamEntry::Create(handle, *entry));
|
||||||
|
read_data->resize(entry->uncompressed_length);
|
||||||
|
}
|
||||||
|
uint8_t* read_data_ptr = read_data->data();
|
||||||
|
ASSERT_TRUE(stream.get() != nullptr);
|
||||||
|
const std::vector<uint8_t>* data;
|
||||||
|
uint64_t total_size = 0;
|
||||||
|
while ((data = stream->Read()) != nullptr) {
|
||||||
|
total_size += data->size();
|
||||||
|
memcpy(read_data_ptr, data->data(), data->size());
|
||||||
|
read_data_ptr += data->size();
|
||||||
|
}
|
||||||
|
ASSERT_EQ(verified, stream->Verify());
|
||||||
|
ASSERT_EQ(total_size, read_data->size());
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ZipArchiveStreamTestUsingContents(
|
||||||
|
const std::string& zip_file, const std::string& entry_name,
|
||||||
|
const std::vector<uint8_t>& contents, bool raw) {
|
||||||
|
ZipArchiveHandle handle;
|
||||||
|
ASSERT_EQ(0, OpenArchiveWrapper(zip_file, &handle));
|
||||||
|
|
||||||
|
ZipEntry entry;
|
||||||
|
std::vector<uint8_t> read_data;
|
||||||
|
ZipArchiveStreamTest(handle, entry_name, raw, true, &entry, &read_data);
|
||||||
|
|
||||||
|
ASSERT_EQ(contents.size(), read_data.size());
|
||||||
|
ASSERT_TRUE(memcmp(read_data.data(), contents.data(), read_data.size()) == 0);
|
||||||
|
|
||||||
|
CloseArchive(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ZipArchiveStreamTestUsingMemory(const std::string& zip_file, const std::string& entry_name) {
|
||||||
|
ZipArchiveHandle handle;
|
||||||
|
ASSERT_EQ(0, OpenArchiveWrapper(zip_file, &handle));
|
||||||
|
|
||||||
|
ZipEntry entry;
|
||||||
|
std::vector<uint8_t> read_data;
|
||||||
|
ZipArchiveStreamTest(handle, entry_name, false, true, &entry, &read_data);
|
||||||
|
|
||||||
|
std::vector<uint8_t> cmp_data(entry.uncompressed_length);
|
||||||
|
ASSERT_EQ(entry.uncompressed_length, read_data.size());
|
||||||
|
ASSERT_EQ(0, ExtractToMemory(handle, &entry, cmp_data.data(), cmp_data.size()));
|
||||||
|
ASSERT_TRUE(memcmp(read_data.data(), cmp_data.data(), read_data.size()) == 0);
|
||||||
|
|
||||||
|
CloseArchive(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ziparchive, StreamCompressed) {
|
||||||
|
ZipArchiveStreamTestUsingContents(kValidZip, kATxtName, kATxtContents, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ziparchive, StreamUncompressed) {
|
||||||
|
ZipArchiveStreamTestUsingContents(kValidZip, kBTxtName, kBTxtContents, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ziparchive, StreamRawCompressed) {
|
||||||
|
ZipArchiveStreamTestUsingContents(kValidZip, kATxtName, kATxtContentsCompressed, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ziparchive, StreamRawUncompressed) {
|
||||||
|
ZipArchiveStreamTestUsingContents(kValidZip, kBTxtName, kBTxtContents, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ziparchive, StreamLargeCompressed) {
|
||||||
|
ZipArchiveStreamTestUsingMemory(kLargeZip, kLargeCompressTxtName);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ziparchive, StreamLargeUncompressed) {
|
||||||
|
ZipArchiveStreamTestUsingMemory(kLargeZip, kLargeUncompressTxtName);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ziparchive, StreamCompressedBadCrc) {
|
||||||
|
ZipArchiveHandle handle;
|
||||||
|
ASSERT_EQ(0, OpenArchiveWrapper(kBadCrcZip, &handle));
|
||||||
|
|
||||||
|
ZipEntry entry;
|
||||||
|
std::vector<uint8_t> read_data;
|
||||||
|
ZipArchiveStreamTest(handle, kATxtName, false, false, &entry, &read_data);
|
||||||
|
|
||||||
|
CloseArchive(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ziparchive, StreamUncompressedBadCrc) {
|
||||||
|
ZipArchiveHandle handle;
|
||||||
|
ASSERT_EQ(0, OpenArchiveWrapper(kBadCrcZip, &handle));
|
||||||
|
|
||||||
|
ZipEntry entry;
|
||||||
|
std::vector<uint8_t> read_data;
|
||||||
|
ZipArchiveStreamTest(handle, kBTxtName, false, false, &entry, &read_data);
|
||||||
|
|
||||||
|
CloseArchive(handle);
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
::testing::InitGoogleTest(&argc, argv);
|
::testing::InitGoogleTest(&argc, argv);
|
||||||
|
|
||||||
static struct option options[] = {
|
static struct option options[] = {
|
||||||
{ "test_data_dir", required_argument, NULL, 't' },
|
{ "test_data_dir", required_argument, nullptr, 't' },
|
||||||
{ NULL, 0, NULL, 0 }
|
{ nullptr, 0, nullptr, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|
@ -557,9 +658,15 @@ int main(int argc, char** argv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (test_data_dir[0] != '/') {
|
if (test_data_dir[0] != '/') {
|
||||||
printf("Test data must be an absolute path, was %s\n\n",
|
std::vector<char> cwd_buffer(1024);
|
||||||
test_data_dir.c_str());
|
const char* cwd = getcwd(cwd_buffer.data(), cwd_buffer.size() - 1);
|
||||||
return -2;
|
if (cwd == nullptr) {
|
||||||
|
printf("Cannot get current working directory, use an absolute path instead, was %s\n\n",
|
||||||
|
test_data_dir.c_str());
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
test_data_dir = '/' + test_data_dir;
|
||||||
|
test_data_dir = cwd + test_data_dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
return RUN_ALL_TESTS();
|
return RUN_ALL_TESTS();
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue