1 // Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
2 // reserved. Use of this source code is governed by a BSD-style license that
3 // can be found in the LICENSE file.
4
5 #include "libcef/browser/zip_reader_impl.h"
6 #include <time.h>
7 #include "base/logging.h"
8 #include "base/notreached.h"
9 #include "include/cef_stream.h"
10
11 // Static functions
12
13 // static
Create(CefRefPtr<CefStreamReader> stream)14 CefRefPtr<CefZipReader> CefZipReader::Create(
15 CefRefPtr<CefStreamReader> stream) {
16 CefRefPtr<CefZipReaderImpl> impl(new CefZipReaderImpl());
17 if (!impl->Initialize(stream))
18 return nullptr;
19 return impl.get();
20 }
21
22 // CefZipReaderImpl
23
24 namespace {
25
zlib_open_callback(voidpf opaque,const void * filename,int mode)26 voidpf ZCALLBACK zlib_open_callback OF((voidpf opaque,
27 const void* filename,
28 int mode)) {
29 // The stream is already implicitly open so just return the pointer.
30 return opaque;
31 }
32
zlib_read_callback(voidpf opaque,voidpf stream,void * buf,uLong size)33 uLong ZCALLBACK zlib_read_callback
34 OF((voidpf opaque, voidpf stream, void* buf, uLong size)) {
35 CefRefPtr<CefStreamReader> reader(static_cast<CefStreamReader*>(opaque));
36 return reader->Read(buf, 1, size);
37 }
38
zlib_tell_callback(voidpf opaque,voidpf stream)39 ZPOS64_T ZCALLBACK zlib_tell_callback OF((voidpf opaque, voidpf stream)) {
40 CefRefPtr<CefStreamReader> reader(static_cast<CefStreamReader*>(opaque));
41 return reader->Tell();
42 }
43
zlib_seek_callback(voidpf opaque,voidpf stream,ZPOS64_T offset,int origin)44 long ZCALLBACK zlib_seek_callback
45 OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)) {
46 CefRefPtr<CefStreamReader> reader(static_cast<CefStreamReader*>(opaque));
47 int whence;
48 switch (origin) {
49 case ZLIB_FILEFUNC_SEEK_CUR:
50 whence = SEEK_CUR;
51 break;
52 case ZLIB_FILEFUNC_SEEK_END:
53 whence = SEEK_END;
54 break;
55 case ZLIB_FILEFUNC_SEEK_SET:
56 whence = SEEK_SET;
57 break;
58 default:
59 NOTREACHED();
60 return -1;
61 }
62 return reader->Seek(offset, whence);
63 }
64
zlib_close_callback(voidpf opaque,voidpf stream)65 int ZCALLBACK zlib_close_callback OF((voidpf opaque, voidpf stream)) {
66 CefRefPtr<CefStreamReader> reader(static_cast<CefStreamReader*>(opaque));
67 // Release the reference added by CefZipReaderImpl::Initialize().
68 reader->Release();
69 return 0;
70 }
71
zlib_error_callback(voidpf opaque,voidpf stream)72 int ZCALLBACK zlib_error_callback OF((voidpf opaque, voidpf stream)) {
73 return 0;
74 }
75
76 } // namespace
77
CefZipReaderImpl()78 CefZipReaderImpl::CefZipReaderImpl()
79 : supported_thread_id_(base::PlatformThread::CurrentId()),
80 reader_(nullptr),
81 has_fileopen_(false),
82 has_fileinfo_(false),
83 filesize_(0),
84 filemodified_(0) {}
85
~CefZipReaderImpl()86 CefZipReaderImpl::~CefZipReaderImpl() {
87 if (reader_ != nullptr) {
88 if (!VerifyContext()) {
89 // Close() is supposed to be called directly. We'll try to free the reader
90 // now on the wrong thread but there's no guarantee this call won't crash.
91 if (has_fileopen_)
92 unzCloseCurrentFile(reader_);
93 unzClose(reader_);
94 } else {
95 Close();
96 }
97 }
98 }
99
Initialize(CefRefPtr<CefStreamReader> stream)100 bool CefZipReaderImpl::Initialize(CefRefPtr<CefStreamReader> stream) {
101 zlib_filefunc64_def filefunc_def;
102 filefunc_def.zopen64_file = zlib_open_callback;
103 filefunc_def.zread_file = zlib_read_callback;
104 filefunc_def.zwrite_file = nullptr;
105 filefunc_def.ztell64_file = zlib_tell_callback;
106 filefunc_def.zseek64_file = zlib_seek_callback;
107 filefunc_def.zclose_file = zlib_close_callback;
108 filefunc_def.zerror_file = zlib_error_callback;
109 filefunc_def.opaque = stream.get();
110
111 // Add a reference that will be released by zlib_close_callback().
112 stream->AddRef();
113
114 reader_ = unzOpen2_64("", &filefunc_def);
115 return (reader_ != nullptr);
116 }
117
MoveToFirstFile()118 bool CefZipReaderImpl::MoveToFirstFile() {
119 if (!VerifyContext())
120 return false;
121
122 if (has_fileopen_)
123 CloseFile();
124
125 has_fileinfo_ = false;
126
127 return (unzGoToFirstFile(reader_) == UNZ_OK);
128 }
129
MoveToNextFile()130 bool CefZipReaderImpl::MoveToNextFile() {
131 if (!VerifyContext())
132 return false;
133
134 if (has_fileopen_)
135 CloseFile();
136
137 has_fileinfo_ = false;
138
139 return (unzGoToNextFile(reader_) == UNZ_OK);
140 }
141
MoveToFile(const CefString & fileName,bool caseSensitive)142 bool CefZipReaderImpl::MoveToFile(const CefString& fileName,
143 bool caseSensitive) {
144 if (!VerifyContext())
145 return false;
146
147 if (has_fileopen_)
148 CloseFile();
149
150 has_fileinfo_ = false;
151
152 std::string fileNameStr = fileName;
153 return (unzLocateFile(reader_, fileNameStr.c_str(),
154 (caseSensitive ? 1 : 2)) == UNZ_OK);
155 }
156
Close()157 bool CefZipReaderImpl::Close() {
158 if (!VerifyContext())
159 return false;
160
161 if (has_fileopen_)
162 CloseFile();
163
164 int result = unzClose(reader_);
165 reader_ = nullptr;
166 return (result == UNZ_OK);
167 }
168
GetFileName()169 CefString CefZipReaderImpl::GetFileName() {
170 if (!VerifyContext() || !GetFileInfo())
171 return CefString();
172
173 return filename_;
174 }
175
GetFileSize()176 int64 CefZipReaderImpl::GetFileSize() {
177 if (!VerifyContext() || !GetFileInfo())
178 return -1;
179
180 return filesize_;
181 }
182
GetFileLastModified()183 CefTime CefZipReaderImpl::GetFileLastModified() {
184 CefTime time;
185 if (!VerifyContext() || !GetFileInfo())
186 return time;
187
188 cef_time_from_timet(filemodified_, &time);
189 return time;
190 }
191
OpenFile(const CefString & password)192 bool CefZipReaderImpl::OpenFile(const CefString& password) {
193 if (!VerifyContext())
194 return false;
195
196 if (has_fileopen_)
197 CloseFile();
198
199 bool ret;
200
201 if (password.empty()) {
202 ret = (unzOpenCurrentFile(reader_) == UNZ_OK);
203 } else {
204 std::string passwordStr = password;
205 ret = (unzOpenCurrentFilePassword(reader_, passwordStr.c_str()) == UNZ_OK);
206 }
207
208 if (ret)
209 has_fileopen_ = true;
210 return ret;
211 }
212
CloseFile()213 bool CefZipReaderImpl::CloseFile() {
214 if (!VerifyContext() || !has_fileopen_)
215 return false;
216
217 has_fileopen_ = false;
218 has_fileinfo_ = false;
219
220 return (unzCloseCurrentFile(reader_) == UNZ_OK);
221 }
222
ReadFile(void * buffer,size_t bufferSize)223 int CefZipReaderImpl::ReadFile(void* buffer, size_t bufferSize) {
224 if (!VerifyContext() || !has_fileopen_)
225 return -1;
226
227 return unzReadCurrentFile(reader_, buffer, bufferSize);
228 }
229
Tell()230 int64 CefZipReaderImpl::Tell() {
231 if (!VerifyContext() || !has_fileopen_)
232 return -1;
233
234 return unztell64(reader_);
235 }
236
Eof()237 bool CefZipReaderImpl::Eof() {
238 if (!VerifyContext() || !has_fileopen_)
239 return true;
240
241 return (unzeof(reader_) == 1 ? true : false);
242 }
243
GetFileInfo()244 bool CefZipReaderImpl::GetFileInfo() {
245 if (has_fileinfo_)
246 return true;
247
248 char file_name[512] = {0};
249 unz_file_info file_info;
250 memset(&file_info, 0, sizeof(file_info));
251
252 if (unzGetCurrentFileInfo(reader_, &file_info, file_name, sizeof(file_name),
253 NULL, 0, NULL, 0) != UNZ_OK) {
254 return false;
255 }
256
257 has_fileinfo_ = true;
258 filename_ = std::string(file_name);
259 filesize_ = file_info.uncompressed_size;
260
261 struct tm time;
262 memset(&time, 0, sizeof(time));
263 time.tm_sec = file_info.tmu_date.tm_sec;
264 time.tm_min = file_info.tmu_date.tm_min;
265 time.tm_hour = file_info.tmu_date.tm_hour;
266 time.tm_mday = file_info.tmu_date.tm_mday;
267 time.tm_mon = file_info.tmu_date.tm_mon;
268 time.tm_year = file_info.tmu_date.tm_year - 1900; // Years since 1900.
269 filemodified_ = mktime(&time);
270 DCHECK_NE(filemodified_, (time_t)-1);
271
272 return true;
273 }
274
VerifyContext()275 bool CefZipReaderImpl::VerifyContext() {
276 if (base::PlatformThread::CurrentId() != supported_thread_id_) {
277 // This object should only be accessed from the thread that created it.
278 NOTREACHED();
279 return false;
280 }
281
282 return (reader_ != nullptr);
283 }
284