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