blob: 57bc299f8748dc372709e1e2cc1cdb812956acae [file] [log] [blame]
// 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 "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_;
}
CefTime CefZipReaderImpl::GetFileLastModified() {
CefTime time;
if (!VerifyContext() || !GetFileInfo())
return time;
cef_time_from_timet(filemodified_, &time);
return time;
}
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);
}