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