| 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 |