diff options
Diffstat (limited to 'libcef/browser/zip_reader_impl.cc')
-rw-r--r-- | libcef/browser/zip_reader_impl.cc | 303 |
1 files changed, 303 insertions, 0 deletions
diff --git a/libcef/browser/zip_reader_impl.cc b/libcef/browser/zip_reader_impl.cc new file mode 100644 index 00000000..74643c6c --- /dev/null +++ b/libcef/browser/zip_reader_impl.cc @@ -0,0 +1,303 @@ +// Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. + +#include "libcef/browser/zip_reader_impl.h" +#include <time.h> +#include "base/logging.h" +#include "base/notreached.h" +#include "base/time/time.h" +#include "include/cef_stream.h" + +// Static functions + +// static +CefRefPtr<CefZipReader> CefZipReader::Create( + CefRefPtr<CefStreamReader> stream) { + CefRefPtr<CefZipReaderImpl> impl(new CefZipReaderImpl()); + if (!impl->Initialize(stream)) { + return nullptr; + } + return impl.get(); +} + +// CefZipReaderImpl + +namespace { + +voidpf ZCALLBACK zlib_open_callback OF((voidpf opaque, + const void* filename, + int mode)) { + // The stream is already implicitly open so just return the pointer. + return opaque; +} + +uLong ZCALLBACK zlib_read_callback +OF((voidpf opaque, voidpf stream, void* buf, uLong size)) { + CefRefPtr<CefStreamReader> reader(static_cast<CefStreamReader*>(opaque)); + return reader->Read(buf, 1, size); +} + +ZPOS64_T ZCALLBACK zlib_tell_callback OF((voidpf opaque, voidpf stream)) { + CefRefPtr<CefStreamReader> reader(static_cast<CefStreamReader*>(opaque)); + return reader->Tell(); +} + +long ZCALLBACK zlib_seek_callback +OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)) { + CefRefPtr<CefStreamReader> reader(static_cast<CefStreamReader*>(opaque)); + int whence; + switch (origin) { + case ZLIB_FILEFUNC_SEEK_CUR: + whence = SEEK_CUR; + break; + case ZLIB_FILEFUNC_SEEK_END: + whence = SEEK_END; + break; + case ZLIB_FILEFUNC_SEEK_SET: + whence = SEEK_SET; + break; + default: + NOTREACHED(); + return -1; + } + return reader->Seek(offset, whence); +} + +int ZCALLBACK zlib_close_callback OF((voidpf opaque, voidpf stream)) { + CefRefPtr<CefStreamReader> reader(static_cast<CefStreamReader*>(opaque)); + // Release the reference added by CefZipReaderImpl::Initialize(). + reader->Release(); + return 0; +} + +int ZCALLBACK zlib_error_callback OF((voidpf opaque, voidpf stream)) { + return 0; +} + +} // namespace + +CefZipReaderImpl::CefZipReaderImpl() + : supported_thread_id_(base::PlatformThread::CurrentId()), + reader_(nullptr), + has_fileopen_(false), + has_fileinfo_(false), + filesize_(0), + filemodified_(0) {} + +CefZipReaderImpl::~CefZipReaderImpl() { + if (reader_ != nullptr) { + if (!VerifyContext()) { + // Close() is supposed to be called directly. We'll try to free the reader + // now on the wrong thread but there's no guarantee this call won't crash. + if (has_fileopen_) { + unzCloseCurrentFile(reader_); + } + unzClose(reader_); + } else { + Close(); + } + } +} + +bool CefZipReaderImpl::Initialize(CefRefPtr<CefStreamReader> stream) { + zlib_filefunc64_def filefunc_def; + filefunc_def.zopen64_file = zlib_open_callback; + filefunc_def.zread_file = zlib_read_callback; + filefunc_def.zwrite_file = nullptr; + filefunc_def.ztell64_file = zlib_tell_callback; + filefunc_def.zseek64_file = zlib_seek_callback; + filefunc_def.zclose_file = zlib_close_callback; + filefunc_def.zerror_file = zlib_error_callback; + filefunc_def.opaque = stream.get(); + + // Add a reference that will be released by zlib_close_callback(). + stream->AddRef(); + + reader_ = unzOpen2_64("", &filefunc_def); + return (reader_ != nullptr); +} + +bool CefZipReaderImpl::MoveToFirstFile() { + if (!VerifyContext()) { + return false; + } + + if (has_fileopen_) { + CloseFile(); + } + + has_fileinfo_ = false; + + return (unzGoToFirstFile(reader_) == UNZ_OK); +} + +bool CefZipReaderImpl::MoveToNextFile() { + if (!VerifyContext()) { + return false; + } + + if (has_fileopen_) { + CloseFile(); + } + + has_fileinfo_ = false; + + return (unzGoToNextFile(reader_) == UNZ_OK); +} + +bool CefZipReaderImpl::MoveToFile(const CefString& fileName, + bool caseSensitive) { + if (!VerifyContext()) { + return false; + } + + if (has_fileopen_) { + CloseFile(); + } + + has_fileinfo_ = false; + + std::string fileNameStr = fileName; + return (unzLocateFile(reader_, fileNameStr.c_str(), + (caseSensitive ? 1 : 2)) == UNZ_OK); +} + +bool CefZipReaderImpl::Close() { + if (!VerifyContext()) { + return false; + } + + if (has_fileopen_) { + CloseFile(); + } + + int result = unzClose(reader_); + reader_ = nullptr; + return (result == UNZ_OK); +} + +CefString CefZipReaderImpl::GetFileName() { + if (!VerifyContext() || !GetFileInfo()) { + return CefString(); + } + + return filename_; +} + +int64 CefZipReaderImpl::GetFileSize() { + if (!VerifyContext() || !GetFileInfo()) { + return -1; + } + + return filesize_; +} + +CefBaseTime CefZipReaderImpl::GetFileLastModified() { + if (!VerifyContext() || !GetFileInfo()) { + return CefBaseTime(); + } + + return base::Time::FromTimeT(filemodified_); +} + +bool CefZipReaderImpl::OpenFile(const CefString& password) { + if (!VerifyContext()) { + return false; + } + + if (has_fileopen_) { + CloseFile(); + } + + bool ret; + + if (password.empty()) { + ret = (unzOpenCurrentFile(reader_) == UNZ_OK); + } else { + std::string passwordStr = password; + ret = (unzOpenCurrentFilePassword(reader_, passwordStr.c_str()) == UNZ_OK); + } + + if (ret) { + has_fileopen_ = true; + } + return ret; +} + +bool CefZipReaderImpl::CloseFile() { + if (!VerifyContext() || !has_fileopen_) { + return false; + } + + has_fileopen_ = false; + has_fileinfo_ = false; + + return (unzCloseCurrentFile(reader_) == UNZ_OK); +} + +int CefZipReaderImpl::ReadFile(void* buffer, size_t bufferSize) { + if (!VerifyContext() || !has_fileopen_) { + return -1; + } + + return unzReadCurrentFile(reader_, buffer, bufferSize); +} + +int64 CefZipReaderImpl::Tell() { + if (!VerifyContext() || !has_fileopen_) { + return -1; + } + + return unztell64(reader_); +} + +bool CefZipReaderImpl::Eof() { + if (!VerifyContext() || !has_fileopen_) { + return true; + } + + return (unzeof(reader_) == 1 ? true : false); +} + +bool CefZipReaderImpl::GetFileInfo() { + if (has_fileinfo_) { + return true; + } + + char file_name[512] = {0}; + unz_file_info file_info; + memset(&file_info, 0, sizeof(file_info)); + + if (unzGetCurrentFileInfo(reader_, &file_info, file_name, sizeof(file_name), + NULL, 0, NULL, 0) != UNZ_OK) { + return false; + } + + has_fileinfo_ = true; + filename_ = std::string(file_name); + filesize_ = file_info.uncompressed_size; + + struct tm time; + memset(&time, 0, sizeof(time)); + time.tm_sec = file_info.tmu_date.tm_sec; + time.tm_min = file_info.tmu_date.tm_min; + time.tm_hour = file_info.tmu_date.tm_hour; + time.tm_mday = file_info.tmu_date.tm_mday; + time.tm_mon = file_info.tmu_date.tm_mon; + time.tm_year = file_info.tmu_date.tm_year - 1900; // Years since 1900. + filemodified_ = mktime(&time); + DCHECK_NE(filemodified_, (time_t)-1); + + return true; +} + +bool CefZipReaderImpl::VerifyContext() { + if (base::PlatformThread::CurrentId() != supported_thread_id_) { + // This object should only be accessed from the thread that created it. + NOTREACHED(); + return false; + } + + return (reader_ != nullptr); +} |