1 // Copyright (c) 2010 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 "include/wrapper/cef_zip_archive.h"
6
7 #include <algorithm>
8
9 #include "include/base/cef_logging.h"
10 #include "include/base/cef_macros.h"
11 #include "include/base/cef_scoped_ptr.h"
12 #include "include/cef_stream.h"
13 #include "include/cef_zip_reader.h"
14 #include "include/wrapper/cef_byte_read_handler.h"
15
16 #if defined(OS_LINUX)
17 #include <wctype.h>
18 #endif
19
20 namespace {
21
22 // Convert |str| to lowercase in a Unicode-friendly manner.
ToLower(const CefString & str)23 CefString ToLower(const CefString& str) {
24 std::wstring wstr = str;
25 std::transform(wstr.begin(), wstr.end(), wstr.begin(), towlower);
26 return wstr;
27 }
28
29 class CefZipFile : public CefZipArchive::File {
30 public:
CefZipFile()31 CefZipFile() : data_size_(0) {}
32
Initialize(size_t data_size)33 bool Initialize(size_t data_size) {
34 data_.reset(new unsigned char[data_size]);
35 if (data_) {
36 data_size_ = data_size;
37 return true;
38 } else {
39 DLOG(ERROR) << "Failed to allocate " << data_size << " bytes of memory";
40 data_size_ = 0;
41 return false;
42 }
43 }
44
GetData() const45 virtual const unsigned char* GetData() const OVERRIDE { return data_.get(); }
46
GetDataSize() const47 virtual size_t GetDataSize() const OVERRIDE { return data_size_; }
48
GetStreamReader() const49 virtual CefRefPtr<CefStreamReader> GetStreamReader() const OVERRIDE {
50 CefRefPtr<CefReadHandler> handler(new CefByteReadHandler(
51 data_.get(), data_size_, const_cast<CefZipFile*>(this)));
52 return CefStreamReader::CreateForHandler(handler);
53 }
54
data()55 unsigned char* data() { return data_.get(); }
56
57 private:
58 size_t data_size_;
59 scoped_ptr<unsigned char[]> data_;
60
61 IMPLEMENT_REFCOUNTING(CefZipFile);
62 DISALLOW_COPY_AND_ASSIGN(CefZipFile);
63 };
64
65 } // namespace
66
67 // CefZipArchive implementation
68
CefZipArchive()69 CefZipArchive::CefZipArchive() {}
70
~CefZipArchive()71 CefZipArchive::~CefZipArchive() {}
72
Load(CefRefPtr<CefStreamReader> stream,const CefString & password,bool overwriteExisting)73 size_t CefZipArchive::Load(CefRefPtr<CefStreamReader> stream,
74 const CefString& password,
75 bool overwriteExisting) {
76 base::AutoLock lock_scope(lock_);
77
78 CefRefPtr<CefZipReader> reader(CefZipReader::Create(stream));
79 if (!reader.get())
80 return 0;
81
82 if (!reader->MoveToFirstFile())
83 return 0;
84
85 FileMap::iterator it;
86 size_t count = 0;
87
88 do {
89 const size_t size = static_cast<size_t>(reader->GetFileSize());
90 if (size == 0) {
91 // Skip directories and empty files.
92 continue;
93 }
94
95 if (!reader->OpenFile(password))
96 break;
97
98 const CefString& name = ToLower(reader->GetFileName());
99
100 it = contents_.find(name);
101 if (it != contents_.end()) {
102 if (overwriteExisting)
103 contents_.erase(it);
104 else // Skip files that already exist.
105 continue;
106 }
107
108 CefRefPtr<CefZipFile> contents = new CefZipFile();
109 if (!contents->Initialize(size))
110 continue;
111 unsigned char* data = contents->data();
112 size_t offset = 0;
113
114 // Read the file contents.
115 do {
116 offset += reader->ReadFile(data + offset, size - offset);
117 } while (offset < size && !reader->Eof());
118
119 DCHECK(offset == size);
120
121 reader->CloseFile();
122 count++;
123
124 // Add the file to the map.
125 contents_.insert(std::make_pair(name, contents.get()));
126 } while (reader->MoveToNextFile());
127
128 return count;
129 }
130
Clear()131 void CefZipArchive::Clear() {
132 base::AutoLock lock_scope(lock_);
133 contents_.clear();
134 }
135
GetFileCount() const136 size_t CefZipArchive::GetFileCount() const {
137 base::AutoLock lock_scope(lock_);
138 return contents_.size();
139 }
140
HasFile(const CefString & fileName) const141 bool CefZipArchive::HasFile(const CefString& fileName) const {
142 base::AutoLock lock_scope(lock_);
143 FileMap::const_iterator it = contents_.find(ToLower(fileName));
144 return (it != contents_.end());
145 }
146
GetFile(const CefString & fileName) const147 CefRefPtr<CefZipArchive::File> CefZipArchive::GetFile(
148 const CefString& fileName) const {
149 base::AutoLock lock_scope(lock_);
150 FileMap::const_iterator it = contents_.find(ToLower(fileName));
151 if (it != contents_.end())
152 return it->second;
153 return nullptr;
154 }
155
RemoveFile(const CefString & fileName)156 bool CefZipArchive::RemoveFile(const CefString& fileName) {
157 base::AutoLock lock_scope(lock_);
158 FileMap::iterator it = contents_.find(ToLower(fileName));
159 if (it != contents_.end()) {
160 contents_.erase(it);
161 return true;
162 }
163 return false;
164 }
165
GetFiles(FileMap & map) const166 size_t CefZipArchive::GetFiles(FileMap& map) const {
167 base::AutoLock lock_scope(lock_);
168 map = contents_;
169 return contents_.size();
170 }
171