OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/privacy_blacklist/blacklist_io.h" | 5 #include "chrome/browser/privacy_blacklist/blacklist_io.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <limits> |
8 #include <string> | |
9 | 8 |
10 #include "base/file_path.h" | 9 #include "base/file_path.h" |
11 #include "base/file_util.h" | 10 #include "base/file_util.h" |
| 11 #include "base/string_tokenizer.h" |
12 #include "base/string_util.h" | 12 #include "base/string_util.h" |
13 #include "base/string_tokenizer.h" | 13 #include "chrome/browser/privacy_blacklist/blacklist.h" |
14 #include "chrome/browser/privacy_blacklist/blacklist_store.h" | 14 #include "chrome/browser/privacy_blacklist/blacklist_store.h" |
15 | 15 |
16 namespace { | 16 namespace { |
17 | 17 |
18 const char header[] = "[Chromium::PrivacyBlacklist]"; | 18 const char header[] = "[Chromium::PrivacyBlacklist]"; |
19 const char name_tag[] = "Name:"; | 19 const char name_tag[] = "Name:"; |
20 const char url_tag[] = "URL:"; | 20 const char url_tag[] = "URL:"; |
21 const char arrow_tag[] = "=>"; | 21 const char arrow_tag[] = "=>"; |
22 const char eol[] = "\n\r"; | 22 const char eol[] = "\n\r"; |
23 | 23 |
24 class IsWhiteSpace { | 24 class IsWhiteSpace { |
25 public: | 25 public: |
26 bool operator()(const char& c) const { | 26 bool operator()(const char& c) const { |
27 return IsAsciiWhitespace(c); | 27 return IsAsciiWhitespace(c); |
28 } | 28 } |
29 }; | 29 }; |
30 | 30 |
31 class IsNotWhiteSpace { | 31 class IsNotWhiteSpace { |
32 public: | 32 public: |
33 bool operator()(const char& c) const { | 33 bool operator()(const char& c) const { |
34 return !IsAsciiWhitespace(c); | 34 return !IsAsciiWhitespace(c); |
35 } | 35 } |
36 }; | 36 }; |
37 | 37 |
38 bool StartsWith(const char* cur, const char* end, | 38 bool StartsWith(const char* cur, const char* end, |
39 const char* tag, std::size_t size) { | 39 const char* tag, std::size_t size) { |
40 return cur+size <= end && std::equal(tag, tag+size-1, cur); | 40 return cur + size <= end && std::equal(tag, tag + size - 1, cur); |
41 } | 41 } |
42 | 42 |
43 } // namespace | 43 } // namespace |
44 | 44 |
45 BlacklistIO::BlacklistIO() {} | 45 // static |
46 | 46 bool BlacklistIO::ReadText(Blacklist* blacklist, |
47 BlacklistIO::~BlacklistIO() { | 47 const FilePath& path, |
48 for (std::list<Blacklist::Entry*>::iterator i = blacklist_.begin(); | 48 std::string* error_string) { |
49 i != blacklist_.end(); ++i) { | 49 DCHECK(blacklist); |
50 delete *i; | 50 |
51 } | |
52 for (std::list<Blacklist::Provider*>::iterator i = providers_.begin(); | |
53 i != providers_.end(); ++i) { | |
54 delete *i; | |
55 } | |
56 } | |
57 | |
58 bool BlacklistIO::Read(const FilePath& file) { | |
59 // Memory map for efficient parsing. If the file cannot fit in available | 51 // Memory map for efficient parsing. If the file cannot fit in available |
60 // memory it would be the least of our worries. Typical blacklist files | 52 // memory it would be the least of our worries. Typical blacklist files |
61 // are less than 200K. | 53 // are less than 200K. |
62 file_util::MemoryMappedFile input; | 54 file_util::MemoryMappedFile input; |
63 if (!input.Initialize(file) || !input.data()) { | 55 if (!input.Initialize(path) || !input.data()) { |
64 last_error_ = ASCIIToUTF16("File I/O error. Check path and permissions."); | 56 *error_string = "File I/O error. Check path and permissions."; |
65 return false; | 57 return false; |
66 } | 58 } |
67 | 59 |
68 const char* cur = reinterpret_cast<const char*>(input.data()); | 60 const char* cur = reinterpret_cast<const char*>(input.data()); |
69 const char* end = cur + input.length(); | 61 const char* end = cur + input.length(); |
70 | 62 |
71 // Check header. | 63 // Check header. |
72 if (!StartsWith(cur, end, header, arraysize(header))) { | 64 if (!StartsWith(cur, end, header, arraysize(header))) { |
73 last_error_ = ASCIIToUTF16("Incorrect header."); | 65 *error_string = "Incorrect header."; |
74 return false; | 66 return false; |
75 } | 67 } |
76 | 68 |
| 69 Blacklist::EntryList entries; |
| 70 Blacklist::ProviderList providers; |
| 71 |
77 Blacklist::Provider* provider = new Blacklist::Provider; | 72 Blacklist::Provider* provider = new Blacklist::Provider; |
78 providers_.push_back(provider); | 73 providers.push_back(linked_ptr<Blacklist::Provider>(provider)); |
79 | 74 |
80 cur = std::find(cur, end, '\n') + 1; // Skip past EOL. | 75 cur = std::find(cur, end, '\n') + 1; // Skip past EOL. |
81 | 76 |
82 // Each loop iteration takes care of one input line. | 77 // Each loop iteration takes care of one input line. |
83 while (cur < end) { | 78 while (cur < end) { |
84 // Skip whitespace at beginning of line. | 79 // Skip whitespace at beginning of line. |
85 cur = std::find_if(cur, end, IsNotWhiteSpace()); | 80 cur = std::find_if(cur, end, IsNotWhiteSpace()); |
86 if (cur == end) | 81 if (cur == end) |
87 break; | 82 break; |
88 | 83 |
89 if (*cur == '#') { | 84 if (*cur == '#') { |
90 cur = std::find(cur, end, '\n') + 1; | 85 cur = std::find(cur, end, '\n') + 1; |
91 continue; | 86 continue; |
92 } | 87 } |
93 | 88 |
94 if (*cur == '|') { | 89 if (*cur == '|') { |
95 ++cur; | 90 ++cur; |
96 if (StartsWith(cur, end, name_tag, arraysize(name_tag))) { | 91 if (StartsWith(cur, end, name_tag, arraysize(name_tag))) { |
97 // Edge condition: if the find below fails, the next one will too, | 92 // Edge condition: if the find below fails, the next one will too, |
98 // so we'll just skip to the EOF below. | 93 // so we'll just skip to the EOF below. |
99 cur = std::find_if(cur+arraysize(name_tag), end, IsNotWhiteSpace()); | 94 cur = std::find_if(cur + arraysize(name_tag), end, IsNotWhiteSpace()); |
100 const char* skip = std::find_if(cur, end, IsWhiteSpace()); | 95 const char* skip = std::find_if(cur, end, IsWhiteSpace()); |
101 if (skip < end) | 96 if (skip < end) |
102 provider->set_name(std::string(cur, skip)); | 97 provider->set_name(std::string(cur, skip)); |
103 } else if (StartsWith(cur, end, url_tag, arraysize(url_tag))) { | 98 } else if (StartsWith(cur, end, url_tag, arraysize(url_tag))) { |
104 cur = std::find_if(cur+arraysize(url_tag), end, IsNotWhiteSpace()); | 99 cur = std::find_if(cur + arraysize(url_tag), end, IsNotWhiteSpace()); |
105 const char* skip = std::find_if(cur, end, IsWhiteSpace()); | 100 const char* skip = std::find_if(cur, end, IsWhiteSpace()); |
106 if (skip < end) | 101 if (skip < end) |
107 provider->set_url(std::string(cur, skip)); | 102 provider->set_url(std::string(cur, skip)); |
108 } | 103 } |
109 cur = std::find(cur, end, '\n') + 1; | 104 cur = std::find(cur, end, '\n') + 1; |
110 continue; | 105 continue; |
111 } | 106 } |
112 | 107 |
113 const char* skip = std::find_if(cur, end, IsWhiteSpace()); | 108 const char* skip = std::find_if(cur, end, IsWhiteSpace()); |
114 std::string pattern(cur, skip); | 109 std::string pattern(cur, skip); |
115 | 110 |
116 cur = std::find_if(cur+pattern.size(), end, IsNotWhiteSpace()); | 111 cur = std::find_if(cur + pattern.size(), end, IsNotWhiteSpace()); |
117 if (!StartsWith(cur, end, arrow_tag, arraysize(arrow_tag))) { | 112 if (!StartsWith(cur, end, arrow_tag, arraysize(arrow_tag))) { |
118 last_error_ = ASCIIToUTF16("Missing => in rule."); | 113 *error_string = "Missing => in rule."; |
119 return false; | 114 return false; |
120 } | 115 } |
121 | 116 |
122 scoped_ptr<Blacklist::Entry> entry(new Blacklist::Entry(pattern, provider)); | 117 linked_ptr<Blacklist::Entry> entry(new Blacklist::Entry(pattern, provider)); |
123 | 118 |
124 cur = std::find_if(cur+arraysize(arrow_tag), end, IsNotWhiteSpace()); | 119 cur = std::find_if(cur + arraysize(arrow_tag), end, IsNotWhiteSpace()); |
125 skip = std::find_first_of(cur, end, eol, eol+2); | 120 skip = std::find_first_of(cur, end, eol, eol + 2); |
126 std::string buf(cur, skip); | 121 std::string buf(cur, skip); |
127 cur = skip + 1; | 122 cur = skip + 1; |
128 | 123 |
129 StringTokenizer tokenier(buf, " (),\n\r"); | 124 StringTokenizer tokenizer(buf, " (),\n\r"); |
130 tokenier.set_options(StringTokenizer::RETURN_DELIMS); | 125 tokenizer.set_options(StringTokenizer::RETURN_DELIMS); |
131 | 126 |
132 bool in_attribute = false; | 127 bool in_attribute = false; |
133 unsigned int last_attribute = 0; | 128 unsigned int last_attribute = 0; |
134 | 129 |
135 while (tokenier.GetNext()) { | 130 while (tokenizer.GetNext()) { |
136 if (tokenier.token_is_delim()) { | 131 if (tokenizer.token_is_delim()) { |
137 switch (*tokenier.token_begin()) { | 132 switch (*tokenizer.token_begin()) { |
138 case '(': | 133 case '(': |
139 if (in_attribute) { | 134 if (in_attribute) { |
140 last_error_ = | 135 *error_string = "Unexpected ( in attribute parameters."; |
141 ASCIIToUTF16("Unexpected ( in attribute parameters."); | |
142 return false; | 136 return false; |
143 } | 137 } |
144 in_attribute = true; | 138 in_attribute = true; |
145 continue; | 139 continue; |
146 case ')': | 140 case ')': |
147 if (!in_attribute) { | 141 if (!in_attribute) { |
148 last_error_ = ASCIIToUTF16("Unexpected ) in attribute list."); | 142 *error_string = "Unexpected ) in attribute list."; |
149 return false; | 143 return false; |
150 } | 144 } |
151 in_attribute = false; | 145 in_attribute = false; |
152 continue; | 146 continue; |
153 default: | 147 default: |
154 // No state change for other delimiters. | 148 // No state change for other delimiters. |
155 continue; | 149 continue; |
156 } | 150 } |
157 } | 151 } |
158 | 152 |
159 if (in_attribute) { | 153 if (in_attribute) { |
160 // The only attribute to support sub_tokens is kBlockByType, for now. | 154 // The only attribute to support sub_tokens is kBlockByType, for now. |
161 if (last_attribute == Blacklist::kBlockByType) | 155 if (last_attribute == Blacklist::kBlockByType) |
162 entry->AddType(tokenier.token()); | 156 entry->AddType(tokenizer.token()); |
163 } else { | 157 } else { |
164 // Filter attribute. Unrecognized attributes are ignored. | 158 // Filter attribute. Unrecognized attributes are ignored. |
165 last_attribute = Blacklist::String2Attribute(tokenier.token()); | 159 last_attribute = Blacklist::String2Attribute(tokenizer.token()); |
166 entry->AddAttributes(last_attribute); | 160 entry->AddAttributes(last_attribute); |
167 } | 161 } |
168 } | 162 } |
169 blacklist_.push_back(entry.release()); | 163 entries.push_back(entry); |
170 } | 164 } |
| 165 |
| 166 for (Blacklist::EntryList::iterator i = entries.begin(); |
| 167 i != entries.end(); ++i) { |
| 168 blacklist->AddEntry(i->release()); |
| 169 } |
| 170 for (Blacklist::ProviderList::iterator i = providers.begin(); |
| 171 i != providers.end(); ++i) { |
| 172 blacklist->AddProvider(i->release()); |
| 173 } |
| 174 |
171 return true; | 175 return true; |
172 } | 176 } |
173 | 177 |
174 bool BlacklistIO::Write(const FilePath& file) { | 178 // static |
| 179 bool BlacklistIO::ReadBinary(Blacklist* blacklist, const FilePath& path) { |
| 180 DCHECK(blacklist); |
| 181 |
| 182 FILE* fp = file_util::OpenFile(path, "rb"); |
| 183 if (fp == NULL) |
| 184 return false; |
| 185 |
| 186 BlacklistStoreInput input(fp); |
| 187 |
| 188 // Read the providers. |
| 189 uint32 num_providers = input.ReadNumProviders(); |
| 190 if (num_providers == std::numeric_limits<uint32>::max()) |
| 191 return false; |
| 192 |
| 193 Blacklist::EntryList entries; |
| 194 Blacklist::ProviderList providers; |
| 195 std::map<size_t, Blacklist::Provider*> provider_map; |
| 196 |
| 197 std::string name; |
| 198 std::string url; |
| 199 for (size_t i = 0; i < num_providers; ++i) { |
| 200 if (!input.ReadProvider(&name, &url)) |
| 201 return false; |
| 202 provider_map[i] = new Blacklist::Provider(name.c_str(), url.c_str()); |
| 203 providers.push_back(linked_ptr<Blacklist::Provider>(provider_map[i])); |
| 204 } |
| 205 |
| 206 // Read the entries. |
| 207 uint32 num_entries = input.ReadNumEntries(); |
| 208 if (num_entries == std::numeric_limits<uint32>::max()) |
| 209 return false; |
| 210 |
| 211 std::string pattern; |
| 212 unsigned int attributes, provider; |
| 213 std::vector<std::string> types; |
| 214 for (size_t i = 0; i < num_entries; ++i) { |
| 215 if (!input.ReadEntry(&pattern, &attributes, &types, &provider)) |
| 216 return false; |
| 217 |
| 218 Blacklist::Entry* entry = |
| 219 new Blacklist::Entry(pattern, provider_map[provider]); |
| 220 entry->AddAttributes(attributes); |
| 221 entry->SwapTypes(&types); |
| 222 entries.push_back(linked_ptr<Blacklist::Entry>(entry)); |
| 223 } |
| 224 |
| 225 for (Blacklist::EntryList::iterator i = entries.begin(); |
| 226 i != entries.end(); ++i) { |
| 227 blacklist->AddEntry(i->release()); |
| 228 } |
| 229 for (Blacklist::ProviderList::iterator i = providers.begin(); |
| 230 i != providers.end(); ++i) { |
| 231 blacklist->AddProvider(i->release()); |
| 232 } |
| 233 |
| 234 return true; |
| 235 } |
| 236 |
| 237 // static |
| 238 bool BlacklistIO::WriteBinary(const Blacklist* blacklist, |
| 239 const FilePath& file) { |
175 BlacklistStoreOutput output(file_util::OpenFile(file, "wb")); | 240 BlacklistStoreOutput output(file_util::OpenFile(file, "wb")); |
176 if (!output.is_good()) { | 241 if (!output.is_good()) |
177 last_error_ = ASCIIToUTF16("Error opening file for writing."); | |
178 return false; | 242 return false; |
179 } | 243 |
| 244 Blacklist::EntryList entries(blacklist->entries_begin(), |
| 245 blacklist->entries_end()); |
| 246 Blacklist::ProviderList providers(blacklist->providers_begin(), |
| 247 blacklist->providers_end()); |
180 | 248 |
181 // Output providers, give each one an index. | 249 // Output providers, give each one an index. |
182 std::map<const Blacklist::Provider*, uint32> index; | 250 std::map<const Blacklist::Provider*, uint32> index; |
183 uint32 current = 0; | 251 uint32 current = 0; |
184 if (!output.ReserveProviders(providers_.size())) { | 252 if (!output.ReserveProviders(providers.size())) |
185 last_error_ = ASCIIToUTF16("Error writing to file."); | |
186 return false; | 253 return false; |
187 } | |
188 | 254 |
189 for (std::list<Blacklist::Provider*>::const_iterator i = providers_.begin(); | 255 for (Blacklist::ProviderList::const_iterator i = providers.begin(); |
190 i != providers_.end(); ++i, ++current) { | 256 i != providers.end(); ++i, ++current) { |
191 if (!output.StoreProvider((*i)->name(), (*i)->url())) { | 257 if (!output.StoreProvider((*i)->name(), (*i)->url())) |
192 last_error_ = ASCIIToUTF16("Error writing to file."); | |
193 return false; | 258 return false; |
194 } | 259 index[i->get()] = current; |
195 index[*i] = current; | |
196 } | 260 } |
197 | 261 |
198 // Output entries, replacing the provider with its index. | 262 // Output entries, replacing the provider with its index. |
199 if (!output.ReserveEntries(blacklist_.size())) { | 263 if (!output.ReserveEntries(entries.size())) |
200 last_error_ = ASCIIToUTF16("Error writing to file."); | |
201 return false; | 264 return false; |
202 } | |
203 | 265 |
204 for (std::list<Blacklist::Entry*>::const_iterator i = blacklist_.begin(); | 266 for (Blacklist::EntryList::const_iterator i = entries.begin(); |
205 i != blacklist_.end(); ++i) { | 267 i != entries.end(); ++i) { |
206 if (!output.StoreEntry((*i)->pattern_, | 268 if (!output.StoreEntry((*i)->pattern_, |
207 (*i)->attributes_, | 269 (*i)->attributes_, |
208 (*i)->types_, | 270 (*i)->types_, |
209 index[(*i)->provider_])) { | 271 index[(*i)->provider_])) { |
210 last_error_ = ASCIIToUTF16("Error writing to file."); | |
211 return false; | 272 return false; |
212 } | 273 } |
213 } | 274 } |
214 return true; | 275 return true; |
215 } | 276 } |
OLD | NEW |