• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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